From 13f0b6c0cf754184cfef8645e709f10240da5f98 Mon Sep 17 00:00:00 2001 From: tron Date: Wed, 17 Nov 2004 08:52:47 +0000 Subject: (svn r654) Hopefully complete support for randomized variational spritegroups (i.e. the cars transporter in DBSetXL gets different cars each time) (pasky) --- engine.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 136 insertions(+), 16 deletions(-) (limited to 'engine.c') diff --git a/engine.c b/engine.c index fdc9eda01..23916de88 100644 --- a/engine.c +++ b/engine.c @@ -243,9 +243,15 @@ void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group) _engine_custom_sprites[engine][cargo] = *group; } +typedef struct RealSpriteGroup *(*resolve_callback)(struct SpriteGroup *spritegroup, + struct Vehicle *veh, + void *callback); /* XXX data pointer used as function pointer */ + static struct RealSpriteGroup * -ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh) +ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh, + resolve_callback callback) { + //debug("spgt %d", spritegroup->type); switch (spritegroup->type) { case SGT_REAL: return &spritegroup->g.real; @@ -274,7 +280,7 @@ ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh) } else { target = dsg->default_group; } - return ResolveVehicleSpriteGroup(target, NULL); + return callback(target, NULL, callback); } if (dsg->var_scope == VSG_SCOPE_PARENT) { @@ -393,33 +399,44 @@ ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh) } target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group; - //debug("Resolved variable %x: %d", dsg->variable, value); - return ResolveVehicleSpriteGroup(target, veh); + //debug("Resolved variable %x: %d, %p", dsg->variable, value, callback); + return callback(target, veh, callback); + } + + case SGT_RANDOMIZED: { + struct RandomizedSpriteGroup *rsg = &spritegroup->g.random; + + if (veh == NULL) { + /* Purchase list of something. Show the first one. */ + assert(rsg->num_groups > 0); + //debug("going for %p: %d", rsg->groups[0], rsg->groups[0].type); + return callback(&rsg->groups[0], NULL, callback); + } + + if (rsg->var_scope == VSG_SCOPE_PARENT) { + /* First engine in the vehicle chain */ + if (veh->type == VEH_Train) + veh = GetFirstVehicleInChain(veh); + } + + return callback(EvalRandomizedSpriteGroup(rsg, veh->random_bits), veh, callback); } default: - case SGT_RANDOM: - error("I don't know how to handle random spritegroups yet!"); + error("I don't know how to handle such a spritegroup %d!", spritegroup->type); return NULL; } } -int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) +static struct SpriteGroup *GetVehicleSpriteGroup(byte engine, Vehicle *v) { struct SpriteGroup *group; - struct RealSpriteGroup *rsg; uint16 overriding_engine = -1; byte cargo = CID_PURCHASE; - byte loaded = 0; - byte in_motion = 0; - int totalsets, spriteset; - int r; if (v != NULL) { overriding_engine = v->type == VEH_Train ? v->u.rail.first_engine : -1; cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; - loaded = ((v->cargo_count + 1) * 100) / (v->cargo_cap + 1); - in_motion = !!v->cur_speed; } group = &_engine_custom_sprites[engine][cargo]; @@ -431,11 +448,35 @@ int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) if (overset) group = overset; } - rsg = ResolveVehicleSpriteGroup(group, v); + return group; +} + +int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) +{ + struct SpriteGroup *group; + struct RealSpriteGroup *rsg; + byte cargo = CID_PURCHASE; + byte loaded = 0; + bool in_motion = 0; + int totalsets, spriteset; + int r; + + if (v != NULL) { + int capacity = v->cargo_cap; + + cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; + if (capacity == 0) capacity = 1; + loaded = (v->cargo_count * 100) / capacity; + in_motion = (v->cur_speed != 0); + } + + group = GetVehicleSpriteGroup(engine, v); + rsg = ResolveVehicleSpriteGroup(group, v, (resolve_callback) ResolveVehicleSpriteGroup); if (rsg->sprites_per_set == 0 && cargo != 29) { /* XXX magic number */ // This group is empty but perhaps there'll be a default one. - rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v); + rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v, + (resolve_callback) ResolveVehicleSpriteGroup); } if (!rsg->sprites_per_set) { @@ -470,6 +511,85 @@ int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction) } +// Global variables are evil, yes, but we would end up with horribly overblown +// calling convention otherwise and this should be 100% reentrant. +static byte _vsg_random_triggers; +static byte _vsg_bits_to_reseed; + +extern int _custom_sprites_base; + +static struct RealSpriteGroup * +TriggerVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh, + resolve_callback callback) +{ + if (spritegroup->type == SGT_RANDOMIZED) + _vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits(&spritegroup->g.random, + _vsg_random_triggers, + &veh->waiting_triggers); + + return ResolveVehicleSpriteGroup(spritegroup, veh, callback); +} + +static void DoTriggerVehicle(Vehicle *veh, enum VehicleTrigger trigger, byte base_random_bits, bool first) +{ + struct RealSpriteGroup *rsg; + byte new_random_bits; + + _vsg_random_triggers = trigger; + _vsg_bits_to_reseed = 0; + rsg = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh, + (resolve_callback) TriggerVehicleSpriteGroup); + if (rsg->sprites_per_set == 0 && veh->cargo_type != 29) { /* XXX magic number */ + // This group turned out to be empty but perhaps there'll be a default one. + rsg = TriggerVehicleSpriteGroup(&_engine_custom_sprites[veh->engine_type][29], veh, + (resolve_callback) TriggerVehicleSpriteGroup); + } + veh->random_bits &= ~_vsg_bits_to_reseed; + veh->random_bits |= (first ? (new_random_bits = Random()) : base_random_bits) & _vsg_bits_to_reseed; + + switch (trigger) { + case VEHICLE_TRIGGER_NEW_CARGO: + /* All vehicles in chain get ANY_NEW_CARGO trigger now. + * So we call it for the first one and they will recurse. */ + /* Indexing part of vehicle random bits needs to be + * same for all triggered vehicles in the chain (to get + * all the random-cargo wagons carry the same cargo, + * i.e.), so we give them all the NEW_CARGO triggered + * vehicle's portion of random bits. */ + assert(first); + DoTriggerVehicle(GetFirstVehicleInChain(veh), VEHICLE_TRIGGER_ANY_NEW_CARGO, new_random_bits, false); + break; + case VEHICLE_TRIGGER_DEPOT: + /* We now trigger the next vehicle in chain recursively. + * The random bits portions may be different for each + * vehicle in chain. */ + if (veh->next != NULL) + DoTriggerVehicle(veh->next, trigger, 0, true); + break; + case VEHICLE_TRIGGER_EMPTY: + /* We now trigger the next vehicle in chain + * recursively. The random bits portions must be same + * for each vehicle in chain, so we give them all + * first chained vehicle's portion of random bits. */ + if (veh->next != NULL) + DoTriggerVehicle(veh->next, trigger, first ? new_random_bits : base_random_bits, false); + break; + case VEHICLE_TRIGGER_ANY_NEW_CARGO: + /* Now pass the trigger recursively to the next vehicle + * in chain. */ + assert(!first); + if (veh->next != NULL) + DoTriggerVehicle(veh->next, VEHICLE_TRIGGER_ANY_NEW_CARGO, base_random_bits, false); + break; + } +} + +void TriggerVehicle(Vehicle *veh, enum VehicleTrigger trigger) +{ + DoTriggerVehicle(veh, trigger, 0, true); +} + + static char *_engine_custom_names[256]; void SetCustomEngineName(int engine, char *name) -- cgit v1.2.3-54-g00ecf