From 3a7abc2a35fba00e1e59d8ea7fbfb1442e9c20c9 Mon Sep 17 00:00:00 2001 From: tron Date: Wed, 17 Nov 2004 18:03:33 +0000 Subject: [PATCH] (svn r659) Support for cutomized TTDPatch-style new stations (no selector GUI yet) (pasky) --- docs/landscape.html | 2 + grfspecial.c | 72 ++++++++++++++++++++++--------- rail_gui.c | 11 ++++- station.h | 36 ++++++++++++++++ station_cmd.c | 101 ++++++++++++++++++++++++++++++-------------- 5 files changed, 169 insertions(+), 53 deletions(-) diff --git a/docs/landscape.html b/docs/landscape.html index 18ec83780d..f3b6198120 100644 --- a/docs/landscape.html +++ b/docs/landscape.html @@ -370,6 +370,8 @@ exit towards: 47 - NE, 48 - SE, 49 - SW, 4A
  • map_owner: owner of the station
  • map2: index into the array of stations
  • map3_lo bits 0..3: track type for railway stations, must be 0 for all the other stations
  • +
  • map3_lo bit 4 = use custom sprite (valid only railway stations FOR NOW)
  • +
  • map3_hi = custom station id
  • diff --git a/grfspecial.c b/grfspecial.c index 7141a67819..c83d7d6055 100644 --- a/grfspecial.c +++ b/grfspecial.c @@ -702,11 +702,6 @@ static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int /* This is one single huge TODO. It doesn't handle anything more than * just waypoints for now. */ - /* TODO: Differentiate between railtypes. This is missing in the new - * GRF file specification yet, though, so I need to agree on this with - * patchman yet. We just assume all the station stuff is for railtype 0 - * (railroad) for now. --pasky */ - //printf("sci %d %d [0x%02x]\n", stid, numinfo, prop); switch (prop) { case 0x08: @@ -729,7 +724,12 @@ static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int stat->sclass = STAT_CLASS_WAYP; break; default: - stat->sclass = STAT_CLASS_CUSTOM; + /* 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; } } @@ -826,38 +826,72 @@ static bool StationChangeInfo(uint stid, int numinfo, int prop, byte **bufp, int ret = 1; break; } - case 0x0c: + case 0x0C: { /* Platforms number */ - /* TODO */ FOR_EACH_OBJECT { - grf_load_byte(&buf); + struct StationSpec *stat = &_cur_grffile->stations[stid + i]; + + stat->allowed_platforms = ~grf_load_byte(&buf); } - ret = 1; break; } - case 0x0d: + case 0x0D: { /* Platforms length */ - /* TODO */ FOR_EACH_OBJECT { - grf_load_byte(&buf); + struct StationSpec *stat = &_cur_grffile->stations[stid + i]; + + stat->allowed_lengths = ~grf_load_byte(&buf); } - ret = 1; break; } case 0x0e: { /* Define custom layout */ - /* TODO */ FOR_EACH_OBJECT { + struct StationSpec *stat = &_cur_grffile->stations[stid + i]; + while (buf < *bufp + len) { byte length = grf_load_byte(&buf); byte number = grf_load_byte(&buf); - int k = length * number; + StationLayout layout; + int l, p; - if (!length && !number) break; - while (k--) grf_load_byte(&buf); + if (length == 0 || number == 0) break; + + //debug("l %d > %d ?", length, stat->lengths); + if (length > stat->lengths) { + stat->platforms = realloc(stat->platforms, length); + memset(stat->platforms + stat->lengths, 0, length - stat->lengths); + + stat->layouts = realloc(stat->layouts, length * sizeof(*stat->layouts)); + memset(stat->layouts + stat->lengths, 0, + (length - stat->lengths) * sizeof(*stat->layouts)); + + stat->lengths = length; + } + l = length - 1; // index is zero-based + + //debug("p %d > %d ?", number, stat->platforms[l]); + if (number > stat->platforms[l]) { + stat->layouts[l] = realloc(stat->layouts[l], + number * sizeof(**stat->layouts)); + // We expect NULL being 0 here, but C99 guarantees that. + memset(stat->layouts[l] + stat->platforms[l], 0, + (number - stat->platforms[l]) * sizeof(**stat->layouts)); + + stat->platforms[l] = number; + } + + layout = malloc(length * number); + for (l = 0; l < length; l++) + for (p = 0; p < number; p++) + layout[l * number + p] = grf_load_byte(&buf); + + l--; + p--; + free(stat->layouts[l][p]); + stat->layouts[l][p] = layout; } } - ret = 1; break; } case 0x0f: diff --git a/rail_gui.c b/rail_gui.c index b50b56c59f..dc0721d738 100644 --- a/rail_gui.c +++ b/rail_gui.c @@ -140,7 +140,9 @@ static void PlaceRail_Station(uint tile) VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED); VpSetPlaceSizingLimit(_patches.station_spread); } else { - DoCommandP(tile, _railstation.orientation | (_railstation.numtracks<<8) | (_railstation.platlength<<16),_cur_railtype, CcStation, + // TODO: Custom station selector GUI. Now we just try using first custom station + // (and fall back to normal stations if it isn't available). + DoCommandP(tile, _railstation.orientation | (_railstation.numtracks<<8) | (_railstation.platlength<<16),_cur_railtype|1<<4, CcStation, CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION)); } } @@ -822,6 +824,9 @@ void ShowBuildRailToolbar(int index, int button) if (w != NULL && button >= 0) _build_railroad_button_proc[button](w); } +/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks! + * --pasky */ + static void HandleStationPlacement(uint start, uint end) { uint sx = GET_TILE_X(start); @@ -836,7 +841,9 @@ static void HandleStationPlacement(uint start, uint end) h = ey - sy + 1; if (!_railstation.orientation) intswap(w,h); - DoCommandP(TILE_XY(sx,sy), _railstation.orientation | (w<<8) | (h<<16),_cur_railtype, CcStation, + // TODO: Custom station selector GUI. Now we just try using first custom station + // (and fall back to normal stations if it isn't available). + DoCommandP(TILE_XY(sx,sy), _railstation.orientation | (w<<8) | (h<<16),_cur_railtype|1<<4, CcStation, CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_AUTO | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION)); } diff --git a/station.h b/station.h index 5d1c7b5075..527148f3bf 100644 --- a/station.h +++ b/station.h @@ -93,6 +93,10 @@ void GetAcceptanceAroundTiles(uint *accepts, uint tile, int w, int h); uint GetStationPlatforms(Station *st, uint tile); +/* Station layout for given dimensions - it is a two-dimensional array + * where index is computed as (x * platforms) + platform. */ +typedef byte *StationLayout; + struct StationSpec { uint32 grfid; int localidx; // per-GRFFile station index + 1; SetCustomStation() takes care of this @@ -110,9 +114,41 @@ struct StationSpec { STAT_CLASS_CUSTOM, // some custom class } 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 "CID_PURCHASE". */ struct SpriteGroup spritegroup[2]; diff --git a/station_cmd.c b/station_cmd.c index e7828b563d..9e129defd6 100644 --- a/station_cmd.c +++ b/station_cmd.c @@ -700,8 +700,16 @@ static byte FORCEINLINE *CreateMulti(byte *layout, int n, byte b) } // stolen from TTDPatch -static void GetStationLayout(byte *layout, int numtracks, int plat_len) +static void GetStationLayout(byte *layout, int numtracks, int plat_len, struct StationSpec *spec) { + if (spec != NULL && spec->lengths >= plat_len && spec->platforms[plat_len - 1] >= numtracks + && spec->layouts[plat_len - 1][numtracks - 1]) { + /* Custom layout defined, follow it. */ + memcpy(layout, spec->layouts[plat_len - 1][numtracks - 1], + plat_len * numtracks); + return; + } + if (plat_len == 1) { CreateSingle(layout, numtracks); } else { @@ -720,7 +728,9 @@ static void GetStationLayout(byte *layout, int numtracks, int plat_len) * p1 & 1 - orientation * (p1 >> 8) & 0xFF - numtracks * (p1 >> 16) & 0xFF - platform length - * p2 - railtype + * p2 & 0xF - railtype + * p2 & 0x10 - set for custom station + * p2 >> 8 - custom station id */ int32 CmdBuildRailroadStation(int x_org, int y_org, uint32 flags, uint32 p1, uint32 p2) @@ -815,6 +825,7 @@ int32 CmdBuildRailroadStation(int x_org, int y_org, uint32 flags, uint32 p1, uin int tile_delta; byte *layout_ptr; uint station_index = st->index; + struct StationSpec *statspec; // Now really clear the land below the station // It should never return CMD_ERROR.. but you never know ;) @@ -833,8 +844,9 @@ int32 CmdBuildRailroadStation(int x_org, int y_org, uint32 flags, uint32 p1, uin tile_delta = direction ? TILE_XY(0,1) : TILE_XY(1,0); + statspec = (p2 & 0x10) != 0 ? GetCustomStation(STAT_CLASS_DFLT, p2 >> 8) : NULL; layout_ptr = alloca(numtracks * plat_len); - GetStationLayout(layout_ptr, numtracks, plat_len); + GetStationLayout(layout_ptr, numtracks, plat_len, statspec); do { int tile = tile_org; @@ -843,9 +855,10 @@ int32 CmdBuildRailroadStation(int x_org, int y_org, uint32 flags, uint32 p1, uin ModifyTile(tile, MP_SETTYPE(MP_STATION) | MP_MAPOWNER_CURRENT | - MP_MAP2 | MP_MAP5 | MP_MAP3LO | MP_MAP3HI_CLEAR, + MP_MAP2 | MP_MAP5 | MP_MAP3LO | MP_MAP3HI, station_index, /* map2 parameter */ - p2, /* map3lo parameter */ + p2 & 0xFF, /* map3lo parameter */ + p2 >> 8, /* map3hi parameter */ (*layout_ptr++) + direction /* map5 parameter */ ); @@ -958,24 +971,26 @@ uint GetStationPlatforms(Station *st, uint tile) } -/* TODO: Multiple classes! */ - -static int _waypoint_highest_id = -1; -static struct StationSpec _waypoint_data[256]; +/* TODO: Custom classes! */ +/* Indexed by class, just STAT_CLASS_DFLT and STAT_CLASS_WAYP supported. */ +static int _statspec_highest_id[2] = {-1, -1}; +static struct StationSpec _station_spec[2][256]; void SetCustomStation(byte local_stid, struct StationSpec *spec) { + enum StationClass sclass; int stid = -1; - assert(spec->sclass == STAT_CLASS_WAYP); + 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 <= _waypoint_highest_id; i++) { - if (_waypoint_data[i].grfid == spec->grfid - && _waypoint_data[i].localidx == local_stid + 1) { + 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 @@ -987,23 +1002,26 @@ void SetCustomStation(byte local_stid, struct StationSpec *spec) if (stid == -1) { /* Allocate new one. */ - if (_waypoint_highest_id >= 255) { + if (_statspec_highest_id[sclass] >= 255) { error("Too many custom stations allocated."); return; } - stid = ++_waypoint_highest_id; + stid = ++_statspec_highest_id[sclass]; spec->localidx = local_stid + 1; } - memcpy(&_waypoint_data[stid], spec, sizeof(*spec)); + //debug("Registering station #%d of class %d", stid, sclass); + memcpy(&_station_spec[sclass][stid], spec, sizeof(*spec)); } struct StationSpec *GetCustomStation(enum StationClass sclass, byte stid) { - assert(sclass == STAT_CLASS_WAYP); - if (stid > _waypoint_highest_id) + 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 &_waypoint_data[stid]; + return &_station_spec[sclass][stid]; } static struct RealSpriteGroup * @@ -1092,8 +1110,6 @@ uint32 GetCustomStationRelocation(struct StationSpec *spec, struct Station *stat { struct RealSpriteGroup *rsg; - assert(spec->sclass == STAT_CLASS_WAYP); - rsg = ResolveStationSpriteGroup(&spec->spritegroup[ctype], stat); if (rsg->sprites_per_set != 0) { @@ -1114,8 +1130,9 @@ uint32 GetCustomStationRelocation(struct StationSpec *spec, struct Station *stat int GetCustomStationsCount(enum StationClass sclass) { - assert(sclass == STAT_CLASS_WAYP); - return _waypoint_highest_id + 1; + assert(sclass == STAT_CLASS_DFLT || sclass == STAT_CLASS_WAYP); + sclass--; + return _statspec_highest_id[sclass] + 1; } @@ -1879,17 +1896,16 @@ static int32 RemoveDock(Station *st, uint32 flags) #include "table/station_land.h" +extern uint16 _custom_sprites_base; static void DrawTile_Station(TileInfo *ti) { uint32 image_or_modificator; - uint32 base_img, image; + uint32 image; const DrawTileSeqStruct *dtss; - const DrawTileSprites *t; - - // station_land array has been increased from 82 elements to 114 - // but this is something else. If AI builds station with 114 it looks all weird - base_img = (_map3_lo[ti->tile] & 0xF) * 82; + const DrawTileSprites *t = NULL; + byte railtype = _map3_lo[ti->tile] & 0xF; + uint32 relocation = 0; { uint owner = _map_owner[ti->tile]; @@ -1902,15 +1918,36 @@ static void DrawTile_Station(TileInfo *ti) if (ti->tileh != 0 && (ti->map5 < 0x4C || ti->map5 > 0x51)) DrawFoundation(ti, ti->tileh); - t = &_station_display_datas[ti->map5]; + if (_map3_lo[ti->tile] & 0x10) { + // look for customization + struct StationSpec *statspec = GetCustomStation(STAT_CLASS_DFLT, _map3_hi[ti->tile]); + + //debug("Cust-o-mized %p", statspec); + + if (statspec != NULL) { + Station *st = DEREF_STATION(_map2[ti->tile]); + + relocation = GetCustomStationRelocation(statspec, st, 0); + //debug("Relocation %d", relocation); + t = &statspec->renderdata[ti->map5]; + } + } + + if (t == NULL) t = &_station_display_datas[ti->map5]; image = t->ground_sprite; if (image & 0x8000) image |= image_or_modificator; - DrawGroundSprite(image + base_img); + + // station_land array has been increased from 82 elements to 114 + // but this is something else. If AI builds station with 114 it looks all weird + image += railtype * ((image < _custom_sprites_base) ? TRACKTYPE_SPRITE_PITCH : 1); + DrawGroundSprite(image); foreach_draw_tile_seq(dtss, t->seq) { - image = dtss->image + base_img; + image = dtss->image + relocation; + // XXX: Do we want to do this for custom stations? --pasky + image += railtype * ((image < _custom_sprites_base) ? TRACKTYPE_SPRITE_PITCH : 1); if (_display_opt & DO_TRANS_BUILDINGS) { if (image&0x8000) image |= image_or_modificator; } else {