diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 070f2ceb55..e563c1de28 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -210,8 +210,6 @@ static bool CMSATree(TileIndex tile) return IsTileType(tile, MP_TREES); } -#define M(x) ((x) - STR_SV_STNAME) - enum StationNaming : uint8_t { STATIONNAMING_RAIL, STATIONNAMING_ROAD, @@ -223,8 +221,20 @@ enum StationNaming : uint8_t { /** Information to handle station action 0 property 24 correctly */ struct StationNameInformation { - uint32_t free_names; ///< Current bitset of free names (we can remove names). + std::bitset used_names; ///< Used default station suffixes. std::bitset indtypes; ///< Bit set indicating when an industry type has been found. + + bool IsAvailable(StringID str) const + { + assert(IsInsideMM(str, STR_SV_STNAME, STR_SV_STNAME_FALLBACK)); + return !this->used_names.test(str - STR_SV_STNAME); + } + + void SetUsed(StringID str) + { + assert(IsInsideMM(str, STR_SV_STNAME, STR_SV_STNAME_FALLBACK)); + this->used_names.set(str - STR_SV_STNAME); + } }; /** @@ -247,25 +257,16 @@ static bool FindNearIndustryName(TileIndex tile, void *user_data) /* In all cases if an industry that provides a name is found two of * the standard names will be disabled. */ - sni->free_names &= ~(1 << M(STR_SV_STNAME_OILFIELD) | 1 << M(STR_SV_STNAME_MINES)); + sni->SetUsed(STR_SV_STNAME_OILFIELD); + sni->SetUsed(STR_SV_STNAME_MINES); return !sni->indtypes[indtype]; } static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming name_class) { - static const uint32_t _gen_station_name_bits[] = { - 0, // STATIONNAMING_RAIL - 0, // STATIONNAMING_ROAD - 1U << M(STR_SV_STNAME_AIRPORT), // STATIONNAMING_AIRPORT - 1U << M(STR_SV_STNAME_OILFIELD), // STATIONNAMING_OILRIG - 1U << M(STR_SV_STNAME_DOCKS), // STATIONNAMING_DOCK - 1U << M(STR_SV_STNAME_HELIPORT), // STATIONNAMING_HELIPORT - }; - const Town *t = st->town; StationNameInformation sni{}; - sni.free_names = UINT32_MAX; for (const Station *s : Station::Iterate()) { if (s != st && s->town == t) { @@ -281,12 +282,10 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n } continue; } - uint str = M(s->string_id); - if (str <= 0x20) { - if (str == M(STR_SV_STNAME_FOREST)) { - str = M(STR_SV_STNAME_WOODS); - } - ClrBit(sni.free_names, str); + if (IsInsideMM(s->string_id, STR_SV_STNAME, STR_SV_STNAME_FALLBACK)) { + auto str = s->string_id; + if (str == STR_SV_STNAME_FOREST) str = STR_SV_STNAME_WOODS; + sni.SetUsed(str); } } } @@ -306,11 +305,25 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n /* Oil rigs/mines name could be marked not free by looking for a near by industry. */ /* check default names */ - uint32_t tmp = sni.free_names & _gen_station_name_bits[name_class]; - if (tmp != 0) return STR_SV_STNAME + FindFirstBit(tmp); + switch (name_class) { + case STATIONNAMING_AIRPORT: + if (sni.IsAvailable(STR_SV_STNAME_AIRPORT)) return STR_SV_STNAME_AIRPORT; + break; + case STATIONNAMING_OILRIG: + if (sni.IsAvailable(STR_SV_STNAME_OILFIELD)) return STR_SV_STNAME_OILFIELD; + break; + case STATIONNAMING_DOCK: + if (sni.IsAvailable(STR_SV_STNAME_DOCKS)) return STR_SV_STNAME_DOCKS; + break; + case STATIONNAMING_HELIPORT: + if (sni.IsAvailable(STR_SV_STNAME_HELIPORT)) return STR_SV_STNAME_HELIPORT; + break; + default: + break; + }; /* check mine? */ - if (HasBit(sni.free_names, M(STR_SV_STNAME_MINES))) { + if (sni.IsAvailable(STR_SV_STNAME_MINES)) { if (CountMapSquareAround(tile, CMSAMine) >= 2) { return STR_SV_STNAME_MINES; } @@ -318,20 +331,19 @@ 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) { - if (HasBit(sni.free_names, M(STR_SV_STNAME))) return STR_SV_STNAME; - - if (HasBit(sni.free_names, M(STR_SV_STNAME_CENTRAL))) return STR_SV_STNAME_CENTRAL; + if (sni.IsAvailable(STR_SV_STNAME)) return STR_SV_STNAME; + if (sni.IsAvailable(STR_SV_STNAME_CENTRAL)) return STR_SV_STNAME_CENTRAL; } /* Check lakeside */ - if (HasBit(sni.free_names, M(STR_SV_STNAME_LAKESIDE)) && + if (sni.IsAvailable(STR_SV_STNAME_LAKESIDE) && DistanceFromEdge(tile) < 20 && CountMapSquareAround(tile, CMSAWater) >= 5) { return STR_SV_STNAME_LAKESIDE; } /* Check woods */ - if (HasBit(sni.free_names, M(STR_SV_STNAME_WOODS)) && ( + if (sni.IsAvailable(STR_SV_STNAME_WOODS) && ( CountMapSquareAround(tile, CMSATree) >= 8 || CountMapSquareAround(tile, IsTileForestIndustry) >= 2) ) { @@ -342,43 +354,47 @@ static StringID GenerateStationName(Station *st, TileIndex tile, StationNaming n int z = GetTileZ(tile); int z2 = GetTileZ(t->xy); if (z < z2) { - if (HasBit(sni.free_names, M(STR_SV_STNAME_VALLEY))) return STR_SV_STNAME_VALLEY; + if (sni.IsAvailable(STR_SV_STNAME_VALLEY)) return STR_SV_STNAME_VALLEY; } else if (z > z2) { - if (HasBit(sni.free_names, M(STR_SV_STNAME_HEIGHTS))) return STR_SV_STNAME_HEIGHTS; + if (sni.IsAvailable(STR_SV_STNAME_HEIGHTS)) return STR_SV_STNAME_HEIGHTS; } /* check direction compared to town */ - static const int8_t _direction_and_table[] = { - ~( (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ), - ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_NORTH)) ), - ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_EAST)) | (1 << M(STR_SV_STNAME_NORTH)) ), - ~( (1 << M(STR_SV_STNAME_SOUTH)) | (1 << M(STR_SV_STNAME_WEST)) | (1 << M(STR_SV_STNAME_EAST)) ), + if (TileX(tile) < TileX(t->xy)) { + sni.SetUsed(STR_SV_STNAME_SOUTH); + sni.SetUsed(STR_SV_STNAME_WEST); + } else { + sni.SetUsed(STR_SV_STNAME_NORTH); + sni.SetUsed(STR_SV_STNAME_EAST); + } + if (TileY(tile) < TileY(t->xy)) { + sni.SetUsed(STR_SV_STNAME_SOUTH); + sni.SetUsed(STR_SV_STNAME_EAST); + } else { + sni.SetUsed(STR_SV_STNAME_NORTH); + sni.SetUsed(STR_SV_STNAME_WEST); + } + + /** Remaining station names that can be used when a more specific name has not been used. */ + static const StringID fallback_names[] = { + STR_SV_STNAME_NORTH, + STR_SV_STNAME_SOUTH, + STR_SV_STNAME_EAST, + STR_SV_STNAME_WEST, + STR_SV_STNAME_TRANSFER, + STR_SV_STNAME_HALT, + STR_SV_STNAME_EXCHANGE, + STR_SV_STNAME_ANNEXE, + STR_SV_STNAME_SIDINGS, + STR_SV_STNAME_BRANCH, + STR_SV_STNAME_UPPER, + STR_SV_STNAME_LOWER, }; - - sni.free_names &= _direction_and_table[ - (TileX(tile) < TileX(t->xy)) + - (TileY(tile) < TileY(t->xy)) * 2]; - - /** Bitmask of remaining station names that can be used when a more specific name has not been used. */ - static const uint32_t fallback_names = ( - (1U << M(STR_SV_STNAME_NORTH)) | - (1U << M(STR_SV_STNAME_SOUTH)) | - (1U << M(STR_SV_STNAME_EAST)) | - (1U << M(STR_SV_STNAME_WEST)) | - (1U << M(STR_SV_STNAME_TRANSFER)) | - (1U << M(STR_SV_STNAME_HALT)) | - (1U << M(STR_SV_STNAME_EXCHANGE)) | - (1U << M(STR_SV_STNAME_ANNEXE)) | - (1U << M(STR_SV_STNAME_SIDINGS)) | - (1U << M(STR_SV_STNAME_BRANCH)) | - (1U << M(STR_SV_STNAME_UPPER)) | - (1U << M(STR_SV_STNAME_LOWER)) - ); - - sni.free_names &= fallback_names; - return (sni.free_names == 0) ? STR_SV_STNAME_FALLBACK : (STR_SV_STNAME + FindFirstBit(sni.free_names)); + for (auto str : fallback_names) { + if (sni.IsAvailable(str)) return str; + } + return STR_SV_STNAME_FALLBACK; } -#undef M /** * Find the closest deleted station of the current company