Add NewGRF feature: Extra station name strings
These are used when all the default names have been used up, instead of "Town Station #NNN".
This commit is contained in:
@@ -250,6 +250,36 @@
|
||||
</p>
|
||||
<p>This is indicated by the feature name: <font face="monospace">action0_roadtype_extra_flags</font>, version 1</p>
|
||||
<br />
|
||||
<h3 id="a0bridges"><a href="https://newgrf-specs.tt-wiki.net/wiki/Action0/Global_Settings">Action 0 - Global Settings</a></h3>
|
||||
<h4 id="global_extra_station_names">Extra station names (mappable property: global_extra_station_names)</h4>
|
||||
<p>This adds extra station names for use when all the avilable station names for a given town have been used.<br />
|
||||
The string should have the same format and use the same ID range as
|
||||
<a href="https://newgrf-specs.tt-wiki.net/wiki/Action0/Industries#Default_name_for_nearby_station_.2824.29">industry - default name for nearby station</a>.<br />
|
||||
The Action 0 ID field is ignored. This property always adds a new station name string instead of overwriting an existing one.<br />
|
||||
The property length is 4 bytes. The format is:
|
||||
<table>
|
||||
<tr><th>Size</th><th>Field</th><th>Description</th></tr>
|
||||
<tr><td>W</td><td>String ID</td><td>String to use for the station name</td></tr>
|
||||
<tr><td>W</td><td>Flags</td><td>See table below</td></tr>
|
||||
</table>
|
||||
<br />
|
||||
Flags field:
|
||||
<table>
|
||||
<tr><th>Bit</th><th>Value</th><th>Meaning</th></tr>
|
||||
<tr><td>0</td><td>1</td><td>May be used for rail stations</td></tr>
|
||||
<tr><td>1</td><td>2</td><td>May be used for road stations</td></tr>
|
||||
<tr><td>2</td><td>4</td><td>May be used for airport stations</td></tr>
|
||||
<tr><td>3</td><td>8</td><td>May be used for oil rig stations</td></tr>
|
||||
<tr><td>4</td><td>10</td><td>May be used for dock stations</td></tr>
|
||||
<tr><td>5</td><td>20</td><td>May be used for heliport stations</td></tr>
|
||||
<tr><td>8</td><td>100</td><td>May only be used for stations near the town centre</td></tr>
|
||||
<tr><td>9</td><td>200</td><td>May not be used for stations near the town centre</td></tr>
|
||||
<tr><td>10</td><td>400</td><td>May only be used for stations near water</td></tr>
|
||||
<tr><td>11</td><td>800</td><td>May not be used for stations near water</td></tr>
|
||||
</table>
|
||||
</p>
|
||||
<p>This is indicated by the feature name: <font face="monospace">action0_global_extra_station_names</font>, version 1</p>
|
||||
<br />
|
||||
<h3 id="varaction2_station"><a href="https://newgrf-specs.tt-wiki.net/wiki/VariationalAction2/Stations">Variational Action 2 - Stations</a></h3>
|
||||
<h4 id="varaction2_station_var42">Track type in purchase list (42)</h4>
|
||||
<p>This is indicated by the feature name: <font face="monospace">varaction2_station_var42</font>, version 1</p>
|
||||
|
@@ -214,6 +214,9 @@ static void LoadSpriteTables()
|
||||
/* Initialize the unicode to sprite mapping table */
|
||||
InitializeUnicodeGlyphMap();
|
||||
|
||||
extern uint _extra_station_names_used;
|
||||
_extra_station_names_used = 0;
|
||||
|
||||
/*
|
||||
* Load the base and extra NewGRF with OTTD required graphics as first NewGRF.
|
||||
* However, we do not want it to show up in the list of used NewGRFs,
|
||||
|
@@ -94,6 +94,7 @@ void InitializeGame(uint size_x, uint size_y, bool reset_date, bool reset_settin
|
||||
_game_load_date_fract = 0;
|
||||
_game_load_tick_skip_counter = 0;
|
||||
_game_load_time = 0;
|
||||
_extra_station_names_used = 0;
|
||||
_loadgame_DBGL_data.clear();
|
||||
if (reset_settings) MakeNewgameSettingsLive();
|
||||
|
||||
|
@@ -2886,6 +2886,19 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, co
|
||||
break;
|
||||
}
|
||||
|
||||
case A0RPI_GLOBALVAR_EXTRA_STATION_NAMES: {
|
||||
if (MappedPropertyLengthMismatch(buf, 4, mapping_entry)) break;
|
||||
uint16 str = buf->ReadWord();
|
||||
uint16 flags = buf->ReadWord();
|
||||
if (_extra_station_names_used < MAX_EXTRA_STATION_NAMES) {
|
||||
ExtraStationNameInfo &info = _extra_station_names[_extra_station_names_used];
|
||||
AddStringForMapping(str, &info.str);
|
||||
info.flags = flags;
|
||||
_extra_station_names_used++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = HandleAction0PropertyDefault(buf, prop);
|
||||
break;
|
||||
@@ -2954,6 +2967,10 @@ static ChangeInfoResult GlobalVarReserveInfo(uint gvid, int numinfo, int prop, c
|
||||
}
|
||||
break;
|
||||
|
||||
case A0RPI_GLOBALVAR_EXTRA_STATION_NAMES:
|
||||
buf->Skip(buf->ReadExtendedByte());
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = HandleAction0PropertyDefault(buf, prop);
|
||||
break;
|
||||
@@ -8380,6 +8397,7 @@ static const GRFFeatureInfo _grf_feature_list[] = {
|
||||
GRFFeatureInfo("action0_railtype_restricted_signals", 1),
|
||||
GRFFeatureInfo("action0_railtype_disable_realistic_braking", 1),
|
||||
GRFFeatureInfo("action0_roadtype_extra_flags", 1),
|
||||
GRFFeatureInfo("action0_global_extra_station_names", 1),
|
||||
GRFFeatureInfo(),
|
||||
};
|
||||
|
||||
@@ -8501,6 +8519,7 @@ static const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
|
||||
GRFPropertyMapDefinition(GSF_RAILTYPES, A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING, "railtype_disable_realistic_braking"),
|
||||
GRFPropertyMapDefinition(GSF_ROADTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"),
|
||||
GRFPropertyMapDefinition(GSF_TRAMTYPES, A0RPI_ROADTYPE_EXTRA_FLAGS, "roadtype_extra_flags"),
|
||||
GRFPropertyMapDefinition(GSF_GLOBALVAR, A0RPI_GLOBALVAR_EXTRA_STATION_NAMES, "global_extra_station_names"),
|
||||
GRFPropertyMapDefinition(),
|
||||
};
|
||||
|
||||
|
@@ -119,6 +119,7 @@ enum Action0RemapPropertyIds {
|
||||
A0RPI_RAILTYPE_ENABLE_RESTRICTED_SIGNALS,
|
||||
A0RPI_RAILTYPE_DISABLE_REALISTIC_BRAKING,
|
||||
A0RPI_ROADTYPE_EXTRA_FLAGS,
|
||||
A0RPI_GLOBALVAR_EXTRA_STATION_NAMES,
|
||||
};
|
||||
|
||||
enum GRFPropertyMapFallbackMode {
|
||||
|
@@ -464,6 +464,7 @@ static void ShutdownGame()
|
||||
_game_load_date_fract = 0;
|
||||
_game_load_tick_skip_counter = 0;
|
||||
_game_load_time = 0;
|
||||
_extra_station_names_used = 0;
|
||||
_loadgame_DBGL_data.clear();
|
||||
_loadgame_DBGC_data.clear();
|
||||
}
|
||||
|
@@ -153,6 +153,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_CUSTOM_TOWN_ZONE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "custom_town_zone", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_STATION_CARGO_HISTORY, XSCF_NULL, 1, 1, "station_cargo_history", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_TRAIN_SPEED_ADAPTATION, XSCF_NULL, 1, 1, "train_speed_adaptation", nullptr, nullptr, "TSAS" },
|
||||
{ XSLFI_EXTRA_STATION_NAMES, XSCF_NULL, 1, 1, "extra_station_names", nullptr, nullptr, nullptr },
|
||||
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
|
||||
};
|
||||
|
||||
|
@@ -107,6 +107,7 @@ enum SlXvFeatureIndex {
|
||||
XSLFI_CUSTOM_TOWN_ZONE, ///< Custom town zones
|
||||
XSLFI_STATION_CARGO_HISTORY, ///< Station waiting cargo history
|
||||
XSLFI_TRAIN_SPEED_ADAPTATION, ///< Train speed adaptation
|
||||
XSLFI_EXTRA_STATION_NAMES, ///< Extra station names
|
||||
|
||||
XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
|
||||
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
|
||||
|
@@ -449,6 +449,7 @@ static const SaveLoad _station_desc[] = {
|
||||
SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
|
||||
|
||||
SLE_VAR(Station, indtype, SLE_UINT8),
|
||||
SLE_CONDVAR_X(Station, extra_name_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_EXTRA_STATION_NAMES)),
|
||||
|
||||
SLE_VAR(Station, time_since_load, SLE_UINT8),
|
||||
SLE_VAR(Station, time_since_unload, SLE_UINT8),
|
||||
|
@@ -38,6 +38,9 @@
|
||||
StationPool _station_pool("Station");
|
||||
INSTANTIATE_POOL_METHODS(Station)
|
||||
|
||||
std::array<ExtraStationNameInfo, MAX_EXTRA_STATION_NAMES> _extra_station_names;
|
||||
uint _extra_station_names_used;
|
||||
|
||||
|
||||
StationKdtree _station_kdtree(Kdtree_StationXYFunc);
|
||||
|
||||
@@ -76,6 +79,7 @@ Station::Station(TileIndex tile) :
|
||||
truck_station(INVALID_TILE, 0, 0),
|
||||
ship_station(INVALID_TILE, 0, 0),
|
||||
indtype(IT_INVALID),
|
||||
extra_name_index(UINT16_MAX),
|
||||
time_since_load(255),
|
||||
time_since_unload(255),
|
||||
station_cargo_history_cargoes(0),
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include "3rdparty/cpp-btree/btree_set.h"
|
||||
#include "bitmap_type.h"
|
||||
#include "core/endian_type.hpp"
|
||||
#include "strings_type.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
@@ -33,6 +34,26 @@ extern StationPool _station_pool;
|
||||
|
||||
static const byte INITIAL_STATION_RATING = 175;
|
||||
|
||||
static const uint MAX_EXTRA_STATION_NAMES = 1024;
|
||||
|
||||
/** Extra station name string flags. */
|
||||
enum ExtraStationNameInfoFlags {
|
||||
/* Bits 0 - 5 used for StationNaming enum */
|
||||
ESNIF_CENTRAL = 8,
|
||||
ESNIF_NOT_CENTRAL = 9,
|
||||
ESNIF_NEAR_WATER = 10,
|
||||
ESNIF_NOT_NEAR_WATER = 11,
|
||||
};
|
||||
|
||||
/** Extra station name string */
|
||||
struct ExtraStationNameInfo {
|
||||
StringID str;
|
||||
uint16 flags;
|
||||
};
|
||||
|
||||
extern std::array<ExtraStationNameInfo, MAX_EXTRA_STATION_NAMES> _extra_station_names;
|
||||
extern uint _extra_station_names_used;
|
||||
|
||||
class FlowStatMap;
|
||||
|
||||
/**
|
||||
@@ -793,6 +814,7 @@ public:
|
||||
std::vector<TileIndex> docking_tiles; ///< Tile vector the docking tiles cover
|
||||
|
||||
IndustryType indtype; ///< Industry type to get the name from
|
||||
uint16 extra_name_index; ///< Extra name index in use (or UINT16_MAX)
|
||||
|
||||
BitmapTileArea catchment_tiles; ///< NOSAVE: Set of individual tiles covered by catchment area
|
||||
uint station_tiles; ///< NOSAVE: Count of station tiles owned by this station
|
||||
|
@@ -63,6 +63,8 @@
|
||||
|
||||
#include "3rdparty/cpp-btree/btree_set.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/**
|
||||
@@ -249,6 +251,8 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
|
||||
bool indtypes[NUM_INDUSTRYTYPES];
|
||||
memset(indtypes, 0, sizeof(indtypes));
|
||||
|
||||
std::bitset<MAX_EXTRA_STATION_NAMES> extra_names;
|
||||
|
||||
for (const Station *s : Station::Iterate()) {
|
||||
if (s != st && s->town == t) {
|
||||
if (s->indtype != IT_INVALID) {
|
||||
@@ -263,6 +267,9 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (s->extra_name_index < MAX_EXTRA_STATION_NAMES) {
|
||||
extra_names.set(s->extra_name_index);
|
||||
}
|
||||
uint str = M(s->string_id);
|
||||
if (str <= 0x20) {
|
||||
if (str == M(STR_SV_STNAME_FOREST)) {
|
||||
@@ -301,7 +308,8 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
|
||||
}
|
||||
|
||||
/* check close enough to town to get central as name? */
|
||||
if (DistanceMax(tile, t->xy) < 8) {
|
||||
const bool is_central = DistanceMax(tile, t->xy) < 8;
|
||||
if (is_central) {
|
||||
if (HasBit(free_names, M(STR_SV_STNAME))) return STR_SV_STNAME;
|
||||
|
||||
if (HasBit(free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL;
|
||||
@@ -344,7 +352,32 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n
|
||||
(TileY(tile) < TileY(t->xy)) * 2];
|
||||
|
||||
tmp = free_names & ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 6) | (1 << 7) | (1 << 12) | (1 << 26) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 30));
|
||||
return (tmp == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(tmp));
|
||||
if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp);
|
||||
|
||||
if (_extra_station_names_used > 0) {
|
||||
const bool near_water = CountMapSquareAround(tile, CMSAWater) >= 5;
|
||||
std::vector<uint16> candidates;
|
||||
for (uint i = 0; i < _extra_station_names_used; i++) {
|
||||
const ExtraStationNameInfo &info = _extra_station_names[i];
|
||||
if (extra_names[i]) continue;
|
||||
if (!HasBit(info.flags, name_class)) continue;
|
||||
if (HasBit(info.flags, ESNIF_CENTRAL) && !is_central) continue;
|
||||
if (HasBit(info.flags, ESNIF_NOT_CENTRAL) && is_central) continue;
|
||||
if (HasBit(info.flags, ESNIF_NEAR_WATER) && !near_water) continue;
|
||||
if (HasBit(info.flags, ESNIF_NOT_NEAR_WATER) && near_water) continue;
|
||||
candidates.push_back(i);
|
||||
}
|
||||
|
||||
if (!candidates.empty()) {
|
||||
SavedRandomSeeds saved_seeds;
|
||||
SaveRandomSeeds(&saved_seeds);
|
||||
st->extra_name_index = candidates[RandomRange((uint)candidates.size())];
|
||||
RestoreRandomSeeds(saved_seeds);
|
||||
return STR_SV_STNAME_FALLBACK;
|
||||
}
|
||||
}
|
||||
|
||||
return STR_SV_STNAME_FALLBACK;
|
||||
}
|
||||
#undef M
|
||||
|
||||
|
@@ -1777,6 +1777,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg
|
||||
str = indsp->station_name;
|
||||
}
|
||||
}
|
||||
if (st->extra_name_index != UINT16_MAX && st->extra_name_index < _extra_station_names_used) {
|
||||
str = _extra_station_names[st->extra_name_index].str;
|
||||
}
|
||||
|
||||
uint64 args_array[] = {STR_TOWN_NAME, st->town->index, st->index};
|
||||
WChar types_array[] = {0, SCC_TOWN_NAME, SCC_NUM};
|
||||
|
Reference in New Issue
Block a user