summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortron <tron@openttd.org>2004-11-15 11:54:35 +0000
committertron <tron@openttd.org>2004-11-15 11:54:35 +0000
commit2f35fea0975fe5242d5383331aa2f16e9849135b (patch)
tree237d0fe88d9b9e72918861db823b6302db8c8a1c
parent57c472e093aad072d5c4113790dfafbca0f40fa6 (diff)
downloadopenttd-2f35fea0975fe5242d5383331aa2f16e9849135b.tar.xz
(svn r625) Almost complete support for deterministic variational vehicle spritegroups. (pasky)
-rw-r--r--engine.c155
-rw-r--r--sprite.h15
-rw-r--r--station_cmd.c5
3 files changed, 153 insertions, 22 deletions
diff --git a/engine.c b/engine.c
index 7e6944f5d..1a6d737ff 100644
--- a/engine.c
+++ b/engine.c
@@ -243,6 +243,153 @@ void SetCustomEngineSprites(byte engine, byte cargo, struct SpriteGroup *group)
_engine_custom_sprites[engine][cargo] = *group;
}
+static struct RealSpriteGroup *
+ResolveVehicleSpriteGroup(struct SpriteGroup *spritegroup, struct Vehicle *veh)
+{
+ switch (spritegroup->type) {
+ case SGT_REAL:
+ return &spritegroup->g.real;
+
+ case SGT_DETERMINISTIC: {
+ struct DeterministicSpriteGroup *dsg = &spritegroup->g.determ;
+ struct SpriteGroup *target;
+ int value = -1;
+
+ //debug("[%p] Having fun resolving variable %x", dsg->variable);
+
+ if ((dsg->variable >> 6) == 0) {
+ /* General property */
+ value = GetDeterministicSpriteValue(dsg->variable);
+
+ } else {
+ /* Station-specific property. */
+ if (dsg->var_scope == VSG_SCOPE_PARENT) {
+ /* First engine in the vehicle chain */
+ if (veh != NULL && veh->type == VEH_Train)
+ veh = GetFirstVehicleInChain(veh);
+ }
+
+ if (dsg->variable == 0x40) {
+ if (veh && veh->type == VEH_Train) {
+ Vehicle *u = GetFirstVehicleInChain(veh);
+ byte chain_before = 0, chain_after = 0;
+
+ while (u != veh) {
+ u = u->next;
+ chain_before++;
+ }
+ while (u->next != NULL) {
+ u = u->next;
+ chain_after++;
+ };
+
+ value = chain_before << 16 | chain_after << 8
+ | (chain_before + chain_after + 1);
+ } else {
+ value = 1; /* 1 vehicle in the chain */
+ }
+
+ } else {
+ // TTDPatch runs on little-endian arch;
+ // Variable is 0x80 + offset in TTD's vehicle structure
+ switch (dsg->variable - 0x80) {
+#define veh_prop(id_, value_) case id_: if (veh != NULL) value = value_; break /* XXX factorise "if" */
+ veh_prop(0x00, veh->type);
+ veh_prop(0x01, veh->subtype);
+ veh_prop(0x04, veh->index);
+ veh_prop(0x05, veh->index & 0xFF);
+ /* XXX? Is THIS right? */
+ veh_prop(0x0A, veh->next_order_param << 8 | veh->next_order);
+ veh_prop(0x0B, veh->next_order);
+ veh_prop(0x0C, veh->num_orders);
+ veh_prop(0x0D, veh->cur_order_index);
+ veh_prop(0x10, veh->load_unload_time_rem);
+ veh_prop(0x11, veh->load_unload_time_rem & 0xFF);
+ veh_prop(0x12, veh->date_of_last_service);
+ veh_prop(0x13, veh->date_of_last_service & 0xFF);
+ veh_prop(0x14, veh->service_interval);
+ veh_prop(0x15, veh->service_interval & 0xFF);
+ veh_prop(0x16, veh->last_station_visited);
+ veh_prop(0x17, veh->tick_counter);
+ veh_prop(0x18, veh->max_speed);
+ veh_prop(0x19, veh->max_speed & 0xFF);
+ veh_prop(0x1F, veh->direction);
+ veh_prop(0x28, veh->cur_image);
+ veh_prop(0x29, veh->cur_image & 0xFF);
+ veh_prop(0x32, veh->vehstatus);
+ veh_prop(0x33, veh->vehstatus);
+ veh_prop(0x34, veh->cur_speed);
+ veh_prop(0x35, veh->cur_speed & 0xFF);
+ veh_prop(0x36, veh->subspeed);
+ veh_prop(0x37, veh->acceleration);
+ veh_prop(0x39, veh->cargo_type);
+ veh_prop(0x3A, veh->cargo_cap);
+ veh_prop(0x3B, veh->cargo_cap & 0xFF);
+ veh_prop(0x3C, veh->cargo_count);
+ veh_prop(0x3D, veh->cargo_count & 0xFF);
+ veh_prop(0x3E, veh->cargo_source); // Probably useless; so what
+ veh_prop(0x3F, veh->cargo_days);
+ veh_prop(0x40, veh->age);
+ veh_prop(0x41, veh->age & 0xFF);
+ veh_prop(0x42, veh->max_age);
+ veh_prop(0x43, veh->max_age & 0xFF);
+ veh_prop(0x44, veh->build_year);
+ veh_prop(0x45, veh->unitnumber);
+ veh_prop(0x46, veh->engine_type);
+ veh_prop(0x47, veh->engine_type & 0xFF);
+ veh_prop(0x48, veh->spritenum);
+ veh_prop(0x49, veh->day_counter);
+ veh_prop(0x4A, veh->breakdowns_since_last_service);
+ veh_prop(0x4B, veh->breakdown_ctr);
+ veh_prop(0x4C, veh->breakdown_delay);
+ veh_prop(0x4D, veh->breakdown_chance);
+ veh_prop(0x4E, veh->reliability);
+ veh_prop(0x4F, veh->reliability & 0xFF);
+ veh_prop(0x50, veh->reliability_spd_dec);
+ veh_prop(0x51, veh->reliability_spd_dec & 0xFF);
+ veh_prop(0x52, veh->profit_this_year);
+ veh_prop(0x53, veh->profit_this_year & 0xFFFFFF);
+ veh_prop(0x54, veh->profit_this_year & 0xFFFF);
+ veh_prop(0x55, veh->profit_this_year & 0xFF);
+ veh_prop(0x56, veh->profit_last_year);
+ veh_prop(0x57, veh->profit_last_year & 0xFF);
+ veh_prop(0x58, veh->profit_last_year);
+ veh_prop(0x59, veh->profit_last_year & 0xFF);
+ veh_prop(0x5A, veh->next_in_chain_old);
+ veh_prop(0x5B, veh->next_in_chain_old & 0xFF);
+ veh_prop(0x5C, veh->value);
+ veh_prop(0x5D, veh->value & 0xFFFFFF);
+ veh_prop(0x5E, veh->value & 0xFFFF);
+ veh_prop(0x5F, veh->value & 0xFF);
+ veh_prop(0x60, veh->string_id);
+ veh_prop(0x61, veh->string_id & 0xFF);
+ /* 00h..07h=sub image? 40h=in tunnel; actually some kind of status
+ * aircraft: >=13h when in flight
+ * train, ship: 80h=in depot
+ * rv: 0feh=in depot */
+ /* TODO veh_prop(0x62, veh->???); */
+
+ /* TODO: The rest is per-vehicle, I hope no GRF file looks so far.
+ * But they won't let us have an easy ride so surely *some* GRF
+ * file does. So someone needs to do this too. --pasky */
+
+#undef veh_prop
+ }
+ }
+ }
+
+ target = value != -1 ? EvalDeterministicSpriteGroup(dsg, value) : dsg->default_group;
+ //debug("Resolved variable %x: %d", dsg->variable, value);
+ return ResolveVehicleSpriteGroup(target, veh);
+ }
+
+ default:
+ case SGT_RANDOM:
+ error("I don't know how to handle random spritegroups yet!");
+ return NULL;
+ }
+}
+
int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction)
{
struct SpriteGroup *group;
@@ -270,13 +417,11 @@ int GetCustomEngineSprite(byte engine, Vehicle *v, byte direction)
if (overset) group = overset;
}
- /* TODO: Resolve surreal groups properly. --pasky */
- rsg = TriviallyGetRSG(group);
+ rsg = ResolveVehicleSpriteGroup(group, v);
- if (!rsg->sprites_per_set && cargo != 29) {
+ if (rsg->sprites_per_set == 0 && cargo != 29) { /* XXX magic number */
// This group is empty but perhaps there'll be a default one.
- /* TODO: Resolve surreal groups properly. --pasky */
- rsg = TriviallyGetRSG(&_engine_custom_sprites[engine][29]);
+ rsg = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][29], v);
}
if (!rsg->sprites_per_set) {
diff --git a/sprite.h b/sprite.h
index ded9ce6a8..b75b30dd4 100644
--- a/sprite.h
+++ b/sprite.h
@@ -101,10 +101,6 @@ struct DeterministicSpriteGroupRange {
byte high;
};
-/* This is a temporary helper for SpriteGroup users not supporting variational
- * sprite groups yet - it just traverses those cowardly, always taking the
- * default choice until it hits a real sprite group, returning it. */
-static struct RealSpriteGroup *TriviallyGetRSG(struct SpriteGroup *sg);
/* This takes value (probably of the variable specified in the group) and
* chooses corresponding SpriteGroup accordingly to the given
* DeterministicSpriteGroup. */
@@ -112,15 +108,4 @@ struct SpriteGroup *EvalDeterministicSpriteGroup(struct DeterministicSpriteGroup
/* Get value of a common deterministic SpriteGroup variable. */
int GetDeterministicSpriteValue(byte var);
-
-
-/**** Inline functions ****/
-
-static INLINE struct RealSpriteGroup *TriviallyGetRSG(struct SpriteGroup *sg)
-{
- if (sg->type == SGT_REAL)
- return &sg->g.real;
- return TriviallyGetRSG(sg->g.determ.default_group);
-}
-
#endif
diff --git a/station_cmd.c b/station_cmd.c
index d8181610a..bb110011b 100644
--- a/station_cmd.c
+++ b/station_cmd.c
@@ -1035,7 +1035,8 @@ ResolveStationSpriteGroup(struct SpriteGroup *spritegroup, struct Station *stat)
value = 0x01010000;
} else {
/* TODO: Only small fraction done. */
- // 0x80 + offset - 0x10
+ // TTDPatch runs on little-endian arch;
+ // Variable is 0x70 + offset in the TTD's station structure
switch (dsg->variable - 0x70) {
case 0x80:
if (stat) value = stat->facilities;
@@ -1053,7 +1054,7 @@ ResolveStationSpriteGroup(struct SpriteGroup *spritegroup, struct Station *stat)
if (stat) value = stat->airport_flags & 0xFFFF;
break;
case 0x87:
- if (stat) value = (stat->airport_flags >> 8) & 0xFF;
+ if (stat) value = stat->airport_flags & 0xFF;
break;
case 0x8A:
if (stat) value = stat->build_date;