241 * to prevent leaks. But first we need to refcount the SpriteGroup. |
241 * to prevent leaks. But first we need to refcount the SpriteGroup. |
242 * --pasky */ |
242 * --pasky */ |
243 _engine_custom_sprites[engine][cargo] = *group; |
243 _engine_custom_sprites[engine][cargo] = *group; |
244 } |
244 } |
245 |
245 |
|
246 typedef struct RealSpriteGroup *(*resolve_callback)(struct SpriteGroup *spritegroup, |
|
247 struct Vehicle *veh, |
|
248 void *callback); /* XXX data pointer used as function pointer */ |
|
249 |
246 static struct RealSpriteGroup * |
250 static struct RealSpriteGroup * |
247 ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh) |
251 ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh, |
248 { |
252 resolve_callback callback) |
|
253 { |
|
254 //debug("spgt %d", spritegroup->type); |
249 switch (spritegroup->type) { |
255 switch (spritegroup->type) { |
250 case SGT_REAL: |
256 case SGT_REAL: |
251 return &spritegroup->g.real; |
257 return &spritegroup->g.real; |
252 |
258 |
253 case SGT_DETERMINISTIC: { |
259 case SGT_DETERMINISTIC: { |
391 } |
397 } |
392 } |
398 } |
393 } |
399 } |
394 |
400 |
395 target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group; |
401 target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group; |
396 //debug("Resolved variable %x: %d", dsg->variable, value); |
402 //debug("Resolved variable %x: %d, %p", dsg->variable, value, callback); |
397 return ResolveVehicleSpriteGroup(target, veh); |
403 return callback(target, veh, callback); |
398 } |
404 } |
399 |
405 |
|
406 case SGT_RANDOMIZED: { |
|
407 struct RandomizedSpriteGroup *rsg = &spritegroup->g.random; |
|
408 |
|
409 if (veh == NULL) { |
|
410 /* Purchase list of something. Show the first one. */ |
|
411 assert(rsg->num_groups > 0); |
|
412 //debug("going for %p: %d", rsg->groups[0], rsg->groups[0].type); |
|
413 return callback(&rsg->groups[0], NULL, callback); |
|
414 } |
|
415 |
|
416 if (rsg->var_scope == VSG_SCOPE_PARENT) { |
|
417 /* First engine in the vehicle chain */ |
|
418 if (veh->type == VEH_Train) |
|
419 veh = GetFirstVehicleInChain(veh); |
|
420 } |
|
421 |
|
422 return callback(EvalRandomizedSpriteGroup(rsg, veh->random_bits), veh, callback); |
|
423 } |
|
424 |
400 default: |
425 default: |
401 case SGT_RANDOM: |
426 error("I don't know how to handle such a spritegroup %d!", spritegroup->type); |
402 error("I don't know how to handle random spritegroups yet!"); |
|
403 return NULL; |
427 return NULL; |
404 } |
428 } |
405 } |
429 } |
406 |
430 |
407 int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) |
431 static struct SpriteGroup *GetVehicleSpriteGroup(byte engine, Vehicle *v) |
408 { |
432 { |
409 struct SpriteGroup *group; |
433 struct SpriteGroup *group; |
410 struct RealSpriteGroup *rsg; |
|
411 uint16 overriding_engine = -1; |
434 uint16 overriding_engine = -1; |
412 byte cargo = CID_PURCHASE; |
435 byte cargo = CID_PURCHASE; |
413 byte loaded = 0; |
|
414 byte in_motion = 0; |
|
415 int totalsets, spriteset; |
|
416 int r; |
|
417 |
436 |
418 if (v != NULL) { |
437 if (v != NULL) { |
419 overriding_engine = v->type == VEH_Train ? v->u.rail.first_engine : -1; |
438 overriding_engine = v->type == VEH_Train ? v->u.rail.first_engine : -1; |
420 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
439 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
421 loaded = ((v->cargo_count + 1) * 100) / (v->cargo_cap + 1); |
|
422 in_motion = !!v->cur_speed; |
|
423 } |
440 } |
424 |
441 |
425 group = &_engine_custom_sprites[engine][cargo]; |
442 group = &_engine_custom_sprites[engine][cargo]; |
426 |
443 |
427 if (overriding_engine != 0xffff) { |
444 if (overriding_engine != 0xffff) { |
429 |
446 |
430 overset = GetWagonOverrideSpriteSet(engine, overriding_engine); |
447 overset = GetWagonOverrideSpriteSet(engine, overriding_engine); |
431 if (overset) group = overset; |
448 if (overset) group = overset; |
432 } |
449 } |
433 |
450 |
434 rsg = ResolveVehicleSpriteGroup(group, v); |
451 return group; |
|
452 } |
|
453 |
|
454 int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) |
|
455 { |
|
456 struct SpriteGroup *group; |
|
457 struct RealSpriteGroup *rsg; |
|
458 byte cargo = CID_PURCHASE; |
|
459 byte loaded = 0; |
|
460 bool in_motion = 0; |
|
461 int totalsets, spriteset; |
|
462 int r; |
|
463 |
|
464 if (v != NULL) { |
|
465 int capacity = v->cargo_cap; |
|
466 |
|
467 cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; |
|
468 if (capacity == 0) capacity = 1; |
|
469 loaded = (v->cargo_count * 100) / capacity; |
|
470 in_motion = (v->cur_speed != 0); |
|
471 } |
|
472 |
|
473 group = GetVehicleSpriteGroup(engine, v); |
|
474 rsg = ResolveVehicleSpriteGroup(group, v, (resolve_callback) ResolveVehicleSpriteGroup); |
435 |
475 |
436 if (rsg->sprites_per_set == 0 && cargo != 29) { /* XXX magic number */ |
476 if (rsg->sprites_per_set == 0 && cargo != 29) { /* XXX magic number */ |
437 // This group is empty but perhaps there'll be a default one. |
477 // This group is empty but perhaps there'll be a default one. |
438 rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v); |
478 rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v, |
|
479 (resolve_callback) ResolveVehicleSpriteGroup); |
439 } |
480 } |
440 |
481 |
441 if (!rsg->sprites_per_set) { |
482 if (!rsg->sprites_per_set) { |
442 // This group is empty. This function users should therefore |
483 // This group is empty. This function users should therefore |
443 // look up the sprite number in _engine_original_sprites. |
484 // look up the sprite number in _engine_original_sprites. |
465 spriteset--; |
506 spriteset--; |
466 } |
507 } |
467 |
508 |
468 r = (in_motion ? rsg->loaded[spriteset] : rsg->loading[spriteset]) + direction; |
509 r = (in_motion ? rsg->loaded[spriteset] : rsg->loading[spriteset]) + direction; |
469 return r; |
510 return r; |
|
511 } |
|
512 |
|
513 |
|
514 // Global variables are evil, yes, but we would end up with horribly overblown |
|
515 // calling convention otherwise and this should be 100% reentrant. |
|
516 static byte _vsg_random_triggers; |
|
517 static byte _vsg_bits_to_reseed; |
|
518 |
|
519 extern int _custom_sprites_base; |
|
520 |
|
521 static struct RealSpriteGroup * |
|
522 TriggerVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh, |
|
523 resolve_callback callback) |
|
524 { |
|
525 if (spritegroup->type == SGT_RANDOMIZED) |
|
526 _vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits(&spritegroup->g.random, |
|
527 _vsg_random_triggers, |
|
528 &veh->waiting_triggers); |
|
529 |
|
530 return ResolveVehicleSpriteGroup(spritegroup, veh, callback); |
|
531 } |
|
532 |
|
533 static void DoTriggerVehicle(Vehicle *veh, enum VehicleTrigger trigger, byte base_random_bits, bool first) |
|
534 { |
|
535 struct RealSpriteGroup *rsg; |
|
536 byte new_random_bits; |
|
537 |
|
538 _vsg_random_triggers = trigger; |
|
539 _vsg_bits_to_reseed = 0; |
|
540 rsg = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh, |
|
541 (resolve_callback) TriggerVehicleSpriteGroup); |
|
542 if (rsg->sprites_per_set == 0 && veh->cargo_type != 29) { /* XXX magic number */ |
|
543 // This group turned out to be empty but perhaps there'll be a default one. |
|
544 rsg = TriggerVehicleSpriteGroup(&_engine_custom_sprites[veh->engine_type][29], veh, |
|
545 (resolve_callback) TriggerVehicleSpriteGroup); |
|
546 } |
|
547 veh->random_bits &= ~_vsg_bits_to_reseed; |
|
548 veh->random_bits |= (first ? (new_random_bits = Random()) : base_random_bits) & _vsg_bits_to_reseed; |
|
549 |
|
550 switch (trigger) { |
|
551 case VEHICLE_TRIGGER_NEW_CARGO: |
|
552 /* All vehicles in chain get ANY_NEW_CARGO trigger now. |
|
553 * So we call it for the first one and they will recurse. */ |
|
554 /* Indexing part of vehicle random bits needs to be |
|
555 * same for all triggered vehicles in the chain (to get |
|
556 * all the random-cargo wagons carry the same cargo, |
|
557 * i.e.), so we give them all the NEW_CARGO triggered |
|
558 * vehicle's portion of random bits. */ |
|
559 assert(first); |
|
560 DoTriggerVehicle(GetFirstVehicleInChain(veh), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false); |
|
561 break; |
|
562 case VEHICLE_TRIGGER_DEPOT: |
|
563 /* We now trigger the next vehicle in chain recursively. |
|
564 * The random bits portions may be different for each |
|
565 * vehicle in chain. */ |
|
566 if (veh->next != NULL) |
|
567 DoTriggerVehicle(veh->next, trigger, 0, true); |
|
568 break; |
|
569 case VEHICLE_TRIGGER_EMPTY: |
|
570 /* We now trigger the next vehicle in chain |
|
571 * recursively. The random bits portions must be same |
|
572 * for each vehicle in chain, so we give them all |
|
573 * first chained vehicle's portion of random bits. */ |
|
574 if (veh->next != NULL) |
|
575 DoTriggerVehicle(veh->next, trigger, first ? new_random_bits : base_random_bits, false); |
|
576 break; |
|
577 case VEHICLE_TRIGGER_ANY_NEW_CARGO: |
|
578 /* Now pass the trigger recursively to the next vehicle |
|
579 * in chain. */ |
|
580 assert(!first); |
|
581 if (veh->next != NULL) |
|
582 DoTriggerVehicle(veh->next, VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); |
|
583 break; |
|
584 } |
|
585 } |
|
586 |
|
587 void TriggerVehicle(Vehicle *veh, enum VehicleTrigger trigger) |
|
588 { |
|
589 DoTriggerVehicle(veh, trigger, 0, true); |
470 } |
590 } |
471 |
591 |
472 |
592 |
473 static char *_engine_custom_names[256]; |
593 static char *_engine_custom_names[256]; |
474 |
594 |