From de84d6338d50a35aaee6ae296c796ed3e55b4435 Mon Sep 17 00:00:00 2001 From: peter1138 Date: Wed, 19 Apr 2006 07:17:00 +0000 Subject: [PATCH] (svn r4473) - Newstations: - Alter parameters of CMD_BUILD_RAILROAD_STATION to accept a custom station class and id. - Add a dynamically allocated list of custom stations that the SpecIndex (m4) references. --- newgrf_station.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++ newgrf_station.h | 7 ++++ station.h | 10 +++++ station_cmd.c | 44 +++++++++++++++----- 4 files changed, 155 insertions(+), 9 deletions(-) diff --git a/newgrf_station.c b/newgrf_station.c index 114152b26c..ce336c6ae6 100644 --- a/newgrf_station.c +++ b/newgrf_station.c @@ -7,6 +7,7 @@ #include "debug.h" #include "sprite.h" #include "station.h" +#include "station_map.h" #include "newgrf_station.h" static StationClass station_classes[STAT_CLASS_MAX]; @@ -69,6 +70,17 @@ StationClassID AllocateStationClass(uint32 class) return STAT_CLASS_DFLT; } +/** + * Get the number of station classes in use. + * @return Number of station classes. + */ +uint GetNumStationClasses(void) +{ + uint i; + for (i = 0; i < STAT_CLASS_MAX && station_classes[i].id != 0; i++); + return i; +} + /** * Return the number of stations for the given station class. * @param sclass Index of the station class. @@ -198,3 +210,94 @@ uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, by * emergency measure. */ return 0; } + + +/** + * Allocate a StationSpec to a Station. This is called once per build operation. + * @param spec StationSpec to allocate. + * @param st Station to allocate it to. + * @param exec Whether to actually allocate the spec. + * @return Index within the Station's spec list, or -1 if the allocation failed. + */ +int AllocateSpecToStation(const StationSpec *spec, Station *st, bool exec) +{ + uint i; + + if (spec == NULL) return 0; + + /* Check if this spec has already been allocated */ + for (i = 1; i < st->num_specs && i < 256; i++) { + if (st->speclist[i].spec == spec) return i; + } + + for (i = 1; i < st->num_specs && i < 256; i++) { + if (st->speclist[i].spec == NULL && st->speclist[i].grfid == 0) break; + } + + if (i < 256) { + if (exec) { + if (i >= st->num_specs) { + st->num_specs = i + 1; + st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist)); + + if (st->num_specs == 2) { + /* Initial allocation */ + st->speclist[0].spec = NULL; + st->speclist[0].grfid = 0; + st->speclist[0].localidx = 0; + } + } + + st->speclist[i].spec = spec; + st->speclist[i].grfid = spec->grfid; + st->speclist[i].localidx = spec->localidx; + } + return i; + } + + return -1; +} + + +/** Deallocate a StationSpec from a Station. Called when removing a single station tile. + * @param st Station to work with. + * @param specindex Index of the custom station within the Station's spec list. + * @return Indicates whether the StationSpec was deallocated. + */ +bool DeallocateSpecFromStation(Station *st, byte specindex) +{ + bool freeable = true; + + /* specindex of 0 (default) is never freeable */ + if (specindex == 0) return false; + + /* Check all tiles over the station to check if the specindex is still in use */ + BEGIN_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile) { + if (IsTileType(tile, MP_STATION) && GetStationIndex(tile) == st->index && IsRailwayStation(tile) && GetCustomStationSpecIndex(tile) == specindex) { + freeable = false; + break; + } + } END_TILE_LOOP(tile, st->trainst_w, st->trainst_h, st->train_tile) + + if (freeable) { + /* This specindex is no longer in use, so deallocate it */ + st->speclist[specindex].spec = NULL; + st->speclist[specindex].grfid = 0; + st->speclist[specindex].localidx = 0; + + /* If this was the highest spec index, reallocate */ + if (specindex == st->num_specs - 1) { + for (; st->speclist[st->num_specs - 1].grfid == 0 && st->num_specs > 1; st->num_specs--); + + if (st->num_specs > 1) { + st->speclist = realloc(st->speclist, st->num_specs * sizeof(*st->speclist)); + } else { + free(st->speclist); + st->num_specs = 0; + st->speclist = NULL; + } + } + } + + return freeable; +} diff --git a/newgrf_station.h b/newgrf_station.h index 912c7626f7..2d9123b3ba 100644 --- a/newgrf_station.h +++ b/newgrf_station.h @@ -84,6 +84,7 @@ typedef struct stationclass { void ResetStationClasses(void); StationClassID AllocateStationClass(uint32 class); void SetStationClassName(StationClassID sclass, const char *name); +uint GetNumStationClasses(void); uint GetNumCustomStations(StationClassID sclass); void SetCustomStation(StationSpec *spec); @@ -94,4 +95,10 @@ const StationSpec *GetCustomStation(StationClassID sclass, uint station); * structure is used for variational sprite groups. */ uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, byte ctype); +/* Allocate a StationSpec to a Station. This is called once per build operation. */ +int AllocateSpecToStation(const StationSpec *spec, Station *st, bool exec); + +/* Deallocate a StationSpec from a Station. Called when removing a single station tile. */ +bool DeallocateSpecFromStation(Station *st, byte specindex); + #endif /* NEWGRF_STATION_H */ diff --git a/station.h b/station.h index 2869708d5e..f44d55c00c 100644 --- a/station.h +++ b/station.h @@ -41,6 +41,12 @@ typedef struct RoadStop { struct RoadStop *prev; } RoadStop; +typedef struct StationSpecList { + const StationSpec *spec; + uint32 grfid; /// GRF ID of this custom station + uint8 localidx; /// Station ID within GRF of station +} StationSpecList; + struct Station { TileIndex xy; RoadStop *bus_stops; @@ -65,6 +71,10 @@ struct Station { // trainstation width/height byte trainst_w, trainst_h; + /** List of custom stations (StationSpecs) allocated to the station */ + uint num_specs; + StationSpecList *speclist; + uint16 build_date; //uint16 airport_flags; diff --git a/station_cmd.c b/station_cmd.c index ed448d3aec..0871d6d4b5 100644 --- a/station_cmd.c +++ b/station_cmd.c @@ -50,6 +50,17 @@ static void StationPoolNewBlock(uint start_item) FOR_ALL_STATIONS_FROM(st, start_item) st->index = start_item++; } +static void StationPoolCleanBlock(uint start_item, uint end_item) +{ + uint i; + + for (i = start_item; i <= end_item; i++) { + Station *st = GetStation(i); + free(st->speclist); + st->speclist = NULL; + } +} + /** * Called if a new block is added to the roadstop-pool */ @@ -61,7 +72,7 @@ static void RoadStopPoolNewBlock(uint start_item) } /* Initialize the station-pool and roadstop-pool */ -MemoryPool _station_pool = { "Stations", STATION_POOL_MAX_BLOCKS, STATION_POOL_BLOCK_SIZE_BITS, sizeof(Station), &StationPoolNewBlock, NULL, 0, 0, NULL }; +MemoryPool _station_pool = { "Stations", STATION_POOL_MAX_BLOCKS, STATION_POOL_BLOCK_SIZE_BITS, sizeof(Station), &StationPoolNewBlock, &StationPoolCleanBlock, 0, 0, NULL }; MemoryPool _roadstop_pool = { "RoadStop", ROADSTOP_POOL_MAX_BLOCKS, ROADSTOP_POOL_BLOCK_SIZE_BITS, sizeof(RoadStop), &RoadStopPoolNewBlock, NULL, 0, 0, NULL }; @@ -939,8 +950,8 @@ static void GetStationLayout(byte *layout, int numtracks, int plat_len, const St * - p1 = (bit 16-23) - platform length * @param p2 various bitstuffed elements * - p2 = (bit 0- 3) - railtype (p2 & 0xF) - * - p2 = (bit 4) - set for custom station (p2 & 0x10) - * - p2 = (bit 8-..) - custom station id (p2 >> 8) + * - p2 = (bit 8-15) - custom station class + * - p2 = (bit 16-23) - custom station id */ int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint32 p2) { @@ -951,6 +962,8 @@ int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint3 int plat_len, numtracks; Axis axis; uint finalvalues[3]; + const StationSpec *statspec; + int specindex; SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); @@ -1025,10 +1038,17 @@ int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint3 if (flags & DC_EXEC) StationInitialize(st, tile_org); } + /* Check if the given station class is valid */ + if (GB(p2, 8, 8) >= STAT_CLASS_MAX) return CMD_ERROR; + + /* Check if we can allocate a custom stationspec to this station */ + statspec = GetCustomStation(GB(p2, 8, 8), GB(p2, 16, 8)); + specindex = AllocateSpecToStation(statspec, st, flags & DC_EXEC); + if (specindex == -1) return CMD_ERROR; + if (flags & DC_EXEC) { TileIndexDiff tile_delta; byte *layout_ptr; - const StationSpec *statspec; Track track; // Now really clear the land below the station @@ -1050,7 +1070,6 @@ int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint3 tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); track = (axis == AXIS_X ? TRACK_X : TRACK_Y); - statspec = (p2 & 0x10) != 0 ? GetCustomStation(STAT_CLASS_DFLT, p2 >> 8) : NULL; layout_ptr = alloca(numtracks * plat_len); GetStationLayout(layout_ptr, numtracks, plat_len, statspec); @@ -1060,8 +1079,7 @@ int32 CmdBuildRailroadStation(TileIndex tile_org, uint32 flags, uint32 p1, uint3 do { MakeRailStation(tile, st->owner, st->index, axis, *layout_ptr++, GB(p2, 0, 4)); - - if (HASBIT(p2, 4)) SetCustomStationSpecIndex(tile, GB(p2, 8, 8)); + SetCustomStationSpecIndex(tile, specindex); tile += tile_delta; } while (--w); @@ -1158,9 +1176,13 @@ int32 CmdRemoveFromRailroadStation(TileIndex tile, uint32 flags, uint32 p1, uint // if we reached here, it means we can actually delete it. do that. if (flags & DC_EXEC) { + uint specindex = GetCustomStationSpecIndex(tile); Track track = GetRailStationTrack(tile); DoClearSquare(tile); SetSignalsOnBothDir(tile, track); + + DeallocateSpecFromStation(st, specindex); + // now we need to make the "spanned" area of the railway station smaller if we deleted something at the edges. // we also need to adjust train_tile. MakeRailwayStationAreaSmaller(st); @@ -1252,6 +1274,10 @@ static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags) st->train_tile = 0; st->facilities &= ~FACIL_TRAIN; + free(st->speclist); + st->num_specs = 0; + st->speclist = NULL; + UpdateStationVirtCoordDirty(st); DeleteStationIfEmpty(st); } @@ -1936,12 +1962,12 @@ static void DrawTile_Station(TileInfo *ti) if (IsCustomStationSpecIndex(ti->tile)) { // look for customization - const StationSpec *statspec = GetCustomStation(STAT_CLASS_DFLT, GetCustomStationSpecIndex(ti->tile)); + const Station *st = GetStationByTile(ti->tile); + const StationSpec *statspec = st->speclist[GetCustomStationSpecIndex(ti->tile)].spec; //debug("Cust-o-mized %p", statspec); if (statspec != NULL) { - const Station* st = GetStationByTile(ti->tile); uint tile = GetStationGfx(ti->tile); relocation = GetCustomStationRelocation(statspec, st, 0);