|
1 /* $Id$ */ |
|
2 |
|
3 #include "stdafx.h" |
|
4 #include "openttd.h" |
|
5 #include "debug.h" |
|
6 #include "functions.h" |
|
7 #include "string.h" |
|
8 #include "strings.h" |
|
9 #include "engine.h" |
|
10 #include "newgrf_engine.h" |
|
11 #include "sprite.h" |
|
12 #include "variables.h" |
|
13 #include "train.h" |
|
14 |
|
15 // TODO: We don't support cargo-specific wagon overrides. Pretty exotic... ;-) --pasky |
|
16 |
|
17 typedef struct WagonOverride { |
|
18 byte *train_id; |
|
19 int trains; |
|
20 SpriteGroup *group; |
|
21 } WagonOverride; |
|
22 |
|
23 typedef struct WagonOverrides { |
|
24 int overrides_count; |
|
25 WagonOverride *overrides; |
|
26 } WagonOverrides; |
|
27 |
|
28 static WagonOverrides _engine_wagon_overrides[TOTAL_NUM_ENGINES]; |
|
29 |
|
30 void SetWagonOverrideSprites(EngineID engine, SpriteGroup *group, byte *train_id, |
|
31 int trains) |
|
32 { |
|
33 WagonOverrides *wos; |
|
34 WagonOverride *wo; |
|
35 |
|
36 wos = &_engine_wagon_overrides[engine]; |
|
37 wos->overrides_count++; |
|
38 wos->overrides = realloc(wos->overrides, |
|
39 wos->overrides_count * sizeof(*wos->overrides)); |
|
40 |
|
41 wo = &wos->overrides[wos->overrides_count - 1]; |
|
42 /* FIXME: If we are replacing an override, release original SpriteGroup |
|
43 * to prevent leaks. But first we need to refcount the SpriteGroup. |
|
44 * --pasky */ |
|
45 wo->group = group; |
|
46 group->ref_count++; |
|
47 wo->trains = trains; |
|
48 wo->train_id = malloc(trains); |
|
49 memcpy(wo->train_id, train_id, trains); |
|
50 } |
|
51 |
|
52 static const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, byte overriding_engine) |
|
53 { |
|
54 const WagonOverrides *wos = &_engine_wagon_overrides[engine]; |
|
55 int i; |
|
56 |
|
57 // XXX: This could turn out to be a timesink on profiles. We could |
|
58 // always just dedicate 65535 bytes for an [engine][train] trampoline |
|
59 // for O(1). Or O(logMlogN) and searching binary tree or smt. like |
|
60 // that. --pasky |
|
61 |
|
62 for (i = 0; i < wos->overrides_count; i++) { |
|
63 const WagonOverride *wo = &wos->overrides[i]; |
|
64 int j; |
|
65 |
|
66 for (j = 0; j < wo->trains; j++) { |
|
67 if (wo->train_id[j] == overriding_engine) |
|
68 return wo->group; |
|
69 } |
|
70 } |
|
71 return NULL; |
|
72 } |
|
73 |
|
74 /** |
|
75 * Unload all wagon override sprite groups. |
|
76 */ |
|
77 void UnloadWagonOverrides(void) |
|
78 { |
|
79 WagonOverrides *wos; |
|
80 WagonOverride *wo; |
|
81 EngineID engine; |
|
82 int i; |
|
83 |
|
84 for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) { |
|
85 wos = &_engine_wagon_overrides[engine]; |
|
86 for (i = 0; i < wos->overrides_count; i++) { |
|
87 wo = &wos->overrides[i]; |
|
88 UnloadSpriteGroup(&wo->group); |
|
89 free(wo->train_id); |
|
90 } |
|
91 free(wos->overrides); |
|
92 wos->overrides_count = 0; |
|
93 wos->overrides = NULL; |
|
94 } |
|
95 } |
|
96 |
|
97 // 0 - 28 are cargos, 29 is default, 30 is the advert (purchase list) |
|
98 // (It isn't and shouldn't be like this in the GRF files since new cargo types |
|
99 // may appear in future - however it's more convenient to store it like this in |
|
100 // memory. --pasky) |
|
101 static SpriteGroup *engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID]; |
|
102 |
|
103 void SetCustomEngineSprites(EngineID engine, byte cargo, SpriteGroup *group) |
|
104 { |
|
105 if (engine_custom_sprites[engine][cargo] != NULL) { |
|
106 DEBUG(grf, 6)("SetCustomEngineSprites: engine `%d' cargo `%d' already has group -- removing.", engine, cargo); |
|
107 UnloadSpriteGroup(&engine_custom_sprites[engine][cargo]); |
|
108 } |
|
109 engine_custom_sprites[engine][cargo] = group; |
|
110 group->ref_count++; |
|
111 } |
|
112 |
|
113 /** |
|
114 * Unload all engine sprite groups. |
|
115 */ |
|
116 void UnloadCustomEngineSprites(void) |
|
117 { |
|
118 EngineID engine; |
|
119 CargoID cargo; |
|
120 |
|
121 for (engine = 0; engine < TOTAL_NUM_ENGINES; engine++) { |
|
122 for (cargo = 0; cargo < NUM_GLOBAL_CID; cargo++) { |
|
123 if (engine_custom_sprites[engine][cargo] != NULL) { |
|
124 DEBUG(grf, 6)("UnloadCustomEngineSprites: Unloading group for engine `%d' cargo `%d'.", engine, cargo); |
|
125 UnloadSpriteGroup(&engine_custom_sprites[engine][cargo]); |
|
126 } |
|
127 } |
|
128 } |
|
129 } |
|
130 |
|
131 static int MapOldSubType(const Vehicle *v) |
|
132 { |
|
133 if (v->type != VEH_Train) return v->subtype; |
|
134 if (IsTrainEngine(v)) return 0; |
|
135 if (IsFreeWagon(v)) return 4; |
|
136 return 2; |
|
137 } |
|
138 |
|
139 typedef SpriteGroup *(*resolve_callback)(const SpriteGroup *spritegroup, |
|
140 const Vehicle *veh, uint16 callback_info, void *resolve_func); /* XXX data pointer used as function pointer */ |
|
141 |
|
142 static const SpriteGroup* ResolveVehicleSpriteGroup(const SpriteGroup *spritegroup, |
|
143 const Vehicle *veh, uint16 callback_info, resolve_callback resolve_func) |
|
144 { |
|
145 if (spritegroup == NULL) |
|
146 return NULL; |
|
147 |
|
148 //debug("spgt %d", spritegroup->type); |
|
149 switch (spritegroup->type) { |
|
150 case SGT_REAL: |
|
151 case SGT_CALLBACK: |
|
152 return spritegroup; |
|
153 |
|
154 case SGT_DETERMINISTIC: { |
|
155 const DeterministicSpriteGroup *dsg = &spritegroup->g.determ; |
|
156 const SpriteGroup *target; |
|
157 int value = -1; |
|
158 |
|
159 //debug("[%p] Having fun resolving variable %x", veh, dsg->variable); |
|
160 if (dsg->variable == 0x0C) { |
|
161 /* Callback ID */ |
|
162 value = callback_info & 0xFF; |
|
163 } else if (dsg->variable == 0x10) { |
|
164 value = (callback_info >> 8) & 0xFF; |
|
165 } else if ((dsg->variable >> 6) == 0) { |
|
166 /* General property */ |
|
167 value = GetDeterministicSpriteValue(dsg->variable); |
|
168 } else { |
|
169 /* Vehicle-specific property. */ |
|
170 |
|
171 if (veh == NULL) { |
|
172 /* We are in a purchase list of something, |
|
173 * and we are checking for something undefined. |
|
174 * That means we should get the first target |
|
175 * (NOT the default one). */ |
|
176 if (dsg->num_ranges > 0) { |
|
177 target = dsg->ranges[0].group; |
|
178 } else { |
|
179 target = dsg->default_group; |
|
180 } |
|
181 return resolve_func(target, NULL, callback_info, resolve_func); |
|
182 } |
|
183 |
|
184 if (dsg->var_scope == VSG_SCOPE_PARENT) { |
|
185 /* First engine in the vehicle chain */ |
|
186 if (veh->type == VEH_Train) |
|
187 veh = GetFirstVehicleInChain(veh); |
|
188 } |
|
189 |
|
190 if (dsg->variable == 0x40 || dsg->variable == 0x41) { |
|
191 if (veh->type == VEH_Train) { |
|
192 const Vehicle *u = GetFirstVehicleInChain(veh); |
|
193 byte chain_before = 0, chain_after = 0; |
|
194 |
|
195 while (u != veh) { |
|
196 chain_before++; |
|
197 if (dsg->variable == 0x41 && u->engine_type != veh->engine_type) |
|
198 chain_before = 0; |
|
199 u = u->next; |
|
200 } |
|
201 while (u->next != NULL && (dsg->variable == 0x40 || u->next->engine_type == veh->engine_type)) { |
|
202 chain_after++; |
|
203 u = u->next; |
|
204 }; |
|
205 |
|
206 value = chain_before | chain_after << 8 |
|
207 | (chain_before + chain_after) << 16; |
|
208 } else { |
|
209 value = 1; /* 1 vehicle in the chain */ |
|
210 } |
|
211 |
|
212 } else { |
|
213 // TTDPatch runs on little-endian arch; |
|
214 // Variable is 0x80 + offset in TTD's vehicle structure |
|
215 switch (dsg->variable - 0x80) { |
|
216 #define veh_prop(id_, value_) case (id_): value = (value_); break |
|
217 veh_prop(0x00, veh->type); |
|
218 veh_prop(0x01, MapOldSubType(veh)); |
|
219 veh_prop(0x04, veh->index); |
|
220 veh_prop(0x05, veh->index & 0xFF); |
|
221 /* XXX? Is THIS right? */ |
|
222 veh_prop(0x0A, PackOrder(&veh->current_order)); |
|
223 veh_prop(0x0B, PackOrder(&veh->current_order) & 0xff); |
|
224 veh_prop(0x0C, veh->num_orders); |
|
225 veh_prop(0x0D, veh->cur_order_index); |
|
226 veh_prop(0x10, veh->load_unload_time_rem); |
|
227 veh_prop(0x11, veh->load_unload_time_rem & 0xFF); |
|
228 veh_prop(0x12, veh->date_of_last_service); |
|
229 veh_prop(0x13, veh->date_of_last_service & 0xFF); |
|
230 veh_prop(0x14, veh->service_interval); |
|
231 veh_prop(0x15, veh->service_interval & 0xFF); |
|
232 veh_prop(0x16, veh->last_station_visited); |
|
233 veh_prop(0x17, veh->tick_counter); |
|
234 veh_prop(0x18, veh->max_speed); |
|
235 veh_prop(0x19, veh->max_speed & 0xFF); |
|
236 veh_prop(0x1F, veh->direction); |
|
237 veh_prop(0x28, veh->cur_image); |
|
238 veh_prop(0x29, veh->cur_image & 0xFF); |
|
239 veh_prop(0x32, veh->vehstatus); |
|
240 veh_prop(0x33, veh->vehstatus); |
|
241 veh_prop(0x34, veh->cur_speed); |
|
242 veh_prop(0x35, veh->cur_speed & 0xFF); |
|
243 veh_prop(0x36, veh->subspeed); |
|
244 veh_prop(0x37, veh->acceleration); |
|
245 veh_prop(0x39, veh->cargo_type); |
|
246 veh_prop(0x3A, veh->cargo_cap); |
|
247 veh_prop(0x3B, veh->cargo_cap & 0xFF); |
|
248 veh_prop(0x3C, veh->cargo_count); |
|
249 veh_prop(0x3D, veh->cargo_count & 0xFF); |
|
250 veh_prop(0x3E, veh->cargo_source); // Probably useless; so what |
|
251 veh_prop(0x3F, veh->cargo_days); |
|
252 veh_prop(0x40, veh->age); |
|
253 veh_prop(0x41, veh->age & 0xFF); |
|
254 veh_prop(0x42, veh->max_age); |
|
255 veh_prop(0x43, veh->max_age & 0xFF); |
|
256 veh_prop(0x44, veh->build_year); |
|
257 veh_prop(0x45, veh->unitnumber); |
|
258 veh_prop(0x46, veh->engine_type); |
|
259 veh_prop(0x47, veh->engine_type & 0xFF); |
|
260 veh_prop(0x48, veh->spritenum); |
|
261 veh_prop(0x49, veh->day_counter); |
|
262 veh_prop(0x4A, veh->breakdowns_since_last_service); |
|
263 veh_prop(0x4B, veh->breakdown_ctr); |
|
264 veh_prop(0x4C, veh->breakdown_delay); |
|
265 veh_prop(0x4D, veh->breakdown_chance); |
|
266 veh_prop(0x4E, veh->reliability); |
|
267 veh_prop(0x4F, veh->reliability & 0xFF); |
|
268 veh_prop(0x50, veh->reliability_spd_dec); |
|
269 veh_prop(0x51, veh->reliability_spd_dec & 0xFF); |
|
270 veh_prop(0x52, veh->profit_this_year); |
|
271 veh_prop(0x53, veh->profit_this_year & 0xFFFFFF); |
|
272 veh_prop(0x54, veh->profit_this_year & 0xFFFF); |
|
273 veh_prop(0x55, veh->profit_this_year & 0xFF); |
|
274 veh_prop(0x56, veh->profit_last_year); |
|
275 veh_prop(0x57, veh->profit_last_year & 0xFF); |
|
276 veh_prop(0x58, veh->profit_last_year); |
|
277 veh_prop(0x59, veh->profit_last_year & 0xFF); |
|
278 veh_prop(0x5A, veh->next == NULL ? INVALID_VEHICLE : veh->next->index); |
|
279 veh_prop(0x5C, veh->value); |
|
280 veh_prop(0x5D, veh->value & 0xFFFFFF); |
|
281 veh_prop(0x5E, veh->value & 0xFFFF); |
|
282 veh_prop(0x5F, veh->value & 0xFF); |
|
283 veh_prop(0x60, veh->string_id); |
|
284 veh_prop(0x61, veh->string_id & 0xFF); |
|
285 /* 00h..07h=sub image? 40h=in tunnel; actually some kind of status |
|
286 * aircraft: >=13h when in flight |
|
287 * train, ship: 80h=in depot |
|
288 * rv: 0feh=in depot */ |
|
289 /* TODO veh_prop(0x62, veh->???); */ |
|
290 |
|
291 /* TODO: The rest is per-vehicle, I hope no GRF file looks so far. |
|
292 * But they won't let us have an easy ride so surely *some* GRF |
|
293 * file does. So someone needs to do this too. --pasky */ |
|
294 |
|
295 #undef veh_prop |
|
296 } |
|
297 } |
|
298 } |
|
299 |
|
300 target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group; |
|
301 //debug("Resolved variable %x: %d, %p", dsg->variable, value, callback); |
|
302 return resolve_func(target, veh, callback_info, resolve_func); |
|
303 } |
|
304 |
|
305 case SGT_RANDOMIZED: { |
|
306 const RandomizedSpriteGroup *rsg = &spritegroup->g.random; |
|
307 |
|
308 if (veh == NULL) { |
|
309 /* Purchase list of something. Show the first one. */ |
|
310 assert(rsg->num_groups > 0); |
|
311 //debug("going for %p: %d", rsg->groups[0], rsg->groups[0].type); |
|
312 return resolve_func(rsg->groups[0], NULL, callback_info, resolve_func); |
|
313 } |
|
314 |
|
315 if (rsg->var_scope == VSG_SCOPE_PARENT) { |
|
316 /* First engine in the vehicle chain */ |
|
317 if (veh->type == VEH_Train) |
|
318 veh = GetFirstVehicleInChain(veh); |
|
319 } |
|
320 |
|
321 return resolve_func(EvalRandomizedSpriteGroup(rsg, veh->random_bits), veh, callback_info, resolve_func); |
|
322 } |
|
323 |
|
324 default: |
|
325 error("I don't know how to handle such a spritegroup %d!", spritegroup->type); |
|
326 return NULL; |
|
327 } |
|
328 } |
|
329 |
|
330 static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *v) |
|
331 { |
|
332 const SpriteGroup *group; |
|
333 byte cargo = GC_PURCHASE; |
|
334 |
|
335 if (v != NULL) { |
|
336 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
|
337 assert(cargo != GC_INVALID); |
|
338 } |
|
339 |
|
340 group = engine_custom_sprites[engine][cargo]; |
|
341 |
|
342 if (v != NULL && v->type == VEH_Train) { |
|
343 const SpriteGroup *overset = GetWagonOverrideSpriteSet(engine, v->u.rail.first_engine); |
|
344 |
|
345 if (overset != NULL) group = overset; |
|
346 } |
|
347 |
|
348 return group; |
|
349 } |
|
350 |
|
351 int GetCustomEngineSprite(EngineID engine, const Vehicle *v, byte direction) |
|
352 { |
|
353 const SpriteGroup *group; |
|
354 const RealSpriteGroup *rsg; |
|
355 byte cargo = GC_PURCHASE; |
|
356 byte loaded = 0; |
|
357 bool in_motion = 0; |
|
358 int totalsets, spriteset; |
|
359 int r; |
|
360 |
|
361 if (v != NULL) { |
|
362 int capacity = v->cargo_cap; |
|
363 |
|
364 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
|
365 assert(cargo != GC_INVALID); |
|
366 |
|
367 if (capacity == 0) capacity = 1; |
|
368 loaded = (v->cargo_count * 100) / capacity; |
|
369 |
|
370 if (v->type == VEH_Train) { |
|
371 in_motion = GetFirstVehicleInChain(v)->current_order.type != OT_LOADING; |
|
372 } else { |
|
373 in_motion = v->current_order.type != OT_LOADING; |
|
374 } |
|
375 } |
|
376 |
|
377 group = GetVehicleSpriteGroup(engine, v); |
|
378 group = ResolveVehicleSpriteGroup(group, v, 0, (resolve_callback) ResolveVehicleSpriteGroup); |
|
379 |
|
380 if (group == NULL && cargo != GC_DEFAULT) { |
|
381 // This group is empty but perhaps there'll be a default one. |
|
382 group = ResolveVehicleSpriteGroup(engine_custom_sprites[engine][GC_DEFAULT], v, 0, |
|
383 (resolve_callback) ResolveVehicleSpriteGroup); |
|
384 } |
|
385 |
|
386 if (group == NULL) |
|
387 return 0; |
|
388 |
|
389 assert(group->type == SGT_REAL); |
|
390 rsg = &group->g.real; |
|
391 |
|
392 if (!rsg->sprites_per_set) { |
|
393 // This group is empty. This function users should therefore |
|
394 // look up the sprite number in _engine_original_sprites. |
|
395 return 0; |
|
396 } |
|
397 |
|
398 assert(rsg->sprites_per_set <= 8); |
|
399 direction %= rsg->sprites_per_set; |
|
400 |
|
401 totalsets = in_motion ? rsg->loaded_count : rsg->loading_count; |
|
402 |
|
403 // My aim here is to make it possible to visually determine absolutely |
|
404 // empty and totally full vehicles. --pasky |
|
405 if (loaded == 100 || totalsets == 1) { // full |
|
406 spriteset = totalsets - 1; |
|
407 } else if (loaded == 0 || totalsets == 2) { // empty |
|
408 spriteset = 0; |
|
409 } else { // something inbetween |
|
410 spriteset = loaded * (totalsets - 2) / 100 + 1; |
|
411 // correct possible rounding errors |
|
412 if (!spriteset) |
|
413 spriteset = 1; |
|
414 else if (spriteset == totalsets - 1) |
|
415 spriteset--; |
|
416 } |
|
417 |
|
418 r = (in_motion ? rsg->loaded[spriteset]->g.result.result : rsg->loading[spriteset]->g.result.result) + direction; |
|
419 return r; |
|
420 } |
|
421 |
|
422 /** |
|
423 * Check if a wagon is currently using a wagon override |
|
424 * @param v The wagon to check |
|
425 * @return true if it is using an override, false otherwise |
|
426 */ |
|
427 bool UsesWagonOverride(const Vehicle* v) |
|
428 { |
|
429 assert(v->type == VEH_Train); |
|
430 return GetWagonOverrideSpriteSet(v->engine_type, v->u.rail.first_engine) != NULL; |
|
431 } |
|
432 |
|
433 /** |
|
434 * Evaluates a newgrf callback |
|
435 * @param callback_info info about which callback to evaluate |
|
436 * (bit 0-7) = CallBack id of the callback to use, see CallBackId enum |
|
437 * (bit 8-15) = Other info some callbacks need to have, callback specific, see CallBackId enum, not used yet |
|
438 * @param engine Engine type of the vehicle to evaluate the callback for |
|
439 * @param vehicle The vehicle to evaluate the callback for, NULL if it doesnt exist (yet) |
|
440 * @return The value the callback returned, or CALLBACK_FAILED if it failed |
|
441 */ |
|
442 uint16 GetCallBackResult(uint16 callback_info, EngineID engine, const Vehicle *v) |
|
443 { |
|
444 const SpriteGroup *group; |
|
445 byte cargo = GC_DEFAULT; |
|
446 |
|
447 if (v != NULL) |
|
448 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
|
449 |
|
450 group = engine_custom_sprites[engine][cargo]; |
|
451 |
|
452 if (v != NULL && v->type == VEH_Train) { |
|
453 const SpriteGroup *overset = GetWagonOverrideSpriteSet(engine, v->u.rail.first_engine); |
|
454 |
|
455 if (overset != NULL) group = overset; |
|
456 } |
|
457 |
|
458 group = ResolveVehicleSpriteGroup(group, v, callback_info, (resolve_callback) ResolveVehicleSpriteGroup); |
|
459 |
|
460 if (group == NULL && cargo != GC_DEFAULT) { |
|
461 // This group is empty but perhaps there'll be a default one. |
|
462 group = ResolveVehicleSpriteGroup(engine_custom_sprites[engine][GC_DEFAULT], v, callback_info, |
|
463 (resolve_callback) ResolveVehicleSpriteGroup); |
|
464 } |
|
465 |
|
466 if (group == NULL || group->type != SGT_CALLBACK) |
|
467 return CALLBACK_FAILED; |
|
468 |
|
469 return group->g.callback.result; |
|
470 } |
|
471 |
|
472 |
|
473 |
|
474 // Global variables are evil, yes, but we would end up with horribly overblown |
|
475 // calling convention otherwise and this should be 100% reentrant. |
|
476 static byte _vsg_random_triggers; |
|
477 static byte _vsg_bits_to_reseed; |
|
478 |
|
479 static const SpriteGroup *TriggerVehicleSpriteGroup(const SpriteGroup *spritegroup, |
|
480 Vehicle *veh, uint16 callback_info, resolve_callback resolve_func) |
|
481 { |
|
482 if (spritegroup == NULL) |
|
483 return NULL; |
|
484 |
|
485 if (spritegroup->type == SGT_RANDOMIZED) { |
|
486 _vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits( |
|
487 &spritegroup->g.random, |
|
488 _vsg_random_triggers, |
|
489 &veh->waiting_triggers |
|
490 ); |
|
491 } |
|
492 |
|
493 return ResolveVehicleSpriteGroup(spritegroup, veh, callback_info, resolve_func); |
|
494 } |
|
495 |
|
496 static void DoTriggerVehicle(Vehicle *veh, VehicleTrigger trigger, byte base_random_bits, bool first) |
|
497 { |
|
498 const SpriteGroup *group; |
|
499 const RealSpriteGroup *rsg; |
|
500 byte new_random_bits; |
|
501 |
|
502 _vsg_random_triggers = trigger; |
|
503 _vsg_bits_to_reseed = 0; |
|
504 group = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh, 0, |
|
505 (resolve_callback) TriggerVehicleSpriteGroup); |
|
506 |
|
507 if (group == NULL && veh->cargo_type != GC_DEFAULT) { |
|
508 // This group turned out to be empty but perhaps there'll be a default one. |
|
509 group = TriggerVehicleSpriteGroup(engine_custom_sprites[veh->engine_type][GC_DEFAULT], veh, 0, |
|
510 (resolve_callback) TriggerVehicleSpriteGroup); |
|
511 } |
|
512 |
|
513 if (group == NULL) |
|
514 return; |
|
515 |
|
516 assert(group->type == SGT_REAL); |
|
517 rsg = &group->g.real; |
|
518 |
|
519 new_random_bits = Random(); |
|
520 veh->random_bits &= ~_vsg_bits_to_reseed; |
|
521 veh->random_bits |= (first ? new_random_bits : base_random_bits) & _vsg_bits_to_reseed; |
|
522 |
|
523 switch (trigger) { |
|
524 case VEHICLE_TRIGGER_NEW_CARGO: |
|
525 /* All vehicles in chain get ANY_NEW_CARGO trigger now. |
|
526 * So we call it for the first one and they will recurse. */ |
|
527 /* Indexing part of vehicle random bits needs to be |
|
528 * same for all triggered vehicles in the chain (to get |
|
529 * all the random-cargo wagons carry the same cargo, |
|
530 * i.e.), so we give them all the NEW_CARGO triggered |
|
531 * vehicle's portion of random bits. */ |
|
532 assert(first); |
|
533 DoTriggerVehicle(GetFirstVehicleInChain(veh), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false); |
|
534 break; |
|
535 case VEHICLE_TRIGGER_DEPOT: |
|
536 /* We now trigger the next vehicle in chain recursively. |
|
537 * The random bits portions may be different for each |
|
538 * vehicle in chain. */ |
|
539 if (veh->next != NULL) |
|
540 DoTriggerVehicle(veh->next, trigger, 0, true); |
|
541 break; |
|
542 case VEHICLE_TRIGGER_EMPTY: |
|
543 /* We now trigger the next vehicle in chain |
|
544 * recursively. The random bits portions must be same |
|
545 * for each vehicle in chain, so we give them all |
|
546 * first chained vehicle's portion of random bits. */ |
|
547 if (veh->next != NULL) |
|
548 DoTriggerVehicle(veh->next, trigger, first ? new_random_bits : base_random_bits, false); |
|
549 break; |
|
550 case VEHICLE_TRIGGER_ANY_NEW_CARGO: |
|
551 /* Now pass the trigger recursively to the next vehicle |
|
552 * in chain. */ |
|
553 assert(!first); |
|
554 if (veh->next != NULL) |
|
555 DoTriggerVehicle(veh->next, VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); |
|
556 break; |
|
557 } |
|
558 } |
|
559 |
|
560 void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger) |
|
561 { |
|
562 if (trigger == VEHICLE_TRIGGER_DEPOT) { |
|
563 // store that the vehicle entered a depot this tick |
|
564 VehicleEnteredDepotThisTick(veh); |
|
565 } |
|
566 |
|
567 DoTriggerVehicle(veh, trigger, 0, true); |
|
568 } |
|
569 |
|
570 static char *_engine_custom_names[TOTAL_NUM_ENGINES]; |
|
571 |
|
572 void SetCustomEngineName(EngineID engine, const char *name) |
|
573 { |
|
574 _engine_custom_names[engine] = strdup(name); |
|
575 } |
|
576 |
|
577 void UnloadCustomEngineNames(void) |
|
578 { |
|
579 char **i; |
|
580 for (i = _engine_custom_names; i != endof(_engine_custom_names); i++) { |
|
581 free(*i); |
|
582 *i = NULL; |
|
583 } |
|
584 } |
|
585 |
|
586 StringID GetCustomEngineName(EngineID engine) |
|
587 { |
|
588 if (!_engine_custom_names[engine]) |
|
589 return _engine_name_strings[engine]; |
|
590 ttd_strlcpy(_userstring, _engine_custom_names[engine], lengthof(_userstring)); |
|
591 return STR_SPEC_USERSTRING; |
|
592 } |
|
593 |