This commit is contained in:
Peter Nelson 2024-04-27 18:35:16 +09:00 committed by GitHub
commit 8fb9b219d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 85 additions and 39 deletions

View File

@ -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<const StationSpec::TileFlags *>(buf->ReadBytes(tiles));
statspec->tileflags.assign(flags, flags + tiles);
break;
}
default:
ret = CIR_UNKNOWN;
break;

View File

@ -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

View File

@ -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;
}

View File

@ -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> tileflags; ///< List of tile flags.
AnimationInfo animation;
@ -173,6 +178,7 @@ struct StationSpec {
*/
std::vector<std::vector<std::vector<uint8_t>>> layouts;
};
DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags);
/** Class containing information relating to station classes. */
using StationClass = NewGRFClass<StationSpec, StationClassID, STAT_CLASS_MAX>;

View File

@ -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);
}

View File

@ -28,7 +28,7 @@ static const StationID INVALID_STATION = 0xFFFF;
typedef SmallStack<StationID, StationID, INVALID_STATION, 8, 0xFFFD> 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 */

View File

@ -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),

View File

@ -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<std::span<const DrawTileSprites>, 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,
};
}};