From 0b7fa11a5b4ecc5122a15aabf61dda5321220a8c Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 21 Mar 2025 19:55:32 +0000 Subject: [PATCH] Codechange: Move NewGRF string mapping to own file. --- src/newgrf.cpp | 139 +---------------------- src/newgrf/CMakeLists.txt | 2 + src/newgrf/newgrf_stringmapping.cpp | 165 ++++++++++++++++++++++++++++ src/newgrf/newgrf_stringmapping.h | 20 ++++ 4 files changed, 189 insertions(+), 137 deletions(-) create mode 100644 src/newgrf/newgrf_stringmapping.cpp create mode 100644 src/newgrf/newgrf_stringmapping.h diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4274167dfe..be82d67602 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -56,6 +56,7 @@ #include "newgrf_roadstop.h" #include "newgrf/newgrf_bytereader.h" #include "newgrf/newgrf_internal.h" +#include "newgrf/newgrf_stringmapping.h" #include "table/strings.h" #include "table/build_industry.h" @@ -247,139 +248,6 @@ static GRFError *DisableGrf(StringID message = STR_NULL, GRFConfig *config = nul return &config->error.value(); } -/** - * Information for mapping static StringIDs. - */ -struct StringIDMapping { - uint32_t grfid; ///< Source NewGRF. - GRFStringID source; ///< Source grf-local GRFStringID. - std::function func; ///< Function for mapping result. - - StringIDMapping(uint32_t grfid, GRFStringID source, std::function &&func) : grfid(grfid), source(source), func(std::move(func)) { } -}; - -/** Strings to be mapped during load. */ -static std::vector _string_to_grf_mapping; - -/** - * Record a static StringID for getting translated later. - * @param source Source grf-local GRFStringID. - * @param func Function to call to set the mapping result. - */ -static void AddStringForMapping(GRFStringID source, std::function &&func) -{ - func(STR_UNDEFINED); - _string_to_grf_mapping.emplace_back(_cur.grffile->grfid, source, std::move(func)); -} - -/** - * Record a static StringID for getting translated later. - * @param source Source grf-local GRFStringID. - * @param target Destination for the mapping result. - */ -static void AddStringForMapping(GRFStringID source, StringID *target) -{ - AddStringForMapping(source, [target](StringID str) { *target = str; }); -} - -/** - * Perform a mapping from TTDPatch's string IDs to OpenTTD's - * string IDs, but only for the ones we are aware off; the rest - * like likely unused and will show a warning. - * @param str Grf-local GRFStringID to convert. - * @return the converted string ID - */ -static StringID TTDPStringIDToOTTDStringIDMapping(GRFStringID str) -{ - /* StringID table for TextIDs 0x4E->0x6D */ - static const StringID units_volume[] = { - STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS, - STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS, - STR_TONS, STR_TONS, STR_TONS, STR_BAGS, - STR_TONS, STR_TONS, STR_TONS, STR_BAGS, - STR_TONS, STR_TONS, STR_BAGS, STR_LITERS, - STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS, - STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS, - STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS - }; - - /* A string straight from a NewGRF; this was already translated by MapGRFStringID(). */ - assert(!IsInsideMM(str.base(), 0xD000, 0xD7FF)); - -#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \ - static_assert(stringend - stringid == end - begin); \ - if (str.base() >= begin && str.base() <= end) return StringID{str.base() + (stringid - begin)} - - /* We have some changes in our cargo strings, resulting in some missing. */ - TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS); - TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK); - if (str.base() >= 0x004E && str.base() <= 0x006D) return units_volume[str.base() - 0x004E]; - TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS); - TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS); - TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE); - - /* Map building names according to our lang file changes. There are several - * ranges of house ids, all of which need to be remapped to allow newgrfs - * to use original house names. */ - TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1); - TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1); - TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1); - - /* Same thing for industries */ - TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE); - TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED); - TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES); - TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM); - TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM); - - switch (str.base()) { - case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY; - case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED; - case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED; - } -#undef TEXTID_TO_STRINGID - - if (str.base() == 0) return STR_EMPTY; - - Debug(grf, 0, "Unknown StringID 0x{:04X} remapped to STR_EMPTY. Please open a Feature Request if you need it", str); - - return STR_EMPTY; -} - -/** - * Used when setting an object's property to map to the GRF's strings - * while taking in consideration the "drift" between TTDPatch string system and OpenTTD's one - * @param grfid Id of the grf file. - * @param str GRF-local GRFStringID that we want to have the equivalent in OpenTTD. - * @return The properly adjusted StringID. - */ -StringID MapGRFStringID(uint32_t grfid, GRFStringID str) -{ - if (IsInsideMM(str.base(), 0xD800, 0x10000)) { - /* General text provided by NewGRF. - * In the specs this is called the 0xDCxx range (misc persistent texts), - * but we meanwhile extended the range to 0xD800-0xFFFF. - * Note: We are not involved in the "persistent" business, since we do not store - * any NewGRF strings in savegames. */ - return GetGRFStringID(grfid, str); - } else if (IsInsideMM(str.base(), 0xD000, 0xD800)) { - /* Callback text provided by NewGRF. - * In the specs this is called the 0xD0xx range (misc graphics texts). - * These texts can be returned by various callbacks. - * - * Due to how TTDP implements the GRF-local- to global-textid translation - * texts included via 0x80 or 0x81 control codes have to add 0x400 to the textid. - * We do not care about that difference and just mask out the 0x400 bit. - */ - str = GRFStringID(str.base() & ~0x400); - return GetGRFStringID(grfid, str); - } else { - /* The NewGRF wants to include/reference an original TTD string. - * Try our best to find an equivalent one. */ - return TTDPStringIDToOTTDStringIDMapping(str); - } -} - static std::map _grf_id_overrides; /** @@ -10044,10 +9912,7 @@ static void AfterLoadGRFs() _cached_callback_groups.clear(); _cached_callback_groups.shrink_to_fit(); - for (StringIDMapping &it : _string_to_grf_mapping) { - it.func(MapGRFStringID(it.grfid, it.source)); - } - _string_to_grf_mapping.clear(); + FinaliseStringMapping(); /* Clear the action 6 override sprites. */ _grf_line_to_action6_sprite_override.clear(); diff --git a/src/newgrf/CMakeLists.txt b/src/newgrf/CMakeLists.txt index b6f8d9129c..5debd6a48a 100644 --- a/src/newgrf/CMakeLists.txt +++ b/src/newgrf/CMakeLists.txt @@ -2,4 +2,6 @@ add_files( newgrf_bytereader.cpp newgrf_bytereader.h newgrf_internal.h + newgrf_stringmapping.cpp + newgrf_stringmapping.h ) diff --git a/src/newgrf/newgrf_stringmapping.cpp b/src/newgrf/newgrf_stringmapping.cpp new file mode 100644 index 0000000000..2063325d86 --- /dev/null +++ b/src/newgrf/newgrf_stringmapping.cpp @@ -0,0 +1,165 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_stringmapping.cpp NewGRF string mapping implementation. */ + +#include "../stdafx.h" +#include "../debug.h" +#include "../newgrf.h" +#include "../newgrf_text.h" +#include "../newgrf_text_type.h" +#include "../strings_type.h" +#include "newgrf_internal.h" +#include "newgrf_stringmapping.h" + +#include "../safeguards.h" + +#include "../table/strings.h" + +/** + * Information for mapping static StringIDs. + */ +struct StringIDMapping { + uint32_t grfid; ///< Source NewGRF. + GRFStringID source; ///< Source grf-local GRFStringID. + std::function func; ///< Function for mapping result. + + StringIDMapping(uint32_t grfid, GRFStringID source, std::function &&func) : grfid(grfid), source(source), func(std::move(func)) { } +}; + +/** Strings to be mapped during load. */ +static std::vector _string_to_grf_mapping; + +/** + * Record a static StringID for getting translated later. + * @param source Source grf-local GRFStringID. + * @param func Function to call to set the mapping result. + */ +void AddStringForMapping(GRFStringID source, std::function &&func) +{ + func(STR_UNDEFINED); + _string_to_grf_mapping.emplace_back(_cur.grffile->grfid, source, std::move(func)); +} + +/** + * Record a static StringID for getting translated later. + * @param source Source grf-local GRFStringID. + * @param target Destination for the mapping result. + */ +void AddStringForMapping(GRFStringID source, StringID *target) +{ + AddStringForMapping(source, [target](StringID str) { *target = str; }); +} + +/** + * Perform a mapping from TTDPatch's string IDs to OpenTTD's + * string IDs, but only for the ones we are aware off; the rest + * like likely unused and will show a warning. + * @param str Grf-local GRFStringID to convert. + * @return the converted string ID + */ +static StringID TTDPStringIDToOTTDStringIDMapping(GRFStringID str) +{ + /* StringID table for TextIDs 0x4E->0x6D */ + static const StringID units_volume[] = { + STR_ITEMS, STR_PASSENGERS, STR_TONS, STR_BAGS, + STR_LITERS, STR_ITEMS, STR_CRATES, STR_TONS, + STR_TONS, STR_TONS, STR_TONS, STR_BAGS, + STR_TONS, STR_TONS, STR_TONS, STR_BAGS, + STR_TONS, STR_TONS, STR_BAGS, STR_LITERS, + STR_TONS, STR_LITERS, STR_TONS, STR_ITEMS, + STR_BAGS, STR_LITERS, STR_TONS, STR_ITEMS, + STR_TONS, STR_ITEMS, STR_LITERS, STR_ITEMS + }; + + /* A string straight from a NewGRF; this was already translated by MapGRFStringID(). */ + assert(!IsInsideMM(str.base(), 0xD000, 0xD7FF)); + +#define TEXTID_TO_STRINGID(begin, end, stringid, stringend) \ + static_assert(stringend - stringid == end - begin); \ + if (str.base() >= begin && str.base() <= end) return StringID{str.base() + (stringid - begin)} + + /* We have some changes in our cargo strings, resulting in some missing. */ + TEXTID_TO_STRINGID(0x000E, 0x002D, STR_CARGO_PLURAL_NOTHING, STR_CARGO_PLURAL_FIZZY_DRINKS); + TEXTID_TO_STRINGID(0x002E, 0x004D, STR_CARGO_SINGULAR_NOTHING, STR_CARGO_SINGULAR_FIZZY_DRINK); + if (str.base() >= 0x004E && str.base() <= 0x006D) return units_volume[str.base() - 0x004E]; + TEXTID_TO_STRINGID(0x006E, 0x008D, STR_QUANTITY_NOTHING, STR_QUANTITY_FIZZY_DRINKS); + TEXTID_TO_STRINGID(0x008E, 0x00AD, STR_ABBREV_NOTHING, STR_ABBREV_FIZZY_DRINKS); + TEXTID_TO_STRINGID(0x00D1, 0x00E0, STR_COLOUR_DARK_BLUE, STR_COLOUR_WHITE); + + /* Map building names according to our lang file changes. There are several + * ranges of house ids, all of which need to be remapped to allow newgrfs + * to use original house names. */ + TEXTID_TO_STRINGID(0x200F, 0x201F, STR_TOWN_BUILDING_NAME_TALL_OFFICE_BLOCK_1, STR_TOWN_BUILDING_NAME_OLD_HOUSES_1); + TEXTID_TO_STRINGID(0x2036, 0x2041, STR_TOWN_BUILDING_NAME_COTTAGES_1, STR_TOWN_BUILDING_NAME_SHOPPING_MALL_1); + TEXTID_TO_STRINGID(0x2059, 0x205C, STR_TOWN_BUILDING_NAME_IGLOO_1, STR_TOWN_BUILDING_NAME_PIGGY_BANK_1); + + /* Same thing for industries */ + TEXTID_TO_STRINGID(0x4802, 0x4826, STR_INDUSTRY_NAME_COAL_MINE, STR_INDUSTRY_NAME_SUGAR_MINE); + TEXTID_TO_STRINGID(0x482D, 0x482E, STR_NEWS_INDUSTRY_CONSTRUCTION, STR_NEWS_INDUSTRY_PLANTED); + TEXTID_TO_STRINGID(0x4832, 0x4834, STR_NEWS_INDUSTRY_CLOSURE_GENERAL, STR_NEWS_INDUSTRY_CLOSURE_LACK_OF_TREES); + TEXTID_TO_STRINGID(0x4835, 0x4838, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_INCREASE_FARM); + TEXTID_TO_STRINGID(0x4839, 0x483A, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_GENERAL, STR_NEWS_INDUSTRY_PRODUCTION_DECREASE_FARM); + + switch (str.base()) { + case 0x4830: return STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY; + case 0x4831: return STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED; + case 0x483B: return STR_ERROR_CAN_ONLY_BE_POSITIONED; + } +#undef TEXTID_TO_STRINGID + + if (str.base() == 0) return STR_EMPTY; + + Debug(grf, 0, "Unknown StringID 0x{:04X} remapped to STR_EMPTY. Please open a Feature Request if you need it", str); + + return STR_EMPTY; +} + +/** + * Used when setting an object's property to map to the GRF's strings + * while taking in consideration the "drift" between TTDPatch string system and OpenTTD's one + * @param grfid Id of the grf file. + * @param str GRF-local GRFStringID that we want to have the equivalent in OpenTTD. + * @return The properly adjusted StringID. + */ +StringID MapGRFStringID(uint32_t grfid, GRFStringID str) +{ + if (IsInsideMM(str.base(), 0xD800, 0x10000)) { + /* General text provided by NewGRF. + * In the specs this is called the 0xDCxx range (misc persistent texts), + * but we meanwhile extended the range to 0xD800-0xFFFF. + * Note: We are not involved in the "persistent" business, since we do not store + * any NewGRF strings in savegames. */ + return GetGRFStringID(grfid, str); + } else if (IsInsideMM(str.base(), 0xD000, 0xD800)) { + /* Callback text provided by NewGRF. + * In the specs this is called the 0xD0xx range (misc graphics texts). + * These texts can be returned by various callbacks. + * + * Due to how TTDP implements the GRF-local- to global-textid translation + * texts included via 0x80 or 0x81 control codes have to add 0x400 to the textid. + * We do not care about that difference and just mask out the 0x400 bit. + */ + str = GRFStringID(str.base() & ~0x400); + return GetGRFStringID(grfid, str); + } else { + /* The NewGRF wants to include/reference an original TTD string. + * Try our best to find an equivalent one. */ + return TTDPStringIDToOTTDStringIDMapping(str); + } +} + +/** + * Finalise all string mappings. + */ +void FinaliseStringMapping() +{ + for (StringIDMapping &it : _string_to_grf_mapping) { + it.func(MapGRFStringID(it.grfid, it.source)); + } + _string_to_grf_mapping.clear(); +} diff --git a/src/newgrf/newgrf_stringmapping.h b/src/newgrf/newgrf_stringmapping.h new file mode 100644 index 0000000000..fdae5d7763 --- /dev/null +++ b/src/newgrf/newgrf_stringmapping.h @@ -0,0 +1,20 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file newgrf_stringmapping.h NewGRF string mapping definition. */ + +#ifndef NEWGRF_STRINGMAPPING_H +#define NEWGRF_STRINGMAPPING_H + +#include "../strings_type.h" +#include "../newgrf_text_type.h" + +void AddStringForMapping(GRFStringID source, std::function &&func); +void AddStringForMapping(GRFStringID source, StringID *target); +void FinaliseStringMapping(); + +#endif /* NEWGRF_STRINGMAPPING_H */