From 4174fe727c476d8bef6cc36dd783d414234e1408 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Sat, 17 Jul 2021 20:54:10 +0100 Subject: [PATCH] Add NewGRF feature: Extra station name strings These are used when all the default names have been used up, instead of "Town Station #NNN". --- docs/newgrf-additions.html | 30 ++++++++++++++++++++++++++ src/gfxinit.cpp | 3 +++ src/misc.cpp | 1 + src/newgrf.cpp | 19 ++++++++++++++++ src/newgrf.h | 1 + src/openttd.cpp | 1 + src/saveload/extended_ver_sl.cpp | 1 + src/saveload/extended_ver_sl.h | 1 + src/saveload/station_sl.cpp | 1 + src/station.cpp | 4 ++++ src/station_base.h | 24 ++++++++++++++++++++- src/station_cmd.cpp | 37 ++++++++++++++++++++++++++++++-- src/strings.cpp | 3 +++ 13 files changed, 123 insertions(+), 3 deletions(-) diff --git a/docs/newgrf-additions.html b/docs/newgrf-additions.html index d235c3ac93..ea1b5612bd 100644 --- a/docs/newgrf-additions.html +++ b/docs/newgrf-additions.html @@ -250,6 +250,36 @@

This is indicated by the feature name: action0_roadtype_extra_flags, version 1


+

Action 0 - Global Settings

+

Extra station names (mappable property: global_extra_station_names)

+

This adds extra station names for use when all the avilable station names for a given town have been used.
+ The string should have the same format and use the same ID range as + industry - default name for nearby station.
+ The Action 0 ID field is ignored. This property always adds a new station name string instead of overwriting an existing one.
+ The property length is 4 bytes. The format is: + + + + +
SizeFieldDescription
WString IDString to use for the station name
WFlagsSee table below
+
+ Flags field: + + + + + + + + + + + + +
BitValueMeaning
01May be used for rail stations
12May be used for road stations
24May be used for airport stations
38May be used for oil rig stations
410May be used for dock stations
520May be used for heliport stations
8100May only be used for stations near the town centre
9200May not be used for stations near the town centre
10400May only be used for stations near water
11800May not be used for stations near water
+

+

This is indicated by the feature name: action0_global_extra_station_names, version 1

+

Variational Action 2 - Stations

Track type in purchase list (42)

This is indicated by the feature name: varaction2_station_var42, version 1

diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 1c4ee94f8b..92c3c1051e 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -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, diff --git a/src/misc.cpp b/src/misc.cpp index 279df3f8cf..249eaaad9e 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -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(); diff --git a/src/newgrf.cpp b/src/newgrf.cpp index cea70af355..43d14584a3 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -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(), }; diff --git a/src/newgrf.h b/src/newgrf.h index d19ec636b8..1bf44d8c54 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -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 { diff --git a/src/openttd.cpp b/src/openttd.cpp index 8495833a19..4ea16b2907 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -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(); } diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index ddf2fa57cd..136b12606c 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -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 }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 54921e8dd4..b22e064202 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -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 diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index 0572d55ba0..223fd5e880 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -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), diff --git a/src/station.cpp b/src/station.cpp index effc2c898d..419098254c 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -38,6 +38,9 @@ StationPool _station_pool("Station"); INSTANTIATE_POOL_METHODS(Station) +std::array _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), diff --git a/src/station_base.h b/src/station_base.h index c11f1fa24c..5a61edd621 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -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 #include #include @@ -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 _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 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 diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 7c45135f35..ac697c66ae 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -63,6 +63,8 @@ #include "3rdparty/cpp-btree/btree_set.h" +#include + #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 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 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 diff --git a/src/strings.cpp b/src/strings.cpp index ca4bf881d0..b919660573 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -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};