# HG changeset patch # User peter1138 # Date 1131754774 0 # Node ID 66b3d632dcd29fba70c779fae40fedaa732cfa64 # Parent 47d7768c6dcab269c975d60808c6abd66d9583b5 (svn r3167) - NewGRF: Start moving custom station code to separate files. Rewrite handling of station classes. Allow for more than 8 station tile layouts. Start of code to unload custom stations. diff -r 47d7768c6dca -r 66b3d632dcd2 Makefile --- a/Makefile Fri Nov 11 20:34:16 2005 +0000 +++ b/Makefile Sat Nov 12 00:19:34 2005 +0000 @@ -659,6 +659,7 @@ C_SOURCES += spritecache.c C_SOURCES += station_cmd.c C_SOURCES += station_gui.c +C_SOURCES += station_newgrf.c C_SOURCES += string.c C_SOURCES += strings.c C_SOURCES += subsidy_gui.c diff -r 47d7768c6dca -r 66b3d632dcd2 newgrf.c --- a/newgrf.c Fri Nov 11 20:34:16 2005 +0000 +++ b/newgrf.c Sat Nov 12 00:19:34 2005 +0000 @@ -800,22 +800,7 @@ classid |= *(buf++) << 8; classid |= *(buf++); - switch (classid) { - case 'DFLT': - stat->sclass = STAT_CLASS_DFLT; - break; - case 'WAYP': - stat->sclass = STAT_CLASS_WAYP; - break; - default: - /* TODO: No support for custom - * classes for now, so stuff - * everything to the single - * default one. --pasky */ - stat->sclass = STAT_CLASS_DFLT; - //stat->sclass = STAT_CLASS_CUSTOM; - break; - } + stat->sclass = AllocateStationClass(classid); } break; } @@ -825,24 +810,28 @@ StationSpec *stat = &_cur_grffile->stations[stid + i]; int t; - stat->tiles = grf_load_byte(&buf); + stat->tiles = grf_load_extended(&buf); + stat->renderdata = calloc(stat->tiles, sizeof(*stat->renderdata)); for (t = 0; t < stat->tiles; t++) { DrawTileSprites *dts = &stat->renderdata[t]; int seq_count = 0; - - if (t >= 8) { - grfmsg(GMS_WARN, "StationChangeInfo: Sprite %d>=8, skipping.", t); - grf_load_dword(&buf); // at least something - continue; - } - - dts->ground_sprite = grf_load_dword(&buf); - if (!dts->ground_sprite) { + PalSpriteID ground_sprite; + + ground_sprite = grf_load_dword(&buf); + if (ground_sprite == 0) { static const DrawTileSeqStruct empty = {0x80, 0, 0, 0, 0, 0, 0}; dts->seq = ∅ continue; } + if (HASBIT(ground_sprite, 31)) { + // Bit 31 indicates that we should use a custom sprite. + dts->ground_sprite = GB(ground_sprite, 0, 15) - 0x42D; + dts->ground_sprite += _cur_grffile->first_spriteset; + } else { + dts->ground_sprite = ground_sprite; + } + dts->seq = NULL; while (buf < *bufp + len) { DrawTileSeqStruct *dtss; @@ -873,6 +862,7 @@ int t; stat->tiles = srcstat->tiles; + stat->renderdata = calloc(stat->tiles, sizeof(*stat->renderdata)); for (t = 0; t < stat->tiles; t++) { DrawTileSprites *dts = &stat->renderdata[t]; const DrawTileSprites *sdts = &srcstat->renderdata[t]; @@ -1548,6 +1538,9 @@ loaded_ptr = buf; loading_ptr = buf + 2 * numloaded; + if (_cur_grffile->first_spriteset == 0) + _cur_grffile->first_spriteset = _cur_grffile->spriteset_start; + if (numloaded > 16) { grfmsg(GMS_WARN, "NewSpriteGroup: More than 16 sprites in group %x, skipping the rest.", setid); numloaded = 16; @@ -1688,8 +1681,8 @@ stat->spritegroup[0] = _cur_grffile->spritegroups[groupid]; stat->spritegroup[0]->ref_count++; stat->grfid = _cur_grffile->grfid; - SetCustomStation(stid, stat); - stat->sclass = STAT_CLASS_NONE; + stat->localidx = stid; + SetCustomStation(stat); } } return; @@ -2396,6 +2389,28 @@ file->spritegroups_count = 0; } +static void ResetCustomStations(void) +{ + GRFFile *file; + int i; + CargoID c; + + for (file = _first_grffile; file != NULL; file = file->next) { + for (i = 0; i < 256; i++) { + if (file->stations[i].grfid != file->grfid) + continue; + + // TODO: Release renderdata, platforms and layouts + + // Release this stations sprite groups. + for (c = 0; c < NUM_GLOBAL_CID; c++) { + if (file->stations[i].spritegroup[c] != NULL) + UnloadSpriteGroup(&file->stations[i].spritegroup[c]); + } + } + } +} + /** * Reset all NewGRF loaded data * TODO @@ -2433,6 +2448,10 @@ // Reset price base data ResetPriceBaseMultipliers(); + + // Reset station classes + ResetStationClasses(); + ResetCustomStations(); } static void InitNewGRFFile(const char* filename, int sprite_offset) diff -r 47d7768c6dca -r 66b3d632dcd2 newgrf.h --- a/newgrf.h Fri Nov 11 20:34:16 2005 +0000 +++ b/newgrf.h Sat Nov 12 00:19:34 2005 +0000 @@ -12,6 +12,7 @@ uint32 grfid; uint16 flags; uint16 sprite_offset; + SpriteID first_spriteset; ///< Holds the first spriteset's sprite offset. GRFFile *next; /* A sprite group contains all sprites of a given vehicle (or multiple diff -r 47d7768c6dca -r 66b3d632dcd2 rail_gui.c --- a/rail_gui.c Fri Nov 11 20:34:16 2005 +0000 +++ b/rail_gui.c Sat Nov 12 00:19:34 2005 +0000 @@ -127,7 +127,7 @@ static void PlaceRail_Waypoint(TileIndex tile) { if (!_remove_button_clicked) { - DoCommandP(tile, (_waypoint_count > 0) ? (0x100 + _cur_waypoint_type) : 0, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT)); + DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT)); } else { DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT)); } @@ -257,9 +257,9 @@ static void BuildRailClick_Waypoint(Window *w) { - _waypoint_count = GetCustomStationsCount(STAT_CLASS_WAYP); + _waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP); if (HandlePlacePushButton(w, 11, SPR_CURSOR_WAYPOINT, 1, PlaceRail_Waypoint) - && _waypoint_count > 0) + && _waypoint_count > 1) ShowBuildWaypointPicker(); } @@ -829,14 +829,14 @@ { switch (e->event) { case WE_PAINT: { + int i; w->click_state = (1 << 3) << (_cur_waypoint_type - w->hscroll.pos); DrawWindowWidgets(w); - if(w->hscroll.pos + 0 <= _waypoint_count) DrawWaypointSprite(2, 25, w->hscroll.pos + 0, _cur_railtype); - if(w->hscroll.pos + 1 <= _waypoint_count) DrawWaypointSprite(70, 25, w->hscroll.pos + 1, _cur_railtype); - if(w->hscroll.pos + 2 <= _waypoint_count) DrawWaypointSprite(138, 25, w->hscroll.pos + 2, _cur_railtype); - if(w->hscroll.pos + 3 <= _waypoint_count) DrawWaypointSprite(206, 25, w->hscroll.pos + 3, _cur_railtype); - if(w->hscroll.pos + 4 <= _waypoint_count) DrawWaypointSprite(274, 25, w->hscroll.pos + 4, _cur_railtype); + for (i = 0; i < 5; i++) + if(w->hscroll.pos + i < _waypoint_count) + DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype); + break; } case WE_CLICK: { @@ -889,7 +889,7 @@ { Window *w = AllocateWindowDesc(&_build_waypoint_desc); w->hscroll.cap = 5; - w->hscroll.count = _waypoint_count + 1; + w->hscroll.count = _waypoint_count; } diff -r 47d7768c6dca -r 66b3d632dcd2 station.h --- a/station.h Fri Nov 11 20:34:16 2005 +0000 +++ b/station.h Sat Nov 12 00:19:34 2005 +0000 @@ -8,6 +8,7 @@ #include "sprite.h" #include "tile.h" #include "vehicle.h" +#include "station_newgrf.h" typedef struct GoodsEntry { uint16 waiting_acceptance; @@ -195,83 +196,10 @@ void StationPickerDrawSprite(int x, int y, RailType railtype, int image); - -/* Station layout for given dimensions - it is a two-dimensional array - * where index is computed as (x * platforms) + platform. */ -typedef byte *StationLayout; - -typedef enum StationClass { - STAT_CLASS_NONE, // unused station slot or so - STAT_CLASS_DFLT, // default station class - STAT_CLASS_WAYP, // waypoints - - /* TODO: When we actually support custom classes, they are - * going to be allocated dynamically (with some classid->sclass - * mapping, there's a TTDPatch limit on 16 custom classes in - * the whole game at the same time) with base at - * STAT_CLASS_CUSTOM. --pasky */ - STAT_CLASS_CUSTOM, // some custom class -} StationClass; - -typedef struct StationSpec { - uint32 grfid; - int localidx; // per-GRFFile station index + 1; SetCustomStation() takes care of this - - StationClass sclass; - - /* Bitmask of platform numbers/lengths available for the station. Bits - * 0..6 correspond to 1..7, while bit 7 corresponds to >7 platforms or - * lenght. */ - byte allowed_platforms; - byte allowed_lengths; - - /* Custom sprites */ - byte tiles; - /* 00 = plain platform - * 02 = platform with building - * 04 = platform with roof, left side - * 06 = platform with roof, right side - * - * These numbers are used for stations in NE-SW direction, or these - * numbers plus one for stations in the NW-SE direction. */ - DrawTileSprites renderdata[8]; - - /* Custom layouts */ - /* The layout array is organized like [lenghts][platforms], both being - * dynamic arrays, the field itself is length*platforms array containing - * indexes to @renderdata (only even numbers allowed) for the given - * station tile. */ - /* @lengths is length of the @platforms and @layouts arrays, that is - * number of maximal length for which the layout is defined (since - * arrays are indexed from 0, the length itself is at [length - 1]). */ - byte lengths; - /* @platforms is array of number of platforms defined for each length. - * Zero means no platforms defined. */ - byte *platforms; - /* @layout is @layouts-sized array of @platforms-sized arrays, - * containing pointers to length*platforms-sized arrays or NULL if - * default OTTD station layout should be used for stations of these - * dimensions. */ - StationLayout **layouts; - - /* Sprite offsets for renderdata->seq->image. spritegroup[0] is default - * whilst spritegroup[1] is "GC_PURCHASE". */ - SpriteGroup *spritegroup[2]; -} StationSpec; - -/* Here, @stid is local per-GRFFile station index. If spec->localidx is not yet - * set, it gets new dynamically allocated global index and spec->localidx is - * set to @stid, otherwise we take it as that we are replacing it and try to - * search for it first (that isn't much fast but we do it only very seldom). */ -void SetCustomStation(byte stid, StationSpec *spec); -/* Here, @stid is global station index (in continous range 0..GetCustomStationsCount()) - * (lookup is therefore very fast as we do this very frequently). */ -StationSpec *GetCustomStation(StationClass sclass, byte stid); /* Get sprite offset for a given custom station and station structure (may be * NULL if ctype is set - that means we are in a build dialog). The station * structure is used for variational sprite groups. */ uint32 GetCustomStationRelocation(const StationSpec *spec, const Station *st, byte ctype); -int GetCustomStationsCount(StationClass sclass); RoadStop * GetRoadStopByTile(TileIndex tile, RoadStopType type); static inline int GetRoadStopType(TileIndex tile) diff -r 47d7768c6dca -r 66b3d632dcd2 station_cmd.c --- a/station_cmd.c Fri Nov 11 20:34:16 2005 +0000 +++ b/station_cmd.c Sat Nov 12 00:19:34 2005 +0000 @@ -1199,60 +1199,6 @@ return len - 1; } - -/* TODO: Custom classes! */ -/* Indexed by class, just STAT_CLASS_DFLT and STAT_CLASS_WAYP supported. */ -static int _statspec_highest_id[2] = {-1, -1}; -static StationSpec _station_spec[2][256]; - -void SetCustomStation(byte local_stid, StationSpec *spec) -{ - StationClass sclass; - int stid = -1; - - assert(spec->sclass == STAT_CLASS_DFLT || spec->sclass == STAT_CLASS_WAYP); - sclass = spec->sclass - 1; - - if (spec->localidx != 0) { - /* Already allocated, try to resolve to global stid */ - int i; - - for (i = 0; i <= _statspec_highest_id[sclass]; i++) { - if (_station_spec[sclass][i].grfid == spec->grfid && - _station_spec[sclass][i].localidx == local_stid + 1) { - stid = i; - /* FIXME: Release original SpriteGroup to - * prevent leaks. But first we need to - * refcount the SpriteGroup. --pasky */ - break; - } - } - } - - if (stid == -1) { - /* Allocate new one. */ - if (_statspec_highest_id[sclass] >= 255) { - error("Too many custom stations allocated."); - return; - } - stid = ++_statspec_highest_id[sclass]; - spec->localidx = local_stid + 1; - } - - //debug("Registering station #%d of class %d", stid, sclass); - memcpy(&_station_spec[sclass][stid], spec, sizeof(*spec)); -} - -StationSpec *GetCustomStation(StationClass sclass, byte stid) -{ - assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP); - sclass--; - //debug("Asking for station #%d of class %d", stid, sclass); - if (stid > _statspec_highest_id[sclass]) - return NULL; - return &_station_spec[sclass][stid]; -} - static const RealSpriteGroup *ResolveStationSpriteGroup(const SpriteGroup *spg, const Station *st) { switch (spg->type) { @@ -1351,14 +1297,6 @@ return SPR_RAIL_PLATFORM_Y_FRONT; } -int GetCustomStationsCount(StationClass sclass) -{ - assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP); - sclass--; - return _statspec_highest_id[sclass] + 1; -} - - static int32 RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags) { int w,h; diff -r 47d7768c6dca -r 66b3d632dcd2 station_newgrf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/station_newgrf.c Sat Nov 12 00:19:34 2005 +0000 @@ -0,0 +1,115 @@ +/* $Id$ */ + +/** @file station_newgrf.c Functions for dealing with station classes and custom stations. */ + +#include "stdafx.h" +#include "openttd.h" +#include "debug.h" +#include "sprite.h" +#include "station_newgrf.h" + +static StationClass station_classes[STAT_CLASS_MAX]; + +/** + * Reset station classes to their default state. + * This includes initialising the Default and Waypoint classes with an empty + * entry, for standard stations and waypoints. + */ +void ResetStationClasses(void) +{ + StationClassID i; + for (i = 0; i < STAT_CLASS_MAX; i++) { + station_classes[i].id = 0; + + free(station_classes[i].name); + station_classes[i].name = NULL; + + station_classes[i].stations = 0; + + free(station_classes[i].spec); + station_classes[i].spec = NULL; + } + + // Set up initial data + station_classes[0].id = 'DFLT'; + station_classes[0].name = strdup("Default"); + station_classes[0].stations = 1; + station_classes[0].spec = malloc(sizeof(*station_classes[0].spec)); + station_classes[0].spec[0] = NULL; + + station_classes[1].id = 'WAYP'; + station_classes[1].name = strdup("Waypoints"); + station_classes[1].stations = 1; + station_classes[1].spec = malloc(sizeof(*station_classes[1].spec)); + station_classes[1].spec[0] = NULL; +} + +/** + * Allocate a station class for the given class id. + * @param classid A 32 bit value identifying the class. + * @return Index into station_classes of allocated class. + */ +StationClassID AllocateStationClass(uint32 class) +{ + StationClassID i; + + for (i = 0; i < STAT_CLASS_MAX; i++) { + if (station_classes[i].id == class) { + // ClassID is already allocated, so reuse it. + return i; + } else if (station_classes[i].id == 0) { + // This class is empty, so allocate it to the ClassID. + station_classes[i].id = class; + return i; + } + } + + DEBUG(grf, 2)("StationClassAllocate: Already allocated %d classes, using default.", STAT_CLASS_MAX); + return STAT_CLASS_DFLT; +} + +/** + * Return the number of stations for the given station class. + * @param sclass Index of the station class. + * @return Number of stations in the class. + */ +uint GetNumCustomStations(StationClassID sclass) +{ + assert(sclass < STAT_CLASS_MAX); + return station_classes[sclass].stations; +} + +/** + * Tie a station spec to its station class. + * @param spec The station spec. + */ +void SetCustomStation(StationSpec *spec) +{ + StationClass *station_class; + int i; + + assert(spec->sclass < STAT_CLASS_MAX); + station_class = &station_classes[spec->sclass]; + + i = station_class->stations++; + station_class->spec = realloc(station_class->spec, station_class->stations * sizeof(*station_class->spec)); + + station_class->spec[i] = spec; +} + +/** + * Retrieve a station spec from a class. + * @param sclass Index of the station class. + * @param station The station index with the class. + * @return The station spec. + */ +const StationSpec *GetCustomStation(StationClassID sclass, uint station) +{ + assert(sclass < STAT_CLASS_MAX); + if (station < station_classes[sclass].stations) + return station_classes[sclass].spec[station]; + + // If the custom station isn't defined any more, then the GRF file + // probably was not loaded. + return NULL; +} diff -r 47d7768c6dca -r 66b3d632dcd2 station_newgrf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/station_newgrf.h Sat Nov 12 00:19:34 2005 +0000 @@ -0,0 +1,77 @@ +/* $Id$ */ + +/** @file station_newgrf.h Header file for NewGRF stations */ + +#ifndef STATION_NEWGRF_H +#define STATION_NEWGRF_H + +#include "engine.h" + +typedef enum { + STAT_CLASS_DFLT, ///< Default station class. + STAT_CLASS_WAYP, ///< Waypoint class. + STAT_CLASS_MAX = 16, ///< Maximum number of classes. +} StationClassID; + +/* Station layout for given dimensions - it is a two-dimensional array + * where index is computed as (x * platforms) + platform. */ +typedef byte *StationLayout; + +typedef struct stationspec { + uint32 grfid; ///< ID of GRF file station belongs to. + int localidx; ///< Index within GRF file of station. + + StationClassID sclass; ///< The class to which this spec belongs. + + /** + * Bitmask of number of platforms available for the station. + * 0..6 correpsond to 1..7, while bit 7 corresponds to >7 platforms. + */ + byte allowed_platforms; + /** + * Bitmask of platform lengths available for the station. + * 0..6 correpsond to 1..7, while bit 7 corresponds to >7 tiles long. + */ + byte allowed_lengths; + + /** Number of tile layouts. + * A minimum of 8 is required is required for stations. + * 0-1 = plain platform + * 2-3 = platform with building + * 4-5 = platform with roof, left side + * 6-7 = platform with roof, right side + */ + int tiles; + DrawTileSprites *renderdata; ///< Array of tile layouts. + + byte lengths; + byte *platforms; + StationLayout **layouts; + + /** + * NUM_GLOBAL_CID sprite groups. + * Used for obtaining the sprite offset of custom sprites, and for + * evaluating callbacks. + */ + SpriteGroup *spritegroup[NUM_GLOBAL_CID]; +} StationSpec; + +/** + * Struct containing information relating to station classes. + */ +typedef struct stationclass { + uint32 id; ///< ID of this class, e.g. 'DFLT', 'WAYP', etc. + char *name; ///< Name of this class. + uint stations; ///< Number of stations in this class. + StationSpec **spec; ///< Array of station specifications. +} StationClass; + +void ResetStationClasses(void); +StationClassID AllocateStationClass(uint32 class); +void SetStationClassName(StationClassID sclass, const char *name); +uint GetNumCustomStations(StationClassID sclass); + +void SetCustomStation(StationSpec *spec); +const StationSpec *GetCustomStation(StationClassID sclass, uint station); + +#endif /* STATION_NEWGRF_H */ diff -r 47d7768c6dca -r 66b3d632dcd2 waypoint.c --- a/waypoint.c Fri Nov 11 20:34:16 2005 +0000 +++ b/waypoint.c Sat Nov 12 00:19:34 2005 +0000 @@ -154,7 +154,7 @@ /** Convert existing rail to waypoint. Eg build a waypoint station over * piece of rail * @param x,y coordinates where waypoint will be built - * @param p1 graphics for waypoint type, bit 8 signifies custom waypoint gfx (& 0x100) + * @param p1 graphics for waypoint type, 0 indicates standard graphics * @param p2 unused * * @todo When checking for the tile slope, @@ -170,7 +170,7 @@ SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION); /* if custom gfx are used, make sure it is within bounds */ - if (p1 > 0x100 + (uint)GetCustomStationsCount(STAT_CLASS_WAYP)) return CMD_ERROR; + if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR; if (!IsTileType(tile, MP_RAILWAY) || ((dir = 0, _m[tile].m5 != 1) && (dir = 1, _m[tile].m5 != 2))) return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK); @@ -200,10 +200,10 @@ if (flags & DC_EXEC) { bool reserved = PBSTileReserved(tile) != 0; ModifyTile(tile, MP_MAP5, RAIL_TYPE_WAYPOINT | dir); - if (--p1 & 0x100) { // waypoint type 0 uses default graphics + if (p1 > 0) { // waypoint type 0 uses default graphics // custom graphics _m[tile].m3 |= 16; - _m[tile].m4 = p1 & 0xff; + _m[tile].m4 = (p1 - 1) & 0xff; } if (reserved) { PBSReserveTrack(tile, dir); @@ -387,14 +387,14 @@ x += 33; y += 17; - /* draw default waypoint graphics of ID 0 */ - if (stat_id == 0) { + stat = GetCustomStation(STAT_CLASS_WAYP, stat_id); + if (stat == NULL) { + // stat is NULL for default waypoints and when waypoint graphics are + // not loaded. DrawDefaultWaypointSprite(x, y, railtype); return; } - stat = GetCustomStation(STAT_CLASS_WAYP, stat_id - 1); - assert(stat); relocation = GetCustomStationRelocation(stat, NULL, 1); // emulate station tile - open with building // add 1 to get the other direction diff -r 47d7768c6dca -r 66b3d632dcd2 waypoint.h --- a/waypoint.h Fri Nov 11 20:34:16 2005 +0000 +++ b/waypoint.h Sat Nov 12 00:19:34 2005 +0000 @@ -16,6 +16,7 @@ ViewportSign sign; uint16 build_date; byte stat_id; + uint32 grfid; byte deleted; // this is a delete counter. when it reaches 0, the waypoint struct is deleted. };