Add NewGRF feature: Extra station name strings

These are used when all the default names have been used up,
instead of "Town Station #NNN".
pull/306/head
Jonathan G Rennison 3 years ago
parent d23720cc60
commit 4174fe727c

@ -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;
/**
@ -792,7 +813,8 @@ public:
TileArea docking_station; ///< Tile area the docking tiles cover
std::vector<TileIndex> docking_tiles; ///< Tile vector the docking tiles cover
IndustryType indtype; ///< Industry type to get the name from
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};

Loading…
Cancel
Save