diff --git a/engine.c b/engine.c index 3871330cc9..26f4720803 100644 --- a/engine.c +++ b/engine.c @@ -240,7 +240,7 @@ uint32 _engine_refit_masks[TOTAL_NUM_ENGINES]; typedef struct WagonOverride { byte *train_id; int trains; - SpriteGroup group; + SpriteGroup *group; } WagonOverride; typedef struct WagonOverrides { @@ -265,7 +265,7 @@ void SetWagonOverrideSprites(EngineID engine, SpriteGroup *group, byte *train_id /* FIXME: If we are replacing an override, release original SpriteGroup * to prevent leaks. But first we need to refcount the SpriteGroup. * --pasky */ - wo->group = *group; + wo->group = group; wo->trains = trains; wo->train_id = malloc(trains); memcpy(wo->train_id, train_id, trains); @@ -287,7 +287,7 @@ static const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, byte overri for (j = 0; j < wo->trains; j++) { if (wo->train_id[j] == overriding_engine) - return &wo->group; + return wo->group; } } return NULL; @@ -298,14 +298,14 @@ static const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, byte overri // (It isn't and shouldn't be like this in the GRF files since new cargo types // may appear in future - however it's more convenient to store it like this in // memory. --pasky) -static SpriteGroup _engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID]; +static SpriteGroup *engine_custom_sprites[TOTAL_NUM_ENGINES][NUM_GLOBAL_CID]; void SetCustomEngineSprites(EngineID engine, byte cargo, SpriteGroup *group) { /* FIXME: If we are replacing an override, release original SpriteGroup * to prevent leaks. But first we need to refcount the SpriteGroup. * --pasky */ - _engine_custom_sprites[engine][cargo] = *group; + engine_custom_sprites[engine][cargo] = group; } typedef SpriteGroup *(*resolve_callback)(const SpriteGroup *spritegroup, @@ -314,6 +314,9 @@ typedef SpriteGroup *(*resolve_callback)(const SpriteGroup *spritegroup, static const SpriteGroup* ResolveVehicleSpriteGroup(const SpriteGroup *spritegroup, const Vehicle *veh, uint16 callback_info, resolve_callback resolve_func) { + if (spritegroup == NULL) + return NULL; + //debug("spgt %d", spritegroup->type); switch (spritegroup->type) { case SGT_REAL: @@ -341,7 +344,7 @@ static const SpriteGroup* ResolveVehicleSpriteGroup(const SpriteGroup *spritegro * That means we should get the first target * (NOT the default one). */ if (dsg->num_ranges > 0) { - target = &dsg->ranges[0].group; + target = dsg->ranges[0].group; } else { target = dsg->default_group; } @@ -476,7 +479,7 @@ static const SpriteGroup* ResolveVehicleSpriteGroup(const SpriteGroup *spritegro /* 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 resolve_func(&rsg->groups[0], NULL, callback_info, resolve_func); + return resolve_func(rsg->groups[0], NULL, callback_info, resolve_func); } if (rsg->var_scope == VSG_SCOPE_PARENT) { @@ -504,7 +507,7 @@ static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle * assert(cargo != GC_INVALID); } - group = &_engine_custom_sprites[engine][cargo]; + group = engine_custom_sprites[engine][cargo]; if (v != NULL && v->type == VEH_Train) { const SpriteGroup *overset = GetWagonOverrideSpriteSet(engine, v->u.rail.first_engine); @@ -539,12 +542,15 @@ int GetCustomEngineSprite(EngineID engine, const Vehicle *v, byte direction) group = GetVehicleSpriteGroup(engine, v); group = ResolveVehicleSpriteGroup(group, v, 0, (resolve_callback) ResolveVehicleSpriteGroup); - if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && cargo != GC_DEFAULT) { + if (group == NULL && cargo != GC_DEFAULT) { // This group is empty but perhaps there'll be a default one. - group = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][GC_DEFAULT], v, 0, + group = ResolveVehicleSpriteGroup(engine_custom_sprites[engine][GC_DEFAULT], v, 0, (resolve_callback) ResolveVehicleSpriteGroup); } + if (group == NULL) + return 0; + assert(group->type == SGT_REAL); rsg = &group->g.real; @@ -605,7 +611,7 @@ uint16 GetCallBackResult(uint16 callback_info, EngineID engine, const Vehicle *v if (v != NULL) cargo = _global_cargo_id[_opt.landscape][v->cargo_type]; - group = &_engine_custom_sprites[engine][cargo]; + group = engine_custom_sprites[engine][cargo]; if (v != NULL && v->type == VEH_Train) { const SpriteGroup *overset = GetWagonOverrideSpriteSet(engine, v->u.rail.first_engine); @@ -615,13 +621,13 @@ uint16 GetCallBackResult(uint16 callback_info, EngineID engine, const Vehicle *v group = ResolveVehicleSpriteGroup(group, v, callback_info, (resolve_callback) ResolveVehicleSpriteGroup); - if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && cargo != GC_DEFAULT) { + if (group == NULL && cargo != GC_DEFAULT) { // This group is empty but perhaps there'll be a default one. - group = ResolveVehicleSpriteGroup(&_engine_custom_sprites[engine][GC_DEFAULT], v, callback_info, + group = ResolveVehicleSpriteGroup(engine_custom_sprites[engine][GC_DEFAULT], v, callback_info, (resolve_callback) ResolveVehicleSpriteGroup); } - if (group->type != SGT_CALLBACK) + if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED; return group->g.callback.result; @@ -637,6 +643,9 @@ static byte _vsg_bits_to_reseed; static const SpriteGroup *TriggerVehicleSpriteGroup(const SpriteGroup *spritegroup, Vehicle *veh, uint16 callback_info, resolve_callback resolve_func) { + if (spritegroup == NULL) + return NULL; + if (spritegroup->type == SGT_RANDOMIZED) { _vsg_bits_to_reseed |= RandomizedSpriteGroupTriggeredBits( &spritegroup->g.random, @@ -659,12 +668,15 @@ static void DoTriggerVehicle(Vehicle *veh, VehicleTrigger trigger, byte base_ran group = TriggerVehicleSpriteGroup(GetVehicleSpriteGroup(veh->engine_type, veh), veh, 0, (resolve_callback) TriggerVehicleSpriteGroup); - if (group->type == SGT_REAL && group->g.real.sprites_per_set == 0 && veh->cargo_type != GC_DEFAULT) { + if (group == NULL && veh->cargo_type != GC_DEFAULT) { // This group turned out to be empty but perhaps there'll be a default one. - group = TriggerVehicleSpriteGroup(&_engine_custom_sprites[veh->engine_type][GC_DEFAULT], veh, 0, + group = TriggerVehicleSpriteGroup(engine_custom_sprites[veh->engine_type][GC_DEFAULT], veh, 0, (resolve_callback) TriggerVehicleSpriteGroup); } + if (group == NULL) + return; + assert(group->type == SGT_REAL); rsg = &group->g.real; diff --git a/newgrf.c b/newgrf.c index ff23eded32..2d1542561b 100644 --- a/newgrf.c +++ b/newgrf.c @@ -1210,11 +1210,11 @@ static void VehicleChangeInfo(byte *buf, int len) * @param value The value that was used to represent this callback result * @return A spritegroup representing that callback result */ -SpriteGroup NewCallBackResult(uint16 value) +SpriteGroup *NewCallBackResultSpriteGroup(uint16 value) { - SpriteGroup group; + SpriteGroup *group = calloc(1, sizeof(*group)); - group.type = SGT_CALLBACK; + group->type = SGT_CALLBACK; // Old style callback results have the highest byte 0xFF so signify it is a callback result // New style ones only have the highest bit set (allows 15-bit results, instead of just 8) @@ -1223,7 +1223,7 @@ SpriteGroup NewCallBackResult(uint16 value) else value &= ~0x8000; - group.g.callback.result = value; + group->g.callback.result = value; return group; } @@ -1308,8 +1308,11 @@ static void NewSpriteGroup(byte *buf, int len) numloading = buf[4]; if (setid >= _cur_grffile->spritegroups_count) { - _cur_grffile->spritegroups_count = setid + 1; - _cur_grffile->spritegroups = realloc(_cur_grffile->spritegroups, _cur_grffile->spritegroups_count * sizeof(*_cur_grffile->spritegroups)); + // Allocate memory for new sprite group references. + _cur_grffile->spritegroups = realloc(_cur_grffile->spritegroups, (setid + 1) * sizeof(*_cur_grffile->spritegroups)); + // Initialise new space to NULL + for (; _cur_grffile->spritegroups_count < (setid + 1); _cur_grffile->spritegroups_count++) + _cur_grffile->spritegroups[_cur_grffile->spritegroups_count] = NULL; } if (numloaded == 0x81 || numloaded == 0x82) { @@ -1354,8 +1357,8 @@ static void NewSpriteGroup(byte *buf, int len) dg->ranges = calloc(dg->num_ranges, sizeof(*dg->ranges)); for (i = 0; i < dg->num_ranges; i++) { groupid = grf_load_word(&buf); - if (groupid & 0x8000) { - dg->ranges[i].group = NewCallBackResult(groupid); + if (HASBIT(groupid, 15)) { + dg->ranges[i].group = NewCallBackResultSpriteGroup(groupid); } else if (groupid >= _cur_grffile->spritegroups_count) { /* This doesn't exist for us. */ grf_load_word(&buf); // skip range @@ -1364,7 +1367,7 @@ static void NewSpriteGroup(byte *buf, int len) } else { /* XXX: If multiple surreal sets attach a surreal * set this way, we are in trouble. */ - dg->ranges[i].group = *_cur_grffile->spritegroups[groupid]; + dg->ranges[i].group = _cur_grffile->spritegroups[groupid]; } dg->ranges[i].low = grf_load_byte(&buf); @@ -1372,17 +1375,15 @@ static void NewSpriteGroup(byte *buf, int len) } groupid = grf_load_word(&buf); - if (groupid & 0x8000) { - dg->default_group = malloc(sizeof(*dg->default_group)); - *dg->default_group = NewCallBackResult(groupid); + if (HASBIT(groupid, 15)) { + dg->default_group = NewCallBackResultSpriteGroup(groupid); } else if (groupid >= _cur_grffile->spritegroups_count) { /* This spritegroup stinks. */ free(dg->ranges), dg->ranges = NULL; grfmsg(GMS_WARN, "NewSpriteGroup(%02x:0x%x): Default groupid %04x is cargo callback or unknown, ignoring spritegroup.", setid, numloaded, groupid); return; } else { - dg->default_group = malloc(sizeof(*dg->default_group)); - memcpy(dg->default_group, _cur_grffile->spritegroups[groupid], sizeof(*dg->default_group)); + dg->default_group = _cur_grffile->spritegroups[groupid]; } _cur_grffile->spritegroups[setid] = group; @@ -1428,7 +1429,7 @@ static void NewSpriteGroup(byte *buf, int len) } /* XXX: If multiple surreal sets attach a surreal * set this way, we are in trouble. */ - rg->groups[i] = *_cur_grffile->spritegroups[groupid]; + rg->groups[i] = _cur_grffile->spritegroups[groupid]; } _cur_grffile->spritegroups[setid] = group; @@ -1556,7 +1557,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len) continue; } - stat->spritegroup[1] = *_cur_grffile->spritegroups[groupid]; + stat->spritegroup[1] = _cur_grffile->spritegroups[groupid]; } } @@ -1574,7 +1575,7 @@ static void NewVehicle_SpriteGroupMapping(byte *buf, int len) uint8 stid = buf[3 + i]; StationSpec *stat = &_cur_grffile->stations[stid]; - stat->spritegroup[0] = *_cur_grffile->spritegroups[groupid]; + stat->spritegroup[0] = _cur_grffile->spritegroups[groupid]; stat->grfid = _cur_grffile->grfid; SetCustomStation(stid, stat); stat->sclass = STAT_CLASS_NONE; diff --git a/sprite.c b/sprite.c index 17ff58c0c7..a1cf5b278f 100644 --- a/sprite.c +++ b/sprite.c @@ -31,7 +31,7 @@ SpriteGroup *EvalDeterministicSpriteGroup(const DeterministicSpriteGroup *dsg, i DeterministicSpriteGroupRange *range = &dsg->ranges[i]; if (range->low <= value && value <= range->high) - return &range->group; + return range->group; } return dsg->default_group; @@ -72,7 +72,7 @@ SpriteGroup *EvalRandomizedSpriteGroup(const RandomizedSpriteGroup *rsg, byte ra mask = (rsg->num_groups - 1) << rsg->lowest_randbit; index = (random_bits & mask) >> rsg->lowest_randbit; assert(index < rsg->num_groups); - return &rsg->groups[index]; + return rsg->groups[index]; } byte RandomizedSpriteGroupTriggeredBits(const RandomizedSpriteGroup *rsg, diff --git a/sprite.h b/sprite.h index 67dce16125..2bacfd734f 100644 --- a/sprite.h +++ b/sprite.h @@ -107,7 +107,7 @@ typedef struct RandomizedSpriteGroup { byte num_groups; // must be power of 2 // Take the group with appropriate index: - SpriteGroup *groups; + SpriteGroup **groups; } RandomizedSpriteGroup; typedef struct CallbackResultSpriteGroup { @@ -133,7 +133,7 @@ struct SpriteGroup { }; struct DeterministicSpriteGroupRange { - SpriteGroup group; + SpriteGroup *group; byte low; byte high; }; diff --git a/station.h b/station.h index 8370313995..26f235225d 100644 --- a/station.h +++ b/station.h @@ -253,7 +253,7 @@ typedef struct StationSpec { /* Sprite offsets for renderdata->seq->image. spritegroup[0] is default * whilst spritegroup[1] is "GC_PURCHASE". */ - SpriteGroup spritegroup[2]; + SpriteGroup *spritegroup[2]; } StationSpec; /* Here, @stid is local per-GRFFile station index. If spec->localidx is not yet diff --git a/station_cmd.c b/station_cmd.c index aeda0fa771..4a62781f38 100644 --- a/station_cmd.c +++ b/station_cmd.c @@ -1286,7 +1286,7 @@ static const RealSpriteGroup *ResolveStationSpriteGroup(const SpriteGroup *spg, * That means we should get the first target * (NOT the default one). */ if (dsg->num_ranges > 0) { - target = &dsg->ranges[0].group; + target = dsg->ranges[0].group; } else { target = dsg->default_group; } @@ -1346,7 +1346,7 @@ static const RealSpriteGroup *ResolveStationSpriteGroup(const SpriteGroup *spg, uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, byte ctype) { - const RealSpriteGroup *rsg = ResolveStationSpriteGroup(&spec->spritegroup[ctype], st); + const RealSpriteGroup *rsg = ResolveStationSpriteGroup(spec->spritegroup[ctype], st); if (rsg->sprites_per_set != 0) { if (rsg->loading_count != 0) return rsg->loading[0];