diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 0b8628f370..6cb0c46e5b 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2043,11 +2043,11 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte const uint8_t *layout = buf->ReadBytes(length * number); statspec->layouts[length - 1][number - 1].assign(layout, layout + length * number); - /* Validate tile values are only the permitted 00, 02, 04 and 06. */ + /* Ensure the first bit, axis, is zero. The rest of the value is validated during rendering, as we don't know the range yet. */ for (auto &tile : statspec->layouts[length - 1][number - 1]) { - if ((tile & 6) != tile) { + if ((tile & ~1U) != tile) { GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number); - tile &= 6; + tile &= ~1U; } } } @@ -2070,9 +2070,18 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte statspec->cargo_threshold = buf->ReadWord(); break; - case 0x11: // Pylon placement - statspec->pylons = buf->ReadByte(); + case 0x11: { // Pylon placement + uint8_t pylons = buf->ReadByte(); + if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8); + for (int j = 0; j < 8; ++j) { + if (HasBit(pylons, j)) { + statspec->tileflags[j] |= StationSpec::TileFlags::Pylons; + } else { + statspec->tileflags[j] &= ~StationSpec::TileFlags::Pylons; + } + } break; + } case 0x12: // Cargo types for random triggers if (_cur.grffile->grf_version >= 7) { @@ -2086,13 +2095,31 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte statspec->flags = buf->ReadByte(); break; - case 0x14: // Overhead wire placement - statspec->wires = buf->ReadByte(); + case 0x14: { // Overhead wire placement + uint8_t wires = buf->ReadByte(); + if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8); + for (int j = 0; j < 8; ++j) { + if (HasBit(wires, j)) { + statspec->tileflags[j] |= StationSpec::TileFlags::NoWires; + } else { + statspec->tileflags[j] &= ~StationSpec::TileFlags::NoWires; + } + } break; + } - case 0x15: // Blocked tiles - statspec->blocked = buf->ReadByte(); + case 0x15: { // Blocked tiles + uint8_t blocked = buf->ReadByte(); + if (statspec->tileflags.size() < 8) statspec->tileflags.resize(8); + for (int j = 0; j < 8; ++j) { + if (HasBit(blocked, j)) { + statspec->tileflags[j] |= StationSpec::TileFlags::Blocked; + } else { + statspec->tileflags[j] &= ~StationSpec::TileFlags::Blocked; + } + } break; + } case 0x16: // Animation info statspec->animation.frames = buf->ReadByte(); @@ -2144,6 +2171,13 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte AddStringForMapping(buf->ReadWord(), [statspec](StringID str) { StationClass::Get(statspec->cls_id)->name = str; }); break; + case 0x1E: { // Extended tile flags (replaces prop 11, 14 and 15) + uint16_t tiles = buf->ReadExtendedByte(); + auto flags = reinterpret_cast(buf->ReadBytes(tiles)); + statspec->tileflags.assign(flags, flags + tiles); + break; + } + default: ret = CIR_UNKNOWN; break; diff --git a/src/newgrf_callbacks.h b/src/newgrf_callbacks.h index 056461c006..017de166d3 100644 --- a/src/newgrf_callbacks.h +++ b/src/newgrf_callbacks.h @@ -38,8 +38,8 @@ enum CallbackID { /** Determine whether a newstation should be made available to build. */ CBID_STATION_AVAILABILITY = 0x13, // 8 bit callback - /** Choose a sprite layout to draw, instead of the standard 0-7 range. */ - CBID_STATION_SPRITE_LAYOUT = 0x14, + /** Choose a tile layout to draw, instead of the standard range. */ + CBID_STATION_DRAW_TILE_LAYOUT = 0x14, /** * Refit capacity, the passed vehicle needs to have its ->cargo_type set to @@ -93,7 +93,7 @@ enum CallbackID { CBID_VEHICLE_ADDITIONAL_TEXT = 0x23, /** Called when building a station to customize the tile layout */ - CBID_STATION_TILE_LAYOUT = 0x24, // 15 bit callback + CBID_STATION_BUILD_TILE_LAYOUT = 0x24, // 15 bit callback /** Called for periodically starting or stopping the animation. */ CBID_INDTILE_ANIM_START_STOP = 0x25, // 15 bit callback @@ -308,7 +308,7 @@ enum VehicleCallbackMask { */ enum StationCallbackMask { CBM_STATION_AVAIL = 0, ///< Availability of station in construction window - CBM_STATION_SPRITE_LAYOUT = 1, ///< Use callback to select a sprite layout to use + CBM_STATION_DRAW_TILE_LAYOUT = 1, ///< Use callback to select a tile layout to use when drawing. CBM_STATION_ANIMATION_NEXT_FRAME = 2, ///< Use a custom next frame callback CBM_STATION_ANIMATION_SPEED = 3, ///< Customize the animation speed of the station CBM_STATION_SLOPE_CHECK = 4, ///< Check slope of new station tiles diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index a6d0d77f8c..c2cb86fc3a 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -782,8 +782,8 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID const StationSpec *statspec = StationClass::Get(sclass)->GetSpec(station); if (statspec == nullptr) return false; - if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { - uint16_t callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, nullptr, INVALID_TILE); + if (HasBit(statspec->callback_mask, CBM_STATION_DRAW_TILE_LAYOUT)) { + uint16_t callback = GetStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, nullptr, INVALID_TILE); if (callback != CALLBACK_FAILED) tile = callback & ~1; } diff --git a/src/newgrf_station.h b/src/newgrf_station.h index f1c619153e..a2da7537ef 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -10,6 +10,7 @@ #ifndef NEWGRF_STATION_H #define NEWGRF_STATION_H +#include "core/enum_type.hpp" #include "newgrf_animation_type.h" #include "newgrf_callbacks.h" #include "newgrf_class.h" @@ -112,7 +113,7 @@ struct StationSpec { StationSpec() : cls_id(STAT_CLASS_DFLT), name(0), disallowed_platforms(0), disallowed_lengths(0), cargo_threshold(0), cargo_triggers(0), - callback_mask(0), flags(0), pylons(0), wires(0), blocked(0), + callback_mask(0), flags(0), animation({0, 0, 0, 0}) {} /** * Properties related the the grf file. @@ -157,9 +158,13 @@ struct StationSpec { uint8_t flags; ///< Bitmask of flags, bit 0: use different sprite set; bit 1: divide cargo about by station size - uint8_t pylons; ///< Bitmask of base tiles (0 - 7) which should contain elrail pylons - uint8_t wires; ///< Bitmask of base tiles (0 - 7) which should contain elrail wires - uint8_t blocked; ///< Bitmask of base tiles (0 - 7) which are blocked to trains + enum class TileFlags : uint8_t { + None = 0, + Pylons = 1U << 0, ///< Tile should contain catenary pylons. + NoWires = 1U << 1, ///< Tile should NOT contain catenary wires. + Blocked = 1U << 2, ///< Tile is blocked to vehicles. + }; + std::vector tileflags; ///< List of tile flags. AnimationInfo animation; @@ -173,6 +178,7 @@ struct StationSpec { */ std::vector>> layouts; }; +DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags); /** Class containing information relating to station classes. */ using StationClass = NewGRFClass; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 615e680723..c5802e73a0 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1294,6 +1294,14 @@ static CommandCost CalculateRailStationCost(TileArea tile_area, DoCommandFlag fl return cost; } +StationSpec::TileFlags GetStationTileFlags(TileIndex tile, const StationSpec *statspec) +{ + const StationGfx gfx = GetStationGfx(tile); + /* Default stations do not draw pylons under roofs (gfx >= 4) */ + if (statspec == nullptr || gfx >= statspec->tileflags.size()) return gfx < 4 ? StationSpec::TileFlags::Pylons : StationSpec::TileFlags::None; + return statspec->tileflags[gfx]; +} + /** * Set rail station tile flags for the given tile. * @param tile Tile to set flags on. @@ -1301,15 +1309,10 @@ static CommandCost CalculateRailStationCost(TileArea tile_area, DoCommandFlag fl */ void SetRailStationTileFlags(TileIndex tile, const StationSpec *statspec) { - const StationGfx gfx = GetStationGfx(tile); - bool blocked = statspec != nullptr && HasBit(statspec->blocked, gfx); - /* Default stations do not draw pylons under roofs (gfx >= 4) */ - bool pylons = statspec != nullptr ? HasBit(statspec->pylons, gfx) : gfx < 4; - bool wires = statspec == nullptr || !HasBit(statspec->wires, gfx); - - SetStationTileBlocked(tile, blocked); - SetStationTileHavePylons(tile, pylons); - SetStationTileHaveWires(tile, wires); + auto flags = GetStationTileFlags(tile, statspec); + SetStationTileBlocked(tile, (flags & StationSpec::TileFlags::Blocked) == StationSpec::TileFlags::Blocked); + SetStationTileHavePylons(tile, (flags & StationSpec::TileFlags::Pylons) == StationSpec::TileFlags::Pylons); + SetStationTileHaveWires(tile, (flags & StationSpec::TileFlags::NoWires) != StationSpec::TileFlags::NoWires); } /** @@ -1461,12 +1464,12 @@ CommandCost CmdBuildRailStation(DoCommandFlag flags, TileIndex tile_org, RailTyp uint32_t platinfo = GetPlatformInfo(AXIS_X, GetStationGfx(tile), plat_len, numtracks_orig, plat_len - w, numtracks_orig - numtracks, false); /* As the station is not yet completely finished, the station does not yet exist. */ - uint16_t callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile); + uint16_t callback = GetStationCallback(CBID_STATION_BUILD_TILE_LAYOUT, platinfo, 0, statspec, nullptr, tile); if (callback != CALLBACK_FAILED) { - if (callback < 8) { + if (callback <= UINT8_MAX) { SetStationGfx(tile, (callback & ~1) + axis); } else { - ErrorUnknownCallbackResult(statspec->grf_prop.grffile->grfid, CBID_STATION_TILE_LAYOUT, callback); + ErrorUnknownCallbackResult(statspec->grf_prop.grffile->grfid, CBID_STATION_BUILD_TILE_LAYOUT, callback); } } @@ -2885,7 +2888,9 @@ static CommandCost RemoveDock(TileIndex tile, DoCommandFlag flags) const DrawTileSprites *GetStationTileLayout(StationType st, uint8_t gfx) { - return &_station_display_datas[st][gfx]; + const auto layouts = _station_display_datas[st]; + if (gfx < layouts.size()) return layouts.data() + gfx; + return layouts.data(); } /** @@ -2978,8 +2983,8 @@ static void DrawTile_Station(TileInfo *ti) if (statspec != nullptr) { tile_layout = GetStationGfx(ti->tile); - if (HasBit(statspec->callback_mask, CBM_STATION_SPRITE_LAYOUT)) { - uint16_t callback = GetStationCallback(CBID_STATION_SPRITE_LAYOUT, 0, 0, statspec, st, ti->tile); + if (HasBit(statspec->callback_mask, CBM_STATION_DRAW_TILE_LAYOUT)) { + uint16_t callback = GetStationCallback(CBID_STATION_DRAW_TILE_LAYOUT, 0, 0, statspec, st, ti->tile); if (callback != CALLBACK_FAILED) tile_layout = (callback & ~1) + GetRailStationAxis(ti->tile); } diff --git a/src/station_type.h b/src/station_type.h index 4e6968ac31..26c5087764 100644 --- a/src/station_type.h +++ b/src/station_type.h @@ -28,7 +28,7 @@ static const StationID INVALID_STATION = 0xFFFF; typedef SmallStack StationIDStack; /** Station types */ -enum StationType { +enum StationType : uint8_t { STATION_RAIL, STATION_AIRPORT, STATION_TRUCK, @@ -37,6 +37,7 @@ enum StationType { STATION_DOCK, STATION_BUOY, STATION_WAYPOINT, + STATION_END, }; /** Types of RoadStops */ diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index 836cec3445..55a8df1db5 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -99,8 +99,8 @@ static const NIFeature _nif_vehicle = { #define NICS(cb_id, bit) NIC(cb_id, StationSpec, callback_mask, bit) static const NICallback _nic_stations[] = { NICS(CBID_STATION_AVAILABILITY, CBM_STATION_AVAIL), - NICS(CBID_STATION_SPRITE_LAYOUT, CBM_STATION_SPRITE_LAYOUT), - NICS(CBID_STATION_TILE_LAYOUT, CBM_NO_BIT), + NICS(CBID_STATION_DRAW_TILE_LAYOUT, CBM_STATION_DRAW_TILE_LAYOUT), + NICS(CBID_STATION_BUILD_TILE_LAYOUT,CBM_NO_BIT), NICS(CBID_STATION_ANIM_START_STOP, CBM_NO_BIT), NICS(CBID_STATION_ANIM_NEXT_FRAME, CBM_STATION_ANIMATION_NEXT_FRAME), NICS(CBID_STATION_ANIMATION_SPEED, CBM_STATION_ANIMATION_SPEED), diff --git a/src/table/station_land.h b/src/table/station_land.h index 6e3db1d0d0..d14dd32cd5 100644 --- a/src/table/station_land.h +++ b/src/table/station_land.h @@ -990,7 +990,7 @@ static const DrawTileSprites _station_display_datas_waypoint[] = { * As these are drawn/build like stations, they may use the same number of layouts. */ static_assert(lengthof(_station_display_datas_rail) == lengthof(_station_display_datas_waypoint)); -static const DrawTileSprites * const _station_display_datas[] = { +static const std::array, STATION_END> _station_display_datas = {{ _station_display_datas_rail, _station_display_datas_airport, _station_display_datas_truck, @@ -999,4 +999,4 @@ static const DrawTileSprites * const _station_display_datas[] = { _station_display_datas_dock, _station_display_datas_buoy, _station_display_datas_waypoint, -}; +}};