1
0
mirror of https://github.com/OpenTTD/OpenTTD.git synced 2025-08-12 09:09:09 +00:00

(svn r654) Hopefully complete support for randomized variational spritegroups (i.e. the cars transporter in DBSetXL gets different cars each time) (pasky)

This commit is contained in:
tron
2004-11-17 08:52:47 +00:00
parent 0086bb9d06
commit 13f0b6c0cf
13 changed files with 301 additions and 23 deletions

152
engine.c
View File

@@ -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)