From 786893a844f62ddc1117699408c9fd6f511dae06 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 11 Apr 2025 18:53:05 +0100 Subject: [PATCH 001/572] Fix: NewGRF Global variables 0D, 0E and 1E refer to wrong GRFFile. (#13986) These variables used GrfProcessingState, which is only valid while loading GRFs, after which they always point to the last loaded GRFFile. --- src/newgrf/newgrf_act0_globalvar.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/newgrf/newgrf_act0_globalvar.cpp b/src/newgrf/newgrf_act0_globalvar.cpp index d1e4f30ead..eb004161cb 100644 --- a/src/newgrf/newgrf_act0_globalvar.cpp +++ b/src/newgrf/newgrf_act0_globalvar.cpp @@ -458,11 +458,11 @@ bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile) } case 0x0D: // TTD Version, 00=DOS, 01=Windows - *value = _cur.grfconfig->palette & GRFP_USE_MASK; + *value = GetGRFConfig(grffile->grfid)->palette & GRFP_USE_MASK; return true; case 0x0E: // Y-offset for train sprites - *value = _cur.grffile->traininfo_vehicle_pitch; + *value = grffile->traininfo_vehicle_pitch; return true; case 0x0F: // Rail track type cost factors @@ -509,7 +509,7 @@ bool GetGlobalVariable(uint8_t param, uint32_t *value, const GRFFile *grffile) /* Add the local flags */ assert(!bits.Test(GrfMiscBit::TrainWidth32Pixels)); - if (_cur.grffile->traininfo_vehicle_width == VEHICLEINFO_FULL_VEHICLE_WIDTH) bits.Set(GrfMiscBit::TrainWidth32Pixels); + if (grffile->traininfo_vehicle_width == VEHICLEINFO_FULL_VEHICLE_WIDTH) bits.Set(GrfMiscBit::TrainWidth32Pixels); *value = bits.base(); return true; From e2ebf3a0f307c85acee06706ccd7396fb0ffc832 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 31 Mar 2025 16:28:29 +0200 Subject: [PATCH 002/572] Codechange: Move global strgen state into a single struct. --- src/game/game_text.cpp | 14 ++++---- src/strgen/strgen.cpp | 74 +++++++++++++++++++------------------- src/strgen/strgen.h | 19 ++++++---- src/strgen/strgen_base.cpp | 73 ++++++++++++++++++------------------- 4 files changed, 91 insertions(+), 89 deletions(-) diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 15c4fd7bdf..dfb170e934 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -25,19 +25,19 @@ void CDECL StrgenWarningI(const std::string &msg) { - Debug(script, 0, "{}:{}: warning: {}", _file, _cur_line, msg); - _warnings++; + Debug(script, 0, "{}:{}: warning: {}", _strgen.file, _strgen.cur_line, msg); + _strgen.warnings++; } void CDECL StrgenErrorI(const std::string &msg) { - Debug(script, 0, "{}:{}: error: {}", _file, _cur_line, msg); - _errors++; + Debug(script, 0, "{}:{}: error: {}", _strgen.file, _strgen.cur_line, msg); + _strgen.errors++; } void CDECL StrgenFatalI(const std::string &msg) { - Debug(script, 0, "{}:{}: FATAL: {}", _file, _cur_line, msg); + Debug(script, 0, "{}:{}: FATAL: {}", _strgen.file, _strgen.cur_line, msg); throw std::exception(); } @@ -289,7 +289,7 @@ void GameStrings::Compile() StringData data(32); StringListReader master_reader(data, this->raw_strings[0], true, false); master_reader.ParseFile(); - if (_errors != 0) throw std::exception(); + if (_strgen.errors != 0) throw std::exception(); this->version = data.Version(); @@ -302,7 +302,7 @@ void GameStrings::Compile() data.FreeTranslation(); StringListReader translation_reader(data, p, false, p.language != "english"); translation_reader.ParseFile(); - if (_errors != 0) throw std::exception(); + if (_strgen.errors != 0) throw std::exception(); auto &strings = this->compiled_strings.emplace_back(p.language); TranslationWriter writer(strings.lines); diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 7b4287eec5..c86c0c1029 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -35,34 +35,34 @@ void StrgenWarningI(const std::string &msg) { - if (_translation) { - fmt::print(stderr, LINE_NUM_FMT("info"), _file, _cur_line, msg); + if (_strgen.translation) { + fmt::print(stderr, LINE_NUM_FMT("info"), _strgen.file, _strgen.cur_line, msg); } else { - fmt::print(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, msg); + fmt::print(stderr, LINE_NUM_FMT("warning"), _strgen.file, _strgen.cur_line, msg); } - _warnings++; + _strgen.warnings++; } void StrgenErrorI(const std::string &msg) { - fmt::print(stderr, LINE_NUM_FMT("error"), _file, _cur_line, msg); - _errors++; + fmt::print(stderr, LINE_NUM_FMT("error"), _strgen.file, _strgen.cur_line, msg); + _strgen.errors++; } [[noreturn]] void StrgenFatalI(const std::string &msg) { - fmt::print(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, msg); + fmt::print(stderr, LINE_NUM_FMT("FATAL"), _strgen.file, _strgen.cur_line, msg); #ifdef _MSC_VER - fmt::print(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, "language is not compiled"); + fmt::print(stderr, LINE_NUM_FMT("warning"), _strgen.file, _strgen.cur_line, "language is not compiled"); #endif throw std::exception(); } [[noreturn]] void FatalErrorI(const std::string &msg) { - fmt::print(stderr, LINE_NUM_FMT("FATAL"), _file, _cur_line, msg); + fmt::print(stderr, LINE_NUM_FMT("FATAL"), _strgen.file, _strgen.cur_line, msg); #ifdef _MSC_VER - fmt::print(stderr, LINE_NUM_FMT("warning"), _file, _cur_line, "language is not compiled"); + fmt::print(stderr, LINE_NUM_FMT("warning"), _strgen.file, _strgen.cur_line, "language is not compiled"); #endif exit(2); } @@ -91,59 +91,59 @@ struct FileStringReader : StringReader { return result; } - void HandlePragma(char *str) override; + void HandlePragma(char *str, LanguagePackHeader &lang) override; void ParseFile() override { this->StringReader::ParseFile(); - if (StrEmpty(_lang.name) || StrEmpty(_lang.own_name) || StrEmpty(_lang.isocode)) { + if (StrEmpty(_strgen.lang.name) || StrEmpty(_strgen.lang.own_name) || StrEmpty(_strgen.lang.isocode)) { FatalError("Language must include ##name, ##ownname and ##isocode"); } } }; -void FileStringReader::HandlePragma(char *str) +void FileStringReader::HandlePragma(char *str, LanguagePackHeader &lang) { if (!memcmp(str, "id ", 3)) { this->data.next_string_id = std::strtoul(str + 3, nullptr, 0); } else if (!memcmp(str, "name ", 5)) { - strecpy(_lang.name, str + 5); + strecpy(lang.name, str + 5); } else if (!memcmp(str, "ownname ", 8)) { - strecpy(_lang.own_name, str + 8); + strecpy(lang.own_name, str + 8); } else if (!memcmp(str, "isocode ", 8)) { - strecpy(_lang.isocode, str + 8); + strecpy(lang.isocode, str + 8); } else if (!memcmp(str, "textdir ", 8)) { if (!memcmp(str + 8, "ltr", 3)) { - _lang.text_dir = TD_LTR; + lang.text_dir = TD_LTR; } else if (!memcmp(str + 8, "rtl", 3)) { - _lang.text_dir = TD_RTL; + lang.text_dir = TD_RTL; } else { FatalError("Invalid textdir {}", str + 8); } } else if (!memcmp(str, "digitsep ", 9)) { str += 9; - strecpy(_lang.digit_group_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); + strecpy(lang.digit_group_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); } else if (!memcmp(str, "digitsepcur ", 12)) { str += 12; - strecpy(_lang.digit_group_separator_currency, strcmp(str, "{NBSP}") == 0 ? NBSP : str); + strecpy(lang.digit_group_separator_currency, strcmp(str, "{NBSP}") == 0 ? NBSP : str); } else if (!memcmp(str, "decimalsep ", 11)) { str += 11; - strecpy(_lang.digit_decimal_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); + strecpy(lang.digit_decimal_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); } else if (!memcmp(str, "winlangid ", 10)) { const char *buf = str + 10; long langid = std::strtol(buf, nullptr, 16); if (langid > UINT16_MAX || langid < 0) { FatalError("Invalid winlangid {}", buf); } - _lang.winlangid = static_cast(langid); + lang.winlangid = static_cast(langid); } else if (!memcmp(str, "grflangid ", 10)) { const char *buf = str + 10; long langid = std::strtol(buf, nullptr, 16); if (langid >= 0x7F || langid < 0) { FatalError("Invalid grflangid {}", buf); } - _lang.newgrflangid = static_cast(langid); + lang.newgrflangid = static_cast(langid); } else if (!memcmp(str, "gender ", 7)) { if (this->master) FatalError("Genders are not allowed in the base translation."); const char *buf = str + 7; @@ -152,9 +152,9 @@ void FileStringReader::HandlePragma(char *str) auto s = ParseWord(&buf); if (!s.has_value()) break; - if (_lang.num_genders >= MAX_NUM_GENDERS) FatalError("Too many genders, max {}", MAX_NUM_GENDERS); - s->copy(_lang.genders[_lang.num_genders], CASE_GENDER_LEN - 1); - _lang.num_genders++; + if (lang.num_genders >= MAX_NUM_GENDERS) FatalError("Too many genders, max {}", MAX_NUM_GENDERS); + s->copy(lang.genders[lang.num_genders], CASE_GENDER_LEN - 1); + lang.num_genders++; } } else if (!memcmp(str, "case ", 5)) { if (this->master) FatalError("Cases are not allowed in the base translation."); @@ -164,12 +164,12 @@ void FileStringReader::HandlePragma(char *str) auto s = ParseWord(&buf); if (!s.has_value()) break; - if (_lang.num_cases >= MAX_NUM_CASES) FatalError("Too many cases, max {}", MAX_NUM_CASES); - s->copy(_lang.cases[_lang.num_cases], CASE_GENDER_LEN - 1); - _lang.num_cases++; + if (lang.num_cases >= MAX_NUM_CASES) FatalError("Too many cases, max {}", MAX_NUM_CASES); + s->copy(lang.cases[lang.num_cases], CASE_GENDER_LEN - 1); + lang.num_cases++; } } else { - StringReader::HandlePragma(str); + StringReader::HandlePragma(str, lang); } } @@ -364,11 +364,11 @@ int CDECL main(int argc, char *argv[]) return 0; case 't': - _annotate_todos = true; + _strgen.annotate_todos = true; break; case 'w': - _show_warnings = true; + _strgen.show_warnings = true; break; case 'h': @@ -417,7 +417,7 @@ int CDECL main(int argc, char *argv[]) StringData data(TEXT_TAB_END); FileStringReader master_reader(data, input_path, true, false); master_reader.ParseFile(); - if (_errors != 0) return 1; + if (_strgen.errors != 0) return 1; /* write strings.h */ std::filesystem::path output_path = dest_dir; @@ -427,7 +427,7 @@ int CDECL main(int argc, char *argv[]) HeaderFileWriter writer(output_path); writer.WriteHeader(data); writer.Finalise(data); - if (_errors != 0) return 1; + if (_strgen.errors != 0) return 1; } else { std::filesystem::path input_path = std::move(src_dir); input_path /= "english.txt"; @@ -443,7 +443,7 @@ int CDECL main(int argc, char *argv[]) std::filesystem::path lang_file = argument; FileStringReader translation_reader(data, lang_file, false, lang_file.filename() != "english.txt"); translation_reader.ParseFile(); // target file - if (_errors != 0) return 1; + if (_strgen.errors != 0) return 1; /* get the targetfile, strip any directories and append to destination path */ std::filesystem::path output_file = dest_dir; @@ -455,8 +455,8 @@ int CDECL main(int argc, char *argv[]) writer.Finalise(); /* if showing warnings, print a summary of the language */ - if (_show_warnings) { - fmt::print("{} warnings and {} errors for {}\n", _warnings, _errors, output_file); + if (_strgen.show_warnings) { + fmt::print("{} warnings and {} errors for {}\n", _strgen.warnings, _strgen.errors, output_file); } } } diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index 7253138063..78a6c8def7 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -74,7 +74,7 @@ struct StringReader { * Handle the pragma of the file. * @param str The pragma string to parse. */ - virtual void HandlePragma(char *str); + virtual void HandlePragma(char *str, LanguagePackHeader &lang); /** * Start parsing the file. @@ -154,10 +154,17 @@ void StrgenErrorI(const std::string &msg); #define StrgenFatal(format_string, ...) StrgenFatalI(fmt::format(FMT_STRING(format_string) __VA_OPT__(,) __VA_ARGS__)) std::optional ParseWord(const char **buf); -extern const char *_file; -extern size_t _cur_line; -extern size_t _errors, _warnings; -extern bool _show_warnings, _annotate_todos, _translation; -extern LanguagePackHeader _lang; +/** Global state shared between strgen.cpp, game_text.cpp and strgen_base.cpp */ +struct StrgenState { + std::string file = "(unknown file)"; ///< The filename of the input, so we can refer to it in errors/warnings + size_t cur_line = 0; ///< The current line we're parsing in the input file + size_t errors = 0; + size_t warnings = 0; + bool show_warnings = false; + bool annotate_todos = false; + bool translation = false; ///< Is the current file actually a translation or not + LanguagePackHeader lang; ///< Header information about a language. +}; +extern StrgenState _strgen; #endif /* STRGEN_H */ diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index c30ad4ae9b..534003ec16 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -21,13 +21,8 @@ #include "../safeguards.h" +StrgenState _strgen; static bool _translated; ///< Whether the current language is not the master language -bool _translation; ///< Is the current file actually a translation or not -const char *_file = "(unknown file)"; ///< The filename of the input, so we can refer to it in errors/warnings -size_t _cur_line; ///< The current line we're parsing in the input file -size_t _errors, _warnings; -bool _show_warnings = false, _annotate_todos = false; -LanguagePackHeader _lang; ///< Header information about a language. static const char *_cur_ident; static ParsedCommandStruct _cur_pcs; static size_t _cur_argidx; @@ -297,13 +292,13 @@ void EmitPlural(StringBuilder &builder, const char *buf, char32_t) StrgenFatal("{}: No plural words", _cur_ident); } - size_t expected = _plural_forms[_lang.plural_form].plural_count; + size_t expected = _plural_forms[_strgen.lang.plural_form].plural_count; if (expected != words.size()) { if (_translated) { StrgenFatal("{}: Invalid number of plural forms. Expecting {}, found {}.", _cur_ident, expected, words.size()); } else { - if (_show_warnings) StrgenWarning("'{}' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); + if (_strgen.show_warnings) StrgenWarning("'{}' is untranslated. Tweaking english string to allow compilation for plural forms", _cur_ident); if (words.size() > expected) { words.resize(expected); } else { @@ -315,7 +310,7 @@ void EmitPlural(StringBuilder &builder, const char *buf, char32_t) } builder.PutUtf8(SCC_PLURAL_LIST); - builder.PutUint8(_lang.plural_form); + builder.PutUint8(_strgen.lang.plural_form); builder.PutUint8(static_cast(TranslateArgumentIdx(*argidx, *offset))); EmitWordList(builder, words); } @@ -326,7 +321,7 @@ void EmitGender(StringBuilder &builder, const char *buf, char32_t) buf++; /* This is a {G=DER} command */ - auto nw = _lang.GetGenderIndex(buf); + auto nw = _strgen.lang.GetGenderIndex(buf); if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", buf); /* now nw contains the gender index */ @@ -350,7 +345,7 @@ void EmitGender(StringBuilder &builder, const char *buf, char32_t) if (!word.has_value()) break; words.emplace_back(*word); } - if (words.size() != _lang.num_genders) StrgenFatal("Bad # of arguments for gender command"); + if (words.size() != _strgen.lang.num_genders) StrgenFatal("Bad # of arguments for gender command"); assert(IsInsideBS(cmd->value, SCC_CONTROL_START, UINT8_MAX)); builder.PutUtf8(SCC_GENDER_LIST); @@ -369,7 +364,7 @@ static const CmdStruct *FindCmd(std::string_view s) static uint8_t ResolveCaseName(std::string_view str) { - uint8_t case_idx = _lang.GetCaseIndex(str); + uint8_t case_idx = _strgen.lang.GetCaseIndex(str); if (case_idx >= MAX_NUM_CASES) StrgenFatal("Invalid case-name '{}'", str); return case_idx + 1; } @@ -510,7 +505,7 @@ static bool CheckCommandsMatch(const char *a, const char *b, const char *name) * it is pointless to do all these checks as it'll always be correct. * After all, all checks are based on the base language. */ - if (!_translation) return true; + if (!_strgen.translation) return true; bool result = true; @@ -558,7 +553,7 @@ static bool CheckCommandsMatch(const char *a, const char *b, const char *name) void StringReader::HandleString(char *str) { if (*str == '#') { - if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2); + if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2, _strgen.lang); return; } @@ -621,7 +616,7 @@ void StringReader::HandleString(char *str) } /* Allocate a new LangString */ - this->data.Add(std::make_unique(str, s, this->data.next_string_id++, _cur_line)); + this->data.Add(std::make_unique(str, s, this->data.next_string_id++, _strgen.cur_line)); } else { if (ent == nullptr) { StrgenWarning("String name '{}' does not exist in master file", str); @@ -643,17 +638,17 @@ void StringReader::HandleString(char *str) /* If the string was translated, use the line from the * translated language so errors in the translated file * are properly referenced to. */ - ent->line = _cur_line; + ent->line = _strgen.cur_line; } } } -void StringReader::HandlePragma(char *str) +void StringReader::HandlePragma(char *str, LanguagePackHeader &lang) { if (!memcmp(str, "plural ", 7)) { - _lang.plural_form = atoi(str + 7); - if (_lang.plural_form >= lengthof(_plural_forms)) { - StrgenFatal("Invalid pluralform {}", _lang.plural_form); + lang.plural_form = atoi(str + 7); + if (lang.plural_form >= lengthof(_plural_forms)) { + StrgenFatal("Invalid pluralform {}", lang.plural_form); } } else { StrgenFatal("unknown pragma '{}'", str); @@ -667,25 +662,25 @@ static void StripTrailingWhitespace(std::string &str) void StringReader::ParseFile() { - _warnings = _errors = 0; + _strgen.warnings = _strgen.errors = 0; - _translation = this->translation; - _file = this->file.c_str(); + _strgen.translation = this->translation; + _strgen.file = this->file; /* For each new file we parse, reset the genders, and language codes. */ - MemSetT(&_lang, 0); - strecpy(_lang.digit_group_separator, ","); - strecpy(_lang.digit_group_separator_currency, ","); - strecpy(_lang.digit_decimal_separator, "."); + MemSetT(&_strgen.lang, 0); + strecpy(_strgen.lang.digit_group_separator, ","); + strecpy(_strgen.lang.digit_group_separator_currency, ","); + strecpy(_strgen.lang.digit_decimal_separator, "."); - _cur_line = 1; + _strgen.cur_line = 1; while (this->data.next_string_id < this->data.max_strings) { std::optional line = this->ReadLine(); if (!line.has_value()) return; StripTrailingWhitespace(line.value()); this->HandleString(line.value().data()); - _cur_line++; + _strgen.cur_line++; } if (this->data.next_string_id == this->data.max_strings) { @@ -812,20 +807,20 @@ void LanguageWriter::WriteLang(const StringData &data) size_t n = data.CountInUse(tab); in_use.push_back(n); - _lang.offsets[tab] = TO_LE16(static_cast(n)); + _strgen.lang.offsets[tab] = TO_LE16(static_cast(n)); for (size_t j = 0; j != in_use[tab]; j++) { const LangString *ls = data.strings[(tab * TAB_SIZE) + j].get(); - if (ls != nullptr && ls->translated.empty()) _lang.missing++; + if (ls != nullptr && ls->translated.empty()) _strgen.lang.missing++; } } - _lang.ident = TO_LE32(LanguagePackHeader::IDENT); - _lang.version = TO_LE32(data.Version()); - _lang.missing = TO_LE16(_lang.missing); - _lang.winlangid = TO_LE16(_lang.winlangid); + _strgen.lang.ident = TO_LE32(LanguagePackHeader::IDENT); + _strgen.lang.version = TO_LE32(data.Version()); + _strgen.lang.missing = TO_LE16(_strgen.lang.missing); + _strgen.lang.winlangid = TO_LE16(_strgen.lang.winlangid); - this->WriteHeader(&_lang); + this->WriteHeader(&_strgen.lang); for (size_t tab = 0; tab < data.tabs; tab++) { for (size_t j = 0; j != in_use[tab]; j++) { @@ -840,14 +835,14 @@ void LanguageWriter::WriteLang(const StringData &data) std::string output; StringBuilder builder(output); _cur_ident = ls->name.c_str(); - _cur_line = ls->line; + _strgen.cur_line = ls->line; /* Produce a message if a string doesn't have a translation. */ if (ls->translated.empty()) { - if (_show_warnings) { + if (_strgen.show_warnings) { StrgenWarning("'{}' is untranslated", ls->name); } - if (_annotate_todos) { + if (_strgen.annotate_todos) { builder.Put(" "); } } From ae513086153d8c6b98a3e3b2195fb18897bd894a Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:08:47 +0200 Subject: [PATCH 003/572] Codechange: Remove unused extern declarations. --- src/cheat_func.h | 2 -- src/vehicle_gui.cpp | 4 ++-- src/vehicle_gui_base.h | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/cheat_func.h b/src/cheat_func.h index 5c205b04bd..8585a589e2 100644 --- a/src/cheat_func.h +++ b/src/cheat_func.h @@ -12,8 +12,6 @@ #include "cheat_type.h" -extern Cheats _cheats; - void ShowCheatWindow(); diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index ed9d4b6a98..83553cad0f 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -51,8 +51,8 @@ #include "safeguards.h" -std::array, VLT_END> _grouping{}; -std::array _sorting{}; +static std::array, VLT_END> _grouping{}; +static std::array _sorting{}; static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNumberSorter; static BaseVehicleListWindow::VehicleIndividualSortFunction VehicleNameSorter; diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index d7e3cdb388..d1097c499c 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -164,7 +164,4 @@ struct Sorting { Listing train; }; -extern std::array, VLT_END> _grouping; -extern std::array _sorting; - #endif /* VEHICLE_GUI_BASE_H */ From 35cd05b27dc1b8b2d156c5036eab9d99a0164084 Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:09:28 +0200 Subject: [PATCH 004/572] Codechange: Rename _current_data to _current_gamestrings_data. --- src/game/game_text.cpp | 28 ++++++++++++++-------------- src/saveload/game_sl.cpp | 18 +++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index dfb170e934..5a7aa0365c 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -311,7 +311,7 @@ void GameStrings::Compile() } /** The currently loaded game strings. */ -std::shared_ptr _current_data = nullptr; +std::shared_ptr _current_gamestrings_data = nullptr; /** * Get the string pointer of a particular game string. @@ -320,8 +320,8 @@ std::shared_ptr _current_data = nullptr; */ std::string_view GetGameStringPtr(StringIndexInTab id) { - if (_current_data == nullptr || _current_data->cur_language == nullptr || id.base() >= _current_data->cur_language->lines.size()) return GetStringPtr(STR_UNDEFINED); - return _current_data->cur_language->lines[id]; + if (_current_gamestrings_data == nullptr || _current_gamestrings_data->cur_language == nullptr || id.base() >= _current_gamestrings_data->cur_language->lines.size()) return GetStringPtr(STR_UNDEFINED); + return _current_gamestrings_data->cur_language->lines[id]; } /** @@ -334,8 +334,8 @@ const StringParams &GetGameStringParams(StringIndexInTab id) /* An empty result for STR_UNDEFINED. */ static StringParams empty; - if (id.base() >= _current_data->string_params.size()) return empty; - return _current_data->string_params[id]; + if (id.base() >= _current_gamestrings_data->string_params.size()) return empty; + return _current_gamestrings_data->string_params[id]; } /** @@ -348,8 +348,8 @@ const std::string &GetGameStringName(StringIndexInTab id) /* The name for STR_UNDEFINED. */ static const std::string undefined = "STR_UNDEFINED"; - if (id.base() >= _current_data->string_names.size()) return undefined; - return _current_data->string_names[id]; + if (id.base() >= _current_gamestrings_data->string_names.size()) return undefined; + return _current_gamestrings_data->string_names[id]; } /** @@ -358,8 +358,8 @@ const std::string &GetGameStringName(StringIndexInTab id) */ void RegisterGameTranslation(Squirrel *engine) { - _current_data = LoadTranslations(); - if (_current_data == nullptr) return; + _current_gamestrings_data = LoadTranslations(); + if (_current_gamestrings_data == nullptr) return; HSQUIRRELVM vm = engine->GetVM(); sq_pushroottable(vm); @@ -367,7 +367,7 @@ void RegisterGameTranslation(Squirrel *engine) if (SQ_FAILED(sq_get(vm, -2))) return; int idx = 0; - for (const auto &p : _current_data->string_names) { + for (const auto &p : _current_gamestrings_data->string_names) { sq_pushstring(vm, p, -1); sq_pushinteger(vm, idx); sq_rawset(vm, -3); @@ -384,15 +384,15 @@ void RegisterGameTranslation(Squirrel *engine) */ void ReconsiderGameScriptLanguage() { - if (_current_data == nullptr) return; + if (_current_gamestrings_data == nullptr) return; std::string language = FS2OTTD(_current_language->file.stem()); - for (auto &p : _current_data->compiled_strings) { + for (auto &p : _current_gamestrings_data->compiled_strings) { if (p.language == language) { - _current_data->cur_language = &p; + _current_gamestrings_data->cur_language = &p; return; } } - _current_data->cur_language = &_current_data->compiled_strings[0]; + _current_gamestrings_data->cur_language = &_current_gamestrings_data->compiled_strings[0]; } diff --git a/src/saveload/game_sl.cpp b/src/saveload/game_sl.cpp index af9512c22b..769f8e030a 100644 --- a/src/saveload/game_sl.cpp +++ b/src/saveload/game_sl.cpp @@ -113,7 +113,7 @@ struct GSDTChunkHandler : ChunkHandler { } }; -extern std::shared_ptr _current_data; +extern std::shared_ptr _current_gamestrings_data; static std::string _game_saveload_string; static uint32_t _game_saveload_strings; @@ -159,21 +159,21 @@ struct GSTRChunkHandler : ChunkHandler { { const std::vector slt = SlCompatTableHeader(_game_language_desc, _game_language_sl_compat); - _current_data = std::make_shared(); + _current_gamestrings_data = std::make_shared(); while (SlIterateArray() != -1) { LanguageStrings ls; SlObject(&ls, slt); - _current_data->raw_strings.push_back(std::move(ls)); + _current_gamestrings_data->raw_strings.push_back(std::move(ls)); } /* If there were no strings in the savegame, set GameStrings to nullptr */ - if (_current_data->raw_strings.empty()) { - _current_data.reset(); + if (_current_gamestrings_data->raw_strings.empty()) { + _current_gamestrings_data.reset(); return; } - _current_data->Compile(); + _current_gamestrings_data->Compile(); ReconsiderGameScriptLanguage(); } @@ -181,11 +181,11 @@ struct GSTRChunkHandler : ChunkHandler { { SlTableHeader(_game_language_desc); - if (_current_data == nullptr) return; + if (_current_gamestrings_data == nullptr) return; - for (uint i = 0; i < _current_data->raw_strings.size(); i++) { + for (uint i = 0; i < _current_gamestrings_data->raw_strings.size(); i++) { SlSetArrayIndex(i); - SlObject(&_current_data->raw_strings[i], _game_language_desc); + SlObject(&_current_gamestrings_data->raw_strings[i], _game_language_desc); } } }; From c9c99738842b26fe6b0790a8e600bc7e36416be3 Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:10:10 +0200 Subject: [PATCH 005/572] Codechange: Rename _circle_size to _setting_circle_size. --- src/settingentry_gui.cpp | 6 +++--- src/settingentry_gui.h | 2 +- src/settings_gui.cpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/settingentry_gui.cpp b/src/settingentry_gui.cpp index 6ceeca0895..e48572e13f 100644 --- a/src/settingentry_gui.cpp +++ b/src/settingentry_gui.cpp @@ -94,7 +94,7 @@ uint BaseSettingEntry::Draw(GameSettings *settings_ptr, int left, int right, int if (cur_row >= max_row) return cur_row; bool rtl = _current_text_dir == TD_RTL; - int offset = (rtl ? -(int)_circle_size.width : (int)_circle_size.width) / 2; + int offset = (rtl ? -(int)_setting_circle_size.width : (int)_setting_circle_size.width) / 2; int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent; int x = rtl ? right : left; @@ -621,8 +621,8 @@ uint SettingsPage::Draw(GameSettings *settings_ptr, int left, int right, int y, void SettingsPage::DrawSetting(GameSettings *, int left, int right, int y, bool) const { bool rtl = _current_text_dir == TD_RTL; - DrawSprite((this->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? right - _circle_size.width : left, y + (SETTING_HEIGHT - _circle_size.height) / 2); - DrawString(rtl ? left : left + _circle_size.width + WidgetDimensions::scaled.hsep_normal, rtl ? right - _circle_size.width - WidgetDimensions::scaled.hsep_normal : right, y + (SETTING_HEIGHT - GetCharacterHeight(FS_NORMAL)) / 2, this->title, TC_ORANGE); + DrawSprite((this->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED), PAL_NONE, rtl ? right - _setting_circle_size.width : left, y + (SETTING_HEIGHT - _setting_circle_size.height) / 2); + DrawString(rtl ? left : left + _setting_circle_size.width + WidgetDimensions::scaled.hsep_normal, rtl ? right - _setting_circle_size.width - WidgetDimensions::scaled.hsep_normal : right, y + (SETTING_HEIGHT - GetCharacterHeight(FS_NORMAL)) / 2, this->title, TC_ORANGE); } /** Construct settings tree */ diff --git a/src/settingentry_gui.h b/src/settingentry_gui.h index 600f2e98e9..5587ae255a 100644 --- a/src/settingentry_gui.h +++ b/src/settingentry_gui.h @@ -14,7 +14,7 @@ #include "settings_internal.h" #include "stringfilter_type.h" -extern Dimension _circle_size; +extern Dimension _setting_circle_size; extern int SETTING_HEIGHT; /** diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 7534f9616f..1337f298e7 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -83,7 +83,7 @@ static const uint32_t _autosave_dropdown_to_minutes[] = { 120, }; -Dimension _circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. +Dimension _setting_circle_size; ///< Dimension of the circle +/- icon. This is here as not all users are within the class of the settings window. /** * Get index of the current screen resolution. @@ -1267,14 +1267,14 @@ struct GameSettingsWindow : Window { void OnInit() override { - _circle_size = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED)); + _setting_circle_size = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED)); } void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override { switch (widget) { case WID_GS_OPTIONSPANEL: - resize.height = SETTING_HEIGHT = std::max({(int)_circle_size.height, SETTING_BUTTON_HEIGHT, GetCharacterHeight(FS_NORMAL)}) + WidgetDimensions::scaled.vsep_normal; + resize.height = SETTING_HEIGHT = std::max({(int)_setting_circle_size.height, SETTING_BUTTON_HEIGHT, GetCharacterHeight(FS_NORMAL)}) + WidgetDimensions::scaled.vsep_normal; resize.width = 1; size.height = 5 * resize.height + WidgetDimensions::scaled.framerect.Vertical(); From b0d678e37588aff347dceafe79fb698d8003d6d1 Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:10:46 +0200 Subject: [PATCH 006/572] Codechange: Rename _ignore_restrictions to _ignore_industry_restrictions. --- src/industry_cmd.cpp | 8 ++++---- src/industry_gui.cpp | 12 ++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index a71421bc1b..1c2d79476d 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1321,7 +1321,7 @@ static CommandCost CheckNewIndustry_OilRefinery(TileIndex tile) return CommandCost(STR_ERROR_CAN_ONLY_BE_POSITIONED); } -extern bool _ignore_restrictions; +extern bool _ignore_industry_restrictions; /** * Check the conditions of #CHECK_OIL_RIG (Industries at sea should be positioned near edge of the map). @@ -1330,7 +1330,7 @@ extern bool _ignore_restrictions; */ static CommandCost CheckNewIndustry_OilRig(TileIndex tile) { - if (_game_mode == GM_EDITOR && _ignore_restrictions) return CommandCost(); + if (_game_mode == GM_EDITOR && _ignore_industry_restrictions) return CommandCost(); if (TileHeight(tile) == 0 && CheckScaledDistanceFromEdge(TileAddXY(tile, 1, 1), _settings_game.game_creation.oil_refinery_limit)) return CommandCost(); @@ -1566,7 +1566,7 @@ static CommandCost CheckIfIndustryTileSlopes(TileIndex tile, const IndustryTileL /* It is almost impossible to have a fully flat land in TG, so what we * do is that we check if we can make the land flat later on. See * CheckIfCanLevelIndustryPlatform(). */ - if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_restrictions)) { + if (!refused_slope || (_settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && !custom_shape && !_ignore_industry_restrictions)) { return CommandCost(); } return CommandCost(STR_ERROR_SITE_UNSUITABLE); @@ -2023,7 +2023,7 @@ static CommandCost CreateNewIndustryHelper(TileIndex tile, IndustryType type, Do if (ret.Failed()) return ret; if (!custom_shape_check && _settings_game.game_creation.land_generator == LG_TERRAGENESIS && _generating_world && - !_ignore_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) { + !_ignore_industry_restrictions && !CheckIfCanLevelIndustryPlatform(tile, DoCommandFlag::NoWater, layout)) { return CommandCost(STR_ERROR_SITE_UNSUITABLE); } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 651dac4014..bbe73b9327 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -56,7 +56,7 @@ #include "safeguards.h" -bool _ignore_restrictions; +bool _ignore_industry_restrictions; std::bitset _displayed_industries; ///< Communication from the industry chain window to the smallmap window about what industries to display. /** Cargo suffix type (for which window is it requested) */ @@ -722,15 +722,11 @@ public: return; } - Backup cur_company(_current_company, OWNER_NONE); - Backup old_generating_world(_generating_world, true); - _ignore_restrictions = true; + AutoRestoreBackup backup_cur_company(_current_company, OWNER_NONE); + AutoRestoreBackup backup_generating_world(_generating_world, true); + AutoRestoreBackup backup_ignore_industry_restritions(_ignore_industry_restrictions, true); Command::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, &CcBuildIndustry, tile, this->selected_type, layout_index, false, seed); - - cur_company.Restore(); - old_generating_world.Restore(); - _ignore_restrictions = false; } else { success = Command::Post(STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY, tile, this->selected_type, layout_index, false, seed); } From e89be12ebb6f0be1d970ffd4a77150dad26dc18c Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:11:14 +0200 Subject: [PATCH 007/572] Codechange: Rename _library to _ft_library. --- src/fontcache/freetypefontcache.cpp | 14 +++++++------- src/os/unix/font_unix.cpp | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index 04ddc3e21f..aec1c5160d 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -46,7 +46,7 @@ public: const void *GetOSHandle() override { return &face; } }; -FT_Library _library = nullptr; +FT_Library _ft_library = nullptr; /** @@ -163,8 +163,8 @@ void LoadFreeTypeFont(FontSize fs) std::string font = GetFontCacheFontName(fs); if (font.empty()) return; - if (_library == nullptr) { - if (FT_Init_FreeType(&_library) != FT_Err_Ok) { + if (_ft_library == nullptr) { + if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) { ShowInfo("Unable to initialize FreeType, using sprite fonts instead"); return; } @@ -178,13 +178,13 @@ void LoadFreeTypeFont(FontSize fs) /* If font is an absolute path to a ttf, try loading that first. */ int32_t index = 0; if (settings->os_handle != nullptr) index = *static_cast(settings->os_handle); - FT_Error error = FT_New_Face(_library, font_name, index, &face); + FT_Error error = FT_New_Face(_ft_library, font_name, index, &face); if (error != FT_Err_Ok) { /* Check if font is a relative filename in one of our search-paths. */ std::string full_font = FioFindFullPath(BASE_DIR, font_name); if (!full_font.empty()) { - error = FT_New_Face(_library, full_font.c_str(), 0, &face); + error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face); } } @@ -303,8 +303,8 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback) */ void UninitFreeType() { - FT_Done_FreeType(_library); - _library = nullptr; + FT_Done_FreeType(_ft_library); + _ft_library = nullptr; } #if !defined(WITH_FONTCONFIG) diff --git a/src/os/unix/font_unix.cpp b/src/os/unix/font_unix.cpp index efaaa3e056..6dbe720bbe 100644 --- a/src/os/unix/font_unix.cpp +++ b/src/os/unix/font_unix.cpp @@ -20,7 +20,7 @@ #include #include FT_FREETYPE_H -extern FT_Library _library; +extern FT_Library _ft_library; /** * Split the font name into the font family and style. These fields are separated by a comma, @@ -85,7 +85,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) * wrongly a 'random' font, so check whether the family name is the * same as the supplied name */ if (StrEqualsIgnoreCase(font_family, (char *)family)) { - err = FT_New_Face(_library, (char *)file, index, face); + err = FT_New_Face(_ft_library, (char *)file, index, face); } } } From 1cfad1474a8deec5d48c6d1f91bff543b5c1dc29 Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 9 Apr 2025 20:13:28 +0200 Subject: [PATCH 008/572] Codechange: Rename _cur to _cur_gps. --- src/newgrf.cpp | 74 +++++++-------- src/newgrf/newgrf_act0.cpp | 8 +- src/newgrf/newgrf_act0_aircraft.cpp | 12 +-- src/newgrf/newgrf_act0_airports.cpp | 20 ++--- src/newgrf/newgrf_act0_badges.cpp | 6 +- src/newgrf/newgrf_act0_canals.cpp | 2 +- src/newgrf/newgrf_act0_cargo.cpp | 2 +- src/newgrf/newgrf_act0_globalvar.cpp | 16 ++-- src/newgrf/newgrf_act0_houses.cpp | 16 ++-- src/newgrf/newgrf_act0_industries.cpp | 34 +++---- src/newgrf/newgrf_act0_objects.cpp | 4 +- src/newgrf/newgrf_act0_railtypes.cpp | 10 +-- src/newgrf/newgrf_act0_roadstops.cpp | 4 +- src/newgrf/newgrf_act0_roadtypes.cpp | 4 +- src/newgrf/newgrf_act0_roadvehs.cpp | 16 ++-- src/newgrf/newgrf_act0_ships.cpp | 16 ++-- src/newgrf/newgrf_act0_sounds.cpp | 8 +- src/newgrf/newgrf_act0_stations.cpp | 14 +-- src/newgrf/newgrf_act0_trains.cpp | 20 ++--- src/newgrf/newgrf_act1.cpp | 16 ++-- src/newgrf/newgrf_act10.cpp | 2 +- src/newgrf/newgrf_act11.cpp | 34 +++---- src/newgrf/newgrf_act12.cpp | 10 +-- src/newgrf/newgrf_act13.cpp | 2 +- src/newgrf/newgrf_act14.cpp | 50 +++++------ src/newgrf/newgrf_act2.cpp | 52 +++++------ src/newgrf/newgrf_act3.cpp | 124 +++++++++++++------------- src/newgrf/newgrf_act4.cpp | 36 ++++---- src/newgrf/newgrf_act5.cpp | 38 ++++---- src/newgrf/newgrf_act6.cpp | 6 +- src/newgrf/newgrf_act7_9.cpp | 30 +++---- src/newgrf/newgrf_act8.cpp | 28 +++--- src/newgrf/newgrf_acta.cpp | 14 +-- src/newgrf/newgrf_actb.cpp | 20 ++--- src/newgrf/newgrf_actd.cpp | 42 ++++----- src/newgrf/newgrf_acte.cpp | 6 +- src/newgrf/newgrf_actf.cpp | 4 +- src/newgrf/newgrf_internal.h | 2 +- src/newgrf/newgrf_stringmapping.cpp | 2 +- 39 files changed, 402 insertions(+), 402 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 46c95a643d..55182b8b5a 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -71,7 +71,7 @@ GrfMiscBits _misc_grf_features{}; /** Indicates which are the newgrf features currently loaded ingame */ GRFLoadedFeatures _loaded_newgrf_features; -GrfProcessingState _cur; +GrfProcessingState _cur_gps; ReferenceThroughBaseContainer> _gted; ///< Temporary engine data used during NewGRF loading @@ -87,7 +87,7 @@ ReferenceThroughBaseContainer> _gted; ///< Tempo */ void GrfMsgI(int severity, const std::string &msg) { - Debug(grf, severity, "[{}:{}] {}", _cur.grfconfig->filename, _cur.nfo_line, msg); + Debug(grf, severity, "[{}:{}] {}", _cur_gps.grfconfig->filename, _cur_gps.nfo_line, msg); } /** @@ -132,18 +132,18 @@ GRFError *DisableGrf(StringID message, GRFConfig *config) if (config != nullptr) { file = GetFileByGRFID(config->ident.grfid); } else { - config = _cur.grfconfig; - file = _cur.grffile; + config = _cur_gps.grfconfig; + file = _cur_gps.grffile; } config->status = GCS_DISABLED; if (file != nullptr) ClearTemporaryNewGRFData(file); - if (config == _cur.grfconfig) _cur.skip_sprites = -1; + if (config == _cur_gps.grfconfig) _cur_gps.skip_sprites = -1; if (message == STR_NULL) return nullptr; config->error = {STR_NEWGRF_ERROR_MSG_FATAL, message}; - if (config == _cur.grfconfig) config->error->param_value[0] = _cur.nfo_line; + if (config == _cur_gps.grfconfig) config->error->param_value[0] = _cur_gps.nfo_line; return &config->error.value(); } @@ -159,7 +159,7 @@ GRFError *DisableGrf(StringID message, GRFConfig *config) void DisableStaticNewGRFInfluencingNonStaticNewGRFs(GRFConfig &c) { GRFError *error = DisableGrf(STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC, &c); - error->data = _cur.grfconfig->GetName(); + error->data = _cur_gps.grfconfig->GetName(); } static std::map _grf_id_overrides; @@ -186,7 +186,7 @@ void SetNewGRFOverride(uint32_t source_grfid, uint32_t target_grfid) */ GRFFile *GetCurrentGRFOverride() { - auto found = _grf_id_overrides.find(_cur.grffile->grfid); + auto found = _grf_id_overrides.find(_cur_gps.grffile->grfid); if (found != std::end(_grf_id_overrides)) { GRFFile *grffile = GetFileByGRFID(found->second); if (grffile != nullptr) return grffile; @@ -306,7 +306,7 @@ CargoTypes TranslateRefitMask(uint32_t refit_mask) { CargoTypes result = 0; for (uint8_t bit : SetBitIterator(refit_mask)) { - CargoType cargo = GetCargoTranslation(bit, _cur.grffile, true); + CargoType cargo = GetCargoTranslation(bit, _cur_gps.grffile, true); if (IsValidCargoType(cargo)) SetBit(result, cargo); } return result; @@ -362,16 +362,16 @@ void ConvertTTDBasePrice(uint32_t base_pointer, const char *error_location, Pric */ void GRFUnsafe(ByteReader &) { - _cur.grfconfig->flags.Set(GRFConfigFlag::Unsafe); + _cur_gps.grfconfig->flags.Set(GRFConfigFlag::Unsafe); /* Skip remainder of GRF */ - _cur.skip_sprites = -1; + _cur_gps.skip_sprites = -1; } /** Reset and clear all NewGRFs */ static void ResetNewGRF() { - _cur.grffile = nullptr; + _cur_gps.grffile = nullptr; _grf_files.clear(); /* We store pointers to GRFFiles in many places, so need to ensure that the pointers do not become invalid @@ -522,14 +522,14 @@ void ResetPersistentNewGRFData() */ static void BuildCargoTranslationMap() { - _cur.grffile->cargo_map.fill(UINT8_MAX); + _cur_gps.grffile->cargo_map.fill(UINT8_MAX); - auto cargo_list = GetCargoTranslationTable(*_cur.grffile); + auto cargo_list = GetCargoTranslationTable(*_cur_gps.grffile); for (const CargoSpec *cs : CargoSpec::Iterate()) { /* Check the translation table for this cargo's label */ int idx = find_index(cargo_list, cs->label); - if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx; + if (idx >= 0) _cur_gps.grffile->cargo_map[cs->Index()] = idx; } } @@ -542,12 +542,12 @@ static void InitNewGRFFile(const GRFConfig &config) GRFFile *newfile = GetFileByFilename(config.filename); if (newfile != nullptr) { /* We already loaded it once. */ - _cur.grffile = newfile; + _cur_gps.grffile = newfile; return; } assert(_grf_files.size() < _grf_files.capacity()); // We must not invalidate pointers. - _cur.grffile = &_grf_files.emplace_back(config); + _cur_gps.grffile = &_grf_files.emplace_back(config); } /** @@ -1215,18 +1215,18 @@ struct InvokeGrfActionHandler { * better make this more robust in the future. */ static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage) { - auto it = _grf_line_to_action6_sprite_override.find({_cur.grfconfig->ident.grfid, _cur.nfo_line}); + auto it = _grf_line_to_action6_sprite_override.find({_cur_gps.grfconfig->ident.grfid, _cur_gps.nfo_line}); if (it == _grf_line_to_action6_sprite_override.end()) { /* No preloaded sprite to work with; read the * pseudo sprite content. */ - _cur.file->ReadBlock(buf, num); + _cur_gps.file->ReadBlock(buf, num); } else { /* Use the preloaded sprite data. */ buf = it->second.data(); GrfMsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data"); /* Skip the real (original) content of this action. */ - _cur.file->SeekTo(num, SEEK_CUR); + _cur_gps.file->SeekTo(num, SEEK_CUR); } ByteReader br(buf, buf + num); @@ -1255,8 +1255,8 @@ static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage) */ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, SpriteFile &file) { - AutoRestoreBackup cur_file(_cur.file, &file); - AutoRestoreBackup cur_config(_cur.grfconfig, &config); + AutoRestoreBackup cur_file(_cur_gps.file, &file); + AutoRestoreBackup cur_config(_cur_gps.grfconfig, &config); Debug(grf, 2, "LoadNewGRFFile: Reading NewGRF-file '{}'", config.filename); @@ -1295,16 +1295,16 @@ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, Spr return; } - _cur.ClearDataForNextFile(); + _cur_gps.ClearDataForNextFile(); ReusableBuffer buf; while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) { uint8_t type = file.ReadByte(); - _cur.nfo_line++; + _cur_gps.nfo_line++; if (type == 0xFF) { - if (_cur.skip_sprites == 0) { + if (_cur_gps.skip_sprites == 0) { /* Limit the special sprites to 1 MiB. */ if (num > 1024 * 1024) { GrfMsg(0, "LoadNewGRFFile: Unexpectedly large sprite, disabling"); @@ -1315,14 +1315,14 @@ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, Spr DecodeSpecialSprite(buf.Allocate(num), num, stage); /* Stop all processing if we are to skip the remaining sprites */ - if (_cur.skip_sprites == -1) break; + if (_cur_gps.skip_sprites == -1) break; continue; } else { file.SkipBytes(num); } } else { - if (_cur.skip_sprites == 0) { + if (_cur_gps.skip_sprites == 0) { GrfMsg(0, "LoadNewGRFFile: Unexpected sprite, disabling"); DisableGrf(STR_NEWGRF_ERROR_UNEXPECTED_SPRITE); break; @@ -1337,7 +1337,7 @@ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, Spr } } - if (_cur.skip_sprites > 0) _cur.skip_sprites--; + if (_cur_gps.skip_sprites > 0) _cur_gps.skip_sprites--; } } @@ -1363,8 +1363,8 @@ void LoadNewGRFFile(GRFConfig &config, GrfLoadingStage stage, Subdirectory subdi * carried out. All others are ignored, because they only need to be * processed once at initialization. */ if (stage != GLS_FILESCAN && stage != GLS_SAFETYSCAN && stage != GLS_LABELSCAN) { - _cur.grffile = GetFileByFilename(filename); - if (_cur.grffile == nullptr) UserError("File '{}' lost in cache.\n", filename); + _cur_gps.grffile = GetFileByFilename(filename); + if (_cur_gps.grffile == nullptr) UserError("File '{}' lost in cache.\n", filename); if (stage == GLS_RESERVE && config.status != GCS_INITIALISED) return; if (stage == GLS_ACTIVATION && !config.flags.Test(GRFConfigFlag::Reserved)) return; } @@ -1755,7 +1755,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset) if (c->status != GCS_NOT_FOUND) c->status = GCS_UNKNOWN; } - _cur.spriteid = load_index; + _cur_gps.spriteid = load_index; /* Load newgrf sprites * in each loading stage, (try to) open each file specified in the config @@ -1781,7 +1781,7 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset) uint num_grfs = 0; uint num_non_static = 0; - _cur.stage = stage; + _cur_gps.stage = stage; for (const auto &c : _grfconfig) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND) continue; if (stage > GLS_INIT && c->flags.Test(GRFConfigFlag::InitOnly)) continue; @@ -1812,19 +1812,19 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset) c->flags.Set(GRFConfigFlag::Reserved); } else if (stage == GLS_ACTIVATION) { c->flags.Reset(GRFConfigFlag::Reserved); - assert(GetFileByGRFID(c->ident.grfid) == _cur.grffile); - ClearTemporaryNewGRFData(_cur.grffile); + assert(GetFileByGRFID(c->ident.grfid) == _cur_gps.grffile); + ClearTemporaryNewGRFData(_cur_gps.grffile); BuildCargoTranslationMap(); - Debug(sprite, 2, "LoadNewGRF: Currently {} sprites are loaded", _cur.spriteid); + Debug(sprite, 2, "LoadNewGRF: Currently {} sprites are loaded", _cur_gps.spriteid); } else if (stage == GLS_INIT && c->flags.Test(GRFConfigFlag::InitOnly)) { /* We're not going to activate this, so free whatever data we allocated */ - ClearTemporaryNewGRFData(_cur.grffile); + ClearTemporaryNewGRFData(_cur_gps.grffile); } } } /* Pseudo sprite processing is finished; free temporary stuff */ - _cur.ClearDataForNextFile(); + _cur_gps.ClearDataForNextFile(); /* Call any functions that should be run after GRFs have been loaded. */ AfterLoadGRFs(); diff --git a/src/newgrf/newgrf_act0.cpp b/src/newgrf/newgrf_act0.cpp index 9f13c1e478..6562ff8f8e 100644 --- a/src/newgrf/newgrf_act0.cpp +++ b/src/newgrf/newgrf_act0.cpp @@ -92,12 +92,12 @@ std::vector ReadBadgeList(ByteReader &buf, GrfSpecFeature feature) while (count-- > 0) { uint16_t local_index = buf.ReadWord(); - if (local_index >= std::size(_cur.grffile->badge_list)) { - GrfMsg(1, "ReadBadgeList: Badge label {} out of range (max {}), skipping.", local_index, std::size(_cur.grffile->badge_list) - 1); + if (local_index >= std::size(_cur_gps.grffile->badge_list)) { + GrfMsg(1, "ReadBadgeList: Badge label {} out of range (max {}), skipping.", local_index, std::size(_cur_gps.grffile->badge_list) - 1); continue; } - BadgeID index = _cur.grffile->badge_list[local_index]; + BadgeID index = _cur_gps.grffile->badge_list[local_index]; /* Is badge already present? */ if (std::ranges::find(badges, index) != std::end(badges)) continue; @@ -204,7 +204,7 @@ static void FeatureChangeInfo(ByteReader &buf) } /* Mark the feature as used by the grf */ - SetBit(_cur.grffile->grf_features, feature); + SetBit(_cur_gps.grffile->grf_features, feature); while (numprops-- && buf.HasData()) { uint8_t prop = buf.ReadByte(); diff --git a/src/newgrf/newgrf_act0_aircraft.cpp b/src/newgrf/newgrf_act0_aircraft.cpp index 922d0b6e07..1c614d0d32 100644 --- a/src/newgrf/newgrf_act0_aircraft.cpp +++ b/src/newgrf/newgrf_act0_aircraft.cpp @@ -31,7 +31,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro ChangeInfoResult ret = CIR_SUCCESS; for (uint id = first; id < last; ++id) { - Engine *e = GetNewEngine(_cur.grffile, VEH_AIRCRAFT, id); + Engine *e = GetNewEngine(_cur_gps.grffile, VEH_AIRCRAFT, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -93,14 +93,14 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro break; case 0x12: // SFX - avi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + avi->sfx = GetNewGRFSoundID(_cur_gps.grffile, buf.ReadByte()); break; case 0x13: { // Cargoes available for refitting uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; } @@ -127,7 +127,7 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro case 0x18: // Cargo classes allowed _gted[e->index].cargo_allowed = CargoClasses{buf.ReadWord()}; _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed.Any()); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; case 0x19: // Cargo classes disallowed @@ -151,11 +151,11 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro case 0x1E: { // CTT refit exclude list uint8_t count = buf.ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x1D && count != 0); - if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile; + if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); if (IsValidCargoType(ctype)) SetBit(ctt, ctype); } break; diff --git a/src/newgrf/newgrf_act0_airports.cpp b/src/newgrf/newgrf_act0_airports.cpp index e70a165f15..0063a78361 100644 --- a/src/newgrf/newgrf_act0_airports.cpp +++ b/src/newgrf/newgrf_act0_airports.cpp @@ -35,10 +35,10 @@ static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteR } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->airportspec.size() < last) _cur.grffile->airportspec.resize(last); + if (_cur_gps.grffile->airportspec.size() < last) _cur_gps.grffile->airportspec.resize(last); for (uint id = first; id < last; ++id) { - auto &as = _cur.grffile->airportspec[id]; + auto &as = _cur_gps.grffile->airportspec[id]; if (as == nullptr && prop != 0x08 && prop != 0x09) { GrfMsg(2, "AirportChangeInfo: Attempt to modify undefined airport {}, ignoring", id); @@ -68,9 +68,9 @@ static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteR as->enabled = true; as->grf_prop.local_id = id; as->grf_prop.subst_id = subs_id; - as->grf_prop.SetGRFFile(_cur.grffile); + as->grf_prop.SetGRFFile(_cur_gps.grffile); /* override the default airport */ - _airport_mngr.Add(id, _cur.grffile->grfid, subs_id); + _airport_mngr.Add(id, _cur_gps.grffile->grfid, subs_id); } break; } @@ -107,7 +107,7 @@ static ChangeInfoResult AirportChangeInfo(uint first, uint last, int prop, ByteR int local_tile_id = buf.ReadWord(); /* Read the ID from the _airporttile_mngr. */ - uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur.grffile->grfid); + uint16_t tempid = _airporttile_mngr.GetID(local_tile_id, _cur_gps.grffile->grfid); if (tempid == INVALID_AIRPORTTILE) { GrfMsg(2, "AirportChangeInfo: Attempt to use airport tile {} with airport id {}, not yet defined. Ignoring.", local_tile_id, id); @@ -185,10 +185,10 @@ static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, } /* Allocate airport tile specs if they haven't been allocated already. */ - if (_cur.grffile->airtspec.size() < last) _cur.grffile->airtspec.resize(last); + if (_cur_gps.grffile->airtspec.size() < last) _cur_gps.grffile->airtspec.resize(last); for (uint id = first; id < last; ++id) { - auto &tsp = _cur.grffile->airtspec[id]; + auto &tsp = _cur_gps.grffile->airtspec[id]; if (prop != 0x08 && tsp == nullptr) { GrfMsg(2, "AirportTileChangeInfo: Attempt to modify undefined airport tile {}. Ignoring.", id); @@ -214,8 +214,8 @@ static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, tsp->grf_prop.local_id = id; tsp->grf_prop.subst_id = subs_id; - tsp->grf_prop.SetGRFFile(_cur.grffile); - _airporttile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot + tsp->grf_prop.SetGRFFile(_cur_gps.grffile); + _airporttile_mngr.AddEntityID(id, _cur_gps.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } @@ -229,7 +229,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, continue; } - _airporttile_mngr.Add(id, _cur.grffile->grfid, override_id); + _airporttile_mngr.Add(id, _cur_gps.grffile->grfid, override_id); break; } diff --git a/src/newgrf/newgrf_act0_badges.cpp b/src/newgrf/newgrf_act0_badges.cpp index 3945e802e2..823cf0e0d5 100644 --- a/src/newgrf/newgrf_act0_badges.cpp +++ b/src/newgrf/newgrf_act0_badges.cpp @@ -26,8 +26,8 @@ static ChangeInfoResult BadgeChangeInfo(uint first, uint last, int prop, ByteRea } for (uint id = first; id < last; ++id) { - auto it = _cur.grffile->badge_map.find(id); - if (prop != 0x08 && it == std::end(_cur.grffile->badge_map)) { + auto it = _cur_gps.grffile->badge_map.find(id); + if (prop != 0x08 && it == std::end(_cur_gps.grffile->badge_map)) { GrfMsg(1, "BadgeChangeInfo: Attempt to modify undefined tag {}, ignoring", id); return CIR_INVALID_ID; } @@ -38,7 +38,7 @@ static ChangeInfoResult BadgeChangeInfo(uint first, uint last, int prop, ByteRea switch (prop) { case 0x08: { // Label std::string_view label = buf.ReadString(); - _cur.grffile->badge_map[id] = GetOrCreateBadge(label).index; + _cur_gps.grffile->badge_map[id] = GetOrCreateBadge(label).index; break; } diff --git a/src/newgrf/newgrf_act0_canals.cpp b/src/newgrf/newgrf_act0_canals.cpp index 38d32cdc02..b48c8af3f7 100644 --- a/src/newgrf/newgrf_act0_canals.cpp +++ b/src/newgrf/newgrf_act0_canals.cpp @@ -32,7 +32,7 @@ static ChangeInfoResult CanalChangeInfo(uint first, uint last, int prop, ByteRea } for (uint id = first; id < last; ++id) { - CanalProperties *cp = &_cur.grffile->canal_local_properties[id]; + CanalProperties *cp = &_cur_gps.grffile->canal_local_properties[id]; switch (prop) { case 0x08: diff --git a/src/newgrf/newgrf_act0_cargo.cpp b/src/newgrf/newgrf_act0_cargo.cpp index db111dda06..c5794a2874 100644 --- a/src/newgrf/newgrf_act0_cargo.cpp +++ b/src/newgrf/newgrf_act0_cargo.cpp @@ -40,7 +40,7 @@ static ChangeInfoResult CargoReserveInfo(uint first, uint last, int prop, ByteRe case 0x08: // Bit number of cargo cs->bitnum = buf.ReadByte(); if (cs->IsValid()) { - cs->grffile = _cur.grffile; + cs->grffile = _cur_gps.grffile; SetBit(_cargo_mask, id); } else { ClrBit(_cargo_mask, id); diff --git a/src/newgrf/newgrf_act0_globalvar.cpp b/src/newgrf/newgrf_act0_globalvar.cpp index eb004161cb..837f68da3d 100644 --- a/src/newgrf/newgrf_act0_globalvar.cpp +++ b/src/newgrf/newgrf_act0_globalvar.cpp @@ -49,7 +49,7 @@ static ChangeInfoResult LoadTranslationTable(uint first, uint last, ByteReader & return CIR_INVALID_ID; } - std::vector &translation_table = gettable(*_cur.grffile); + std::vector &translation_table = gettable(*_cur_gps.grffile); translation_table.clear(); translation_table.reserve(last); for (uint id = first; id < last; ++id) { @@ -122,7 +122,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, Byt return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); case 0x18: // Badge translation table - return LoadBadgeTranslationTable(first, last, buf, _cur.grffile->badge_list, "Badge"); + return LoadBadgeTranslationTable(first, last, buf, _cur_gps.grffile->badge_list, "Badge"); default: break; @@ -136,7 +136,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, Byt int factor = buf.ReadByte(); if (id < PR_END) { - _cur.grffile->price_base_multipliers[id] = std::min(factor - 8, MAX_PRICE_MODIFIER); + _cur_gps.grffile->price_base_multipliers[id] = std::min(factor - 8, MAX_PRICE_MODIFIER); } else { GrfMsg(1, "GlobalVarChangeInfo: Price {} out of range, ignoring", id); } @@ -235,7 +235,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, Byt for (uint j = 0; j < SNOW_LINE_DAYS; j++) { uint8_t &level = snow_line->table[i][j]; level = buf.ReadByte(); - if (_cur.grffile->grf_version >= 8) { + if (_cur_gps.grffile->grf_version >= 8) { if (level != 0xFF) level = level * (1 + _settings_game.construction.map_height_limit) / 256; } else { if (level >= 128) { @@ -283,7 +283,7 @@ static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, Byt if (plural_form >= LANGUAGE_MAX_PLURAL) { GrfMsg(1, "GlobalVarChanceInfo: Plural form {} is out of range, ignoring", plural_form); } else { - _cur.grffile->language_map[curidx].plural_form = plural_form; + _cur_gps.grffile->language_map[curidx].plural_form = plural_form; } break; } @@ -306,14 +306,14 @@ static ChangeInfoResult GlobalVarChangeInfo(uint first, uint last, int prop, Byt if (map.openttd_id >= MAX_NUM_GENDERS) { GrfMsg(1, "GlobalVarChangeInfo: Gender name {} is not known, ignoring", StrMakeValid(name)); } else { - _cur.grffile->language_map[curidx].gender_map.push_back(map); + _cur_gps.grffile->language_map[curidx].gender_map.push_back(map); } } else { map.openttd_id = lang->GetCaseIndex(name); if (map.openttd_id >= MAX_NUM_CASES) { GrfMsg(1, "GlobalVarChangeInfo: Case name {} is not known, ignoring", StrMakeValid(name)); } else { - _cur.grffile->language_map[curidx].case_map.push_back(map); + _cur_gps.grffile->language_map[curidx].case_map.push_back(map); } } newgrf_id = buf.ReadByte(); @@ -347,7 +347,7 @@ static ChangeInfoResult GlobalVarReserveInfo(uint first, uint last, int prop, By return LoadTranslationTable(first, last, buf, [](GRFFile &grf) -> std::vector & { return grf.tramtype_list; }, "Tram type"); case 0x18: // Badge translation table - return LoadBadgeTranslationTable(first, last, buf, _cur.grffile->badge_list, "Badge"); + return LoadBadgeTranslationTable(first, last, buf, _cur_gps.grffile->badge_list, "Badge"); default: break; diff --git a/src/newgrf/newgrf_act0_houses.cpp b/src/newgrf/newgrf_act0_houses.cpp index 51996ac3bc..86b5c83910 100644 --- a/src/newgrf/newgrf_act0_houses.cpp +++ b/src/newgrf/newgrf_act0_houses.cpp @@ -103,10 +103,10 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt } /* Allocate house specs if they haven't been allocated already. */ - if (_cur.grffile->housespec.size() < last) _cur.grffile->housespec.resize(last); + if (_cur_gps.grffile->housespec.size() < last) _cur_gps.grffile->housespec.resize(last); for (uint id = first; id < last; ++id) { - auto &housespec = _cur.grffile->housespec[id]; + auto &housespec = _cur_gps.grffile->housespec[id]; if (prop != 0x08 && housespec == nullptr) { /* If the house property 08 is not yet set, ignore this property */ @@ -137,7 +137,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt housespec->enabled = true; housespec->grf_prop.local_id = id; housespec->grf_prop.subst_id = subs_id; - housespec->grf_prop.SetGRFFile(_cur.grffile); + housespec->grf_prop.SetGRFFile(_cur_gps.grffile); /* Set default colours for randomization, used if not overridden. */ housespec->random_colour[0] = COLOUR_RED; housespec->random_colour[1] = COLOUR_BLUE; @@ -233,7 +233,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt continue; } - _house_mngr.Add(id, _cur.grffile->grfid, override_id); + _house_mngr.Add(id, _cur_gps.grffile->grfid, override_id); break; } @@ -264,7 +264,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt break; case 0x1C: // Class of the building type - housespec->class_id = AllocateHouseClassID(buf.ReadByte(), _cur.grffile->grfid); + housespec->class_id = AllocateHouseClassID(buf.ReadByte(), _cur_gps.grffile->grfid); break; case 0x1D: { // Callback mask part 2 @@ -283,7 +283,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt for (uint j = 0; j < HOUSE_ORIGINAL_NUM_ACCEPTS; j++) { /* Get the cargo number from the 'list' */ uint8_t cargo_part = GB(cargotypes, 8 * j, 8); - CargoType cargo = GetCargoTranslation(cargo_part, _cur.grffile); + CargoType cargo = GetCargoTranslation(cargo_part, _cur_gps.grffile); if (!IsValidCargoType(cargo)) { /* Disable acceptance of invalid cargo type */ @@ -303,7 +303,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt case 0x20: { // Cargo acceptance watch list uint8_t count = buf.ReadByte(); for (uint8_t j = 0; j < count; j++) { - CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); if (IsValidCargoType(cargo)) SetBit(housespec->watched_cargoes, cargo); } break; @@ -330,7 +330,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt * any risks of array overrun. */ for (uint i = 0; i < lengthof(housespec->accepts_cargo); i++) { if (i < count) { - housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + housespec->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); housespec->cargo_acceptance[i] = buf.ReadByte(); } else { housespec->accepts_cargo[i] = INVALID_CARGO; diff --git a/src/newgrf/newgrf_act0_industries.cpp b/src/newgrf/newgrf_act0_industries.cpp index 03f4d79ea3..5f46bc3d2f 100644 --- a/src/newgrf/newgrf_act0_industries.cpp +++ b/src/newgrf/newgrf_act0_industries.cpp @@ -79,10 +79,10 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, } /* Allocate industry tile specs if they haven't been allocated already. */ - if (_cur.grffile->indtspec.size() < last) _cur.grffile->indtspec.resize(last); + if (_cur_gps.grffile->indtspec.size() < last) _cur_gps.grffile->indtspec.resize(last); for (uint id = first; id < last; ++id) { - auto &tsp = _cur.grffile->indtspec[id]; + auto &tsp = _cur_gps.grffile->indtspec[id]; if (prop != 0x08 && tsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryTileProperty(prop, buf); @@ -113,8 +113,8 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, tsp->grf_prop.local_id = id; tsp->grf_prop.subst_id = subs_id; - tsp->grf_prop.SetGRFFile(_cur.grffile); - _industile_mngr.AddEntityID(id, _cur.grffile->grfid, subs_id); // pre-reserve the tile slot + tsp->grf_prop.SetGRFFile(_cur_gps.grffile); + _industile_mngr.AddEntityID(id, _cur_gps.grffile->grfid, subs_id); // pre-reserve the tile slot } break; } @@ -128,7 +128,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, continue; } - _industile_mngr.Add(id, _cur.grffile->grfid, ovrid); + _industile_mngr.Add(id, _cur_gps.grffile->grfid, ovrid); break; } @@ -136,7 +136,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, case 0x0B: case 0x0C: { uint16_t acctp = buf.ReadWord(); - tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur.grffile); + tsp->accepts_cargo[prop - 0x0A] = GetCargoTranslation(GB(acctp, 0, 8), _cur_gps.grffile); tsp->acceptance[prop - 0x0A] = Clamp(GB(acctp, 8, 8), 0, 16); tsp->accepts_cargo_label[prop - 0x0A] = CT_INVALID; break; @@ -176,7 +176,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, } for (uint i = 0; i < std::size(tsp->acceptance); i++) { if (i < num_cargoes) { - tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + tsp->accepts_cargo[i] = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); /* Tile acceptance can be negative to counteract the IndustryTileSpecialFlag::AcceptsAllCargo flag */ tsp->acceptance[i] = (int8_t)buf.ReadByte(); } else { @@ -344,10 +344,10 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By } /* Allocate industry specs if they haven't been allocated already. */ - if (_cur.grffile->industryspec.size() < last) _cur.grffile->industryspec.resize(last); + if (_cur_gps.grffile->industryspec.size() < last) _cur_gps.grffile->industryspec.resize(last); for (uint id = first; id < last; ++id) { - auto &indsp = _cur.grffile->industryspec[id]; + auto &indsp = _cur_gps.grffile->industryspec[id]; if (prop != 0x08 && indsp == nullptr) { ChangeInfoResult cir = IgnoreIndustryProperty(prop, buf); @@ -378,7 +378,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By indsp->enabled = true; indsp->grf_prop.local_id = id; indsp->grf_prop.subst_id = subs_id; - indsp->grf_prop.SetGRFFile(_cur.grffile); + indsp->grf_prop.SetGRFFile(_cur_gps.grffile); /* If the grf industry needs to check its surrounding upon creation, it should * rely on callbacks, not on the original placement functions */ indsp->check_proc = CHECK_NOTHING; @@ -395,7 +395,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By continue; } indsp->grf_prop.override_id = ovrid; - _industry_mngr.Add(id, _cur.grffile->grfid, ovrid); + _industry_mngr.Add(id, _cur_gps.grffile->grfid, ovrid); break; } @@ -459,7 +459,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By bytes_read += 2; /* Read the ID from the _industile_mngr. */ - int tempid = _industile_mngr.GetID(local_tile_id, _cur.grffile->grfid); + int tempid = _industile_mngr.GetID(local_tile_id, _cur_gps.grffile->grfid); if (tempid == INVALID_INDUSTRYTILE) { GrfMsg(2, "IndustriesChangeInfo: Attempt to use industry tile {} with industry id {}, not yet defined. Ignoring.", local_tile_id, id); @@ -478,7 +478,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By * Since GRF version 8 the position is interpreted as pair of independent int8. * For GRF version < 8 we need to emulate the old shifting behaviour. */ - if (_cur.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1; + if (_cur_gps.grffile->grf_version < 8 && it.ti.x < 0) it.ti.y += 1; } } @@ -517,14 +517,14 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By case 0x10: // Production cargo types for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_OUTPUTS; j++) { - indsp->produced_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + indsp->produced_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); indsp->produced_cargo_label[j] = CT_INVALID; } break; case 0x11: // Acceptance cargo types for (uint8_t j = 0; j < INDUSTRY_ORIGINAL_NUM_INPUTS; j++) { - indsp->accepts_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + indsp->accepts_cargo[j] = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); indsp->accepts_cargo_label[j] = CT_INVALID; } buf.ReadByte(); // Unnused, eat it up @@ -624,7 +624,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By } for (size_t i = 0; i < std::size(indsp->produced_cargo); i++) { if (i < num_cargoes) { - CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); indsp->produced_cargo[i] = cargo; } else { indsp->produced_cargo[i] = INVALID_CARGO; @@ -643,7 +643,7 @@ static ChangeInfoResult IndustriesChangeInfo(uint first, uint last, int prop, By } for (size_t i = 0; i < std::size(indsp->accepts_cargo); i++) { if (i < num_cargoes) { - CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType cargo = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); indsp->accepts_cargo[i] = cargo; } else { indsp->accepts_cargo[i] = INVALID_CARGO; diff --git a/src/newgrf/newgrf_act0_objects.cpp b/src/newgrf/newgrf_act0_objects.cpp index b83f2fd0bc..fad95d7911 100644 --- a/src/newgrf/newgrf_act0_objects.cpp +++ b/src/newgrf/newgrf_act0_objects.cpp @@ -83,10 +83,10 @@ static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteRe } /* Allocate object specs if they haven't been allocated already. */ - if (_cur.grffile->objectspec.size() < last) _cur.grffile->objectspec.resize(last); + if (_cur_gps.grffile->objectspec.size() < last) _cur_gps.grffile->objectspec.resize(last); for (uint id = first; id < last; ++id) { - auto &spec = _cur.grffile->objectspec[id]; + auto &spec = _cur_gps.grffile->objectspec[id]; if (prop != 0x08 && spec == nullptr) { /* If the object property 08 is not yet set, ignore this property */ diff --git a/src/newgrf/newgrf_act0_railtypes.cpp b/src/newgrf/newgrf_act0_railtypes.cpp index 18ed679f8f..fe9e52132d 100644 --- a/src/newgrf/newgrf_act0_railtypes.cpp +++ b/src/newgrf/newgrf_act0_railtypes.cpp @@ -36,7 +36,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, Byte } for (uint id = first; id < last; ++id) { - RailType rt = _cur.grffile->railtype_map[id]; + RailType rt = _cur_gps.grffile->railtype_map[id]; if (rt == INVALID_RAILTYPE) return CIR_INVALID_ID; RailTypeInfo *rti = &_railtypes[rt]; @@ -50,7 +50,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, Byte case 0x09: { // Toolbar caption of railtype (sets name as well for backwards compatibility for grf ver < 8) GRFStringID str{buf.ReadWord()}; AddStringForMapping(str, &rti->strings.toolbar_caption); - if (_cur.grffile->grf_version < 8) { + if (_cur_gps.grffile->grf_version < 8) { AddStringForMapping(str, &rti->strings.name); } break; @@ -182,7 +182,7 @@ static ChangeInfoResult RailTypeReserveInfo(uint first, uint last, int prop, Byt rt = AllocateRailType(rtl); } - _cur.grffile->railtype_map[id] = rt; + _cur_gps.grffile->railtype_map[id] = rt; break; } @@ -199,10 +199,10 @@ static ChangeInfoResult RailTypeReserveInfo(uint first, uint last, int prop, Byt break; case 0x1D: // Alternate rail type label list - if (_cur.grffile->railtype_map[id] != INVALID_RAILTYPE) { + if (_cur_gps.grffile->railtype_map[id] != INVALID_RAILTYPE) { int n = buf.ReadByte(); for (int j = 0; j != n; j++) { - _railtypes[_cur.grffile->railtype_map[id]].alternate_labels.push_back(std::byteswap(buf.ReadDWord())); + _railtypes[_cur_gps.grffile->railtype_map[id]].alternate_labels.push_back(std::byteswap(buf.ReadDWord())); } break; } diff --git a/src/newgrf/newgrf_act0_roadstops.cpp b/src/newgrf/newgrf_act0_roadstops.cpp index 4ff60db79a..3da28acf04 100644 --- a/src/newgrf/newgrf_act0_roadstops.cpp +++ b/src/newgrf/newgrf_act0_roadstops.cpp @@ -70,10 +70,10 @@ static ChangeInfoResult RoadStopChangeInfo(uint first, uint last, int prop, Byte return CIR_INVALID_ID; } - if (_cur.grffile->roadstops.size() < last) _cur.grffile->roadstops.resize(last); + if (_cur_gps.grffile->roadstops.size() < last) _cur_gps.grffile->roadstops.resize(last); for (uint id = first; id < last; ++id) { - auto &rs = _cur.grffile->roadstops[id]; + auto &rs = _cur_gps.grffile->roadstops[id]; if (rs == nullptr && prop != 0x08) { GrfMsg(1, "RoadStopChangeInfo: Attempt to modify undefined road stop {}, ignoring", id); diff --git a/src/newgrf/newgrf_act0_roadtypes.cpp b/src/newgrf/newgrf_act0_roadtypes.cpp index 795762f1a6..f6b6f48926 100644 --- a/src/newgrf/newgrf_act0_roadtypes.cpp +++ b/src/newgrf/newgrf_act0_roadtypes.cpp @@ -30,7 +30,7 @@ static ChangeInfoResult RoadTypeChangeInfo(uint first, uint last, int prop, Byte ChangeInfoResult ret = CIR_SUCCESS; extern RoadTypeInfo _roadtypes[ROADTYPE_END]; - std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + std::array &type_map = (rtt == RTT_TRAM) ? _cur_gps.grffile->tramtype_map : _cur_gps.grffile->roadtype_map; if (last > ROADTYPE_END) { GrfMsg(1, "RoadTypeChangeInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END); @@ -151,7 +151,7 @@ static ChangeInfoResult RoadTypeReserveInfo(uint first, uint last, int prop, Byt ChangeInfoResult ret = CIR_SUCCESS; extern RoadTypeInfo _roadtypes[ROADTYPE_END]; - std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + std::array &type_map = (rtt == RTT_TRAM) ? _cur_gps.grffile->tramtype_map : _cur_gps.grffile->roadtype_map; if (last > ROADTYPE_END) { GrfMsg(1, "RoadTypeReserveInfo: Road type {} is invalid, max {}, ignoring", last, ROADTYPE_END); diff --git a/src/newgrf/newgrf_act0_roadvehs.cpp b/src/newgrf/newgrf_act0_roadvehs.cpp index c34fd3a96f..aba759f8f7 100644 --- a/src/newgrf/newgrf_act0_roadvehs.cpp +++ b/src/newgrf/newgrf_act0_roadvehs.cpp @@ -32,7 +32,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B ChangeInfoResult ret = CIR_SUCCESS; for (uint id = first; id < last; ++id) { - Engine *e = GetNewEngine(_cur.grffile, VEH_ROAD, id); + Engine *e = GetNewEngine(_cur_gps.grffile, VEH_ROAD, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -80,7 +80,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B break; case 0x10: { // Cargo type - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; uint8_t ctype = buf.ReadByte(); if (ctype == 0xFF) { @@ -88,7 +88,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ - ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); + ei->cargo_type = GetCargoTranslation(ctype, _cur_gps.grffile); if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RoadVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; @@ -100,7 +100,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B break; case 0x12: // SFX - rvi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + rvi->sfx = GetNewGRFSoundID(_cur_gps.grffile, buf.ReadByte()); break; case PROP_ROADVEH_POWER: // Power in units of 10 HP. @@ -119,7 +119,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; } @@ -154,7 +154,7 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B case 0x1D: // Cargo classes allowed _gted[e->index].cargo_allowed = CargoClasses{buf.ReadWord()}; _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed.Any()); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; case 0x1E: // Cargo classes disallowed @@ -192,11 +192,11 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B case 0x25: { // CTT refit exclude list uint8_t count = buf.ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x24 && count != 0); - if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile; + if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); if (IsValidCargoType(ctype)) SetBit(ctt, ctype); } break; diff --git a/src/newgrf/newgrf_act0_ships.cpp b/src/newgrf/newgrf_act0_ships.cpp index 9641212b45..f24be94bda 100644 --- a/src/newgrf/newgrf_act0_ships.cpp +++ b/src/newgrf/newgrf_act0_ships.cpp @@ -33,7 +33,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B ChangeInfoResult ret = CIR_SUCCESS; for (uint id = first; id < last; ++id) { - Engine *e = GetNewEngine(_cur.grffile, VEH_SHIP, id); + Engine *e = GetNewEngine(_cur_gps.grffile, VEH_SHIP, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -71,7 +71,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B break; case 0x0C: { // Cargo type - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; uint8_t ctype = buf.ReadByte(); if (ctype == 0xFF) { @@ -79,7 +79,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ - ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); + ei->cargo_type = GetCargoTranslation(ctype, _cur_gps.grffile); if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; @@ -95,14 +95,14 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B break; case 0x10: // SFX - svi->sfx = GetNewGRFSoundID(_cur.grffile, buf.ReadByte()); + svi->sfx = GetNewGRFSoundID(_cur_gps.grffile, buf.ReadByte()); break; case 0x11: { // Cargoes available for refitting uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; } @@ -137,7 +137,7 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B case 0x18: // Cargo classes allowed _gted[e->index].cargo_allowed = CargoClasses{buf.ReadWord()}; _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed.Any()); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; case 0x19: // Cargo classes disallowed @@ -171,11 +171,11 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B case 0x1F: { // CTT refit exclude list uint8_t count = buf.ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x1E && count != 0); - if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile; + if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); if (IsValidCargoType(ctype)) SetBit(ctt, ctype); } break; diff --git a/src/newgrf/newgrf_act0_sounds.cpp b/src/newgrf/newgrf_act0_sounds.cpp index d74bb4b45b..7f5c5300e6 100644 --- a/src/newgrf/newgrf_act0_sounds.cpp +++ b/src/newgrf/newgrf_act0_sounds.cpp @@ -27,18 +27,18 @@ static ChangeInfoResult SoundEffectChangeInfo(uint first, uint last, int prop, B { ChangeInfoResult ret = CIR_SUCCESS; - if (_cur.grffile->sound_offset == 0) { + if (_cur_gps.grffile->sound_offset == 0) { GrfMsg(1, "SoundEffectChangeInfo: No effects defined, skipping"); return CIR_INVALID_ID; } - if (last - ORIGINAL_SAMPLE_COUNT > _cur.grffile->num_sounds) { - GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", last, ORIGINAL_SAMPLE_COUNT + _cur.grffile->num_sounds); + if (last - ORIGINAL_SAMPLE_COUNT > _cur_gps.grffile->num_sounds) { + GrfMsg(1, "SoundEffectChangeInfo: Attempting to change undefined sound effect ({}), max ({}). Ignoring.", last, ORIGINAL_SAMPLE_COUNT + _cur_gps.grffile->num_sounds); return CIR_INVALID_ID; } for (uint id = first; id < last; ++id) { - SoundEntry *sound = GetSound(first + _cur.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT); + SoundEntry *sound = GetSound(first + _cur_gps.grffile->sound_offset - ORIGINAL_SAMPLE_COUNT); switch (prop) { case 0x08: // Relative volume diff --git a/src/newgrf/newgrf_act0_stations.cpp b/src/newgrf/newgrf_act0_stations.cpp index 97bbcbef2b..3041060040 100644 --- a/src/newgrf/newgrf_act0_stations.cpp +++ b/src/newgrf/newgrf_act0_stations.cpp @@ -37,10 +37,10 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR } /* Allocate station specs if necessary */ - if (_cur.grffile->stations.size() < last) _cur.grffile->stations.resize(last); + if (_cur_gps.grffile->stations.size() < last) _cur_gps.grffile->stations.resize(last); for (uint id = first; id < last; ++id) { - auto &statspec = _cur.grffile->stations[id]; + auto &statspec = _cur_gps.grffile->stations[id]; /* Check that the station we are modifying is defined. */ if (statspec == nullptr && prop != 0x08) { @@ -81,7 +81,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR ReadSpriteLayoutSprite(buf, false, false, false, GSF_STATIONS, &dts->ground); /* On error, bail out immediately. Temporary GRF data was already freed */ - if (_cur.skip_sprites < 0) return CIR_DISABLED; + if (_cur_gps.skip_sprites < 0) return CIR_DISABLED; std::vector tmp_layout; for (;;) { @@ -99,7 +99,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR ReadSpriteLayoutSprite(buf, false, true, false, GSF_STATIONS, &dtss.image); /* On error, bail out immediately. Temporary GRF data was already freed */ - if (_cur.skip_sprites < 0) return CIR_DISABLED; + if (_cur_gps.skip_sprites < 0) return CIR_DISABLED; } dts->seq = std::move(tmp_layout); } @@ -114,7 +114,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR case 0x0A: { // Copy sprite layout uint16_t srcid = buf.ReadExtendedByte(); - const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get(); + const StationSpec *srcstatspec = srcid >= _cur_gps.grffile->stations.size() ? nullptr : _cur_gps.grffile->stations[srcid].get(); if (srcstatspec == nullptr) { GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy sprite layout to {}.", srcid, id); @@ -167,7 +167,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR case 0x0F: { // Copy custom layout uint16_t srcid = buf.ReadExtendedByte(); - const StationSpec *srcstatspec = srcid >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[srcid].get(); + const StationSpec *srcstatspec = srcid >= _cur_gps.grffile->stations.size() ? nullptr : _cur_gps.grffile->stations[srcid].get(); if (srcstatspec == nullptr) { GrfMsg(1, "StationChangeInfo: Station {} is not defined, cannot copy tile layout to {}.", srcid, id); @@ -196,7 +196,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR } case 0x12: // Cargo types for random triggers - if (_cur.grffile->grf_version >= 7) { + if (_cur_gps.grffile->grf_version >= 7) { statspec->cargo_triggers = TranslateRefitMask(buf.ReadDWord()); } else { statspec->cargo_triggers = (CargoTypes)buf.ReadDWord(); diff --git a/src/newgrf/newgrf_act0_trains.cpp b/src/newgrf/newgrf_act0_trains.cpp index 7840f63e6e..29fa3e473a 100644 --- a/src/newgrf/newgrf_act0_trains.cpp +++ b/src/newgrf/newgrf_act0_trains.cpp @@ -31,7 +31,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead ChangeInfoResult ret = CIR_SUCCESS; for (uint id = first; id < last; ++id) { - Engine *e = GetNewEngine(_cur.grffile, VEH_TRAIN, id); + Engine *e = GetNewEngine(_cur_gps.grffile, VEH_TRAIN, id); if (e == nullptr) return CIR_INVALID_ID; // No engine could be allocated, so neither can any next vehicles EngineInfo *ei = &e->info; @@ -41,8 +41,8 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead case 0x05: { // Track type uint8_t tracktype = buf.ReadByte(); - if (tracktype < _cur.grffile->railtype_list.size()) { - _gted[e->index].railtypelabel = _cur.grffile->railtype_list[tracktype]; + if (tracktype < _cur_gps.grffile->railtype_list.size()) { + _gted[e->index].railtypelabel = _cur_gps.grffile->railtype_list[tracktype]; break; } @@ -126,7 +126,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead break; case 0x15: { // Cargo type - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; uint8_t ctype = buf.ReadByte(); if (ctype == 0xFF) { @@ -134,7 +134,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead ei->cargo_type = INVALID_CARGO; } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ - ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); + ei->cargo_type = GetCargoTranslation(ctype, _cur_gps.grffile); if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; @@ -179,7 +179,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead break; } - if (_cur.grffile->railtype_list.empty()) { + if (_cur_gps.grffile->railtype_list.empty()) { /* Use traction type to select between normal and electrified * rail only when no translation list is in place. */ if (_gted[e->index].railtypelabel == RAILTYPE_LABEL_RAIL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_LABEL_ELECTRIC; @@ -206,7 +206,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead uint32_t mask = buf.ReadDWord(); _gted[e->index].UpdateRefittability(mask != 0); ei->refit_mask = TranslateRefitMask(mask); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; } @@ -270,7 +270,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead case 0x28: // Cargo classes allowed _gted[e->index].cargo_allowed = CargoClasses{buf.ReadWord()}; _gted[e->index].UpdateRefittability(_gted[e->index].cargo_allowed.Any()); - _gted[e->index].defaultcargo_grf = _cur.grffile; + _gted[e->index].defaultcargo_grf = _cur_gps.grffile; break; case 0x29: // Cargo classes disallowed @@ -290,11 +290,11 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead case 0x2D: { // CTT refit exclude list uint8_t count = buf.ReadByte(); _gted[e->index].UpdateRefittability(prop == 0x2C && count != 0); - if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile; + if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur_gps.grffile; CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask; ctt = 0; while (count--) { - CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur.grffile); + CargoType ctype = GetCargoTranslation(buf.ReadByte(), _cur_gps.grffile); if (IsValidCargoType(ctype)) SetBit(ctt, ctype); } break; diff --git a/src/newgrf/newgrf_act1.cpp b/src/newgrf/newgrf_act1.cpp index 21ff5c658f..2336dcc57d 100644 --- a/src/newgrf/newgrf_act1.cpp +++ b/src/newgrf/newgrf_act1.cpp @@ -45,20 +45,20 @@ static void NewSpriteSet(ByteReader &buf) uint16_t num_ents = buf.ReadExtendedByte(); if (feature >= GSF_END) { - _cur.skip_sprites = num_sets * num_ents; - GrfMsg(1, "NewSpriteSet: Unsupported feature 0x{:02X}, skipping {} sprites", feature, _cur.skip_sprites); + _cur_gps.skip_sprites = num_sets * num_ents; + GrfMsg(1, "NewSpriteSet: Unsupported feature 0x{:02X}, skipping {} sprites", feature, _cur_gps.skip_sprites); return; } - _cur.AddSpriteSets(feature, _cur.spriteid, first_set, num_sets, num_ents); + _cur_gps.AddSpriteSets(feature, _cur_gps.spriteid, first_set, num_sets, num_ents); GrfMsg(7, "New sprite set at {} of feature 0x{:02X}, consisting of {} sets with {} views each (total {})", - _cur.spriteid, feature, num_sets, num_ents, num_sets * num_ents + _cur_gps.spriteid, feature, num_sets, num_ents, num_sets * num_ents ); for (int i = 0; i < num_sets * num_ents; i++) { - _cur.nfo_line++; - LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line); + _cur_gps.nfo_line++; + LoadNextSprite(_cur_gps.spriteid++, *_cur_gps.file, _cur_gps.nfo_line); } } @@ -76,9 +76,9 @@ static void SkipAct1(ByteReader &buf) } uint16_t num_ents = buf.ReadExtendedByte(); - _cur.skip_sprites = num_sets * num_ents; + _cur_gps.skip_sprites = num_sets * num_ents; - GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur.skip_sprites); + GrfMsg(3, "SkipAct1: Skipping {} sprites", _cur_gps.skip_sprites); } template <> void GrfActionHandler<0x01>::FileScan(ByteReader &buf) { SkipAct1(buf); } diff --git a/src/newgrf/newgrf_act10.cpp b/src/newgrf/newgrf_act10.cpp index bb9cbb5cb3..7c41d7cb0c 100644 --- a/src/newgrf/newgrf_act10.cpp +++ b/src/newgrf/newgrf_act10.cpp @@ -24,7 +24,7 @@ static void DefineGotoLabel(ByteReader &buf) uint8_t nfo_label = buf.ReadByte(); - _cur.grffile->labels.emplace_back(nfo_label, _cur.nfo_line, _cur.file->GetPos()); + _cur_gps.grffile->labels.emplace_back(nfo_label, _cur_gps.nfo_line, _cur_gps.file->GetPos()); GrfMsg(2, "DefineGotoLabel: GOTO target with label 0x{:02X}", nfo_label); } diff --git a/src/newgrf/newgrf_act11.cpp b/src/newgrf/newgrf_act11.cpp index 9d1fc766f2..fd1dc38029 100644 --- a/src/newgrf/newgrf_act11.cpp +++ b/src/newgrf/newgrf_act11.cpp @@ -24,8 +24,8 @@ static void ImportGRFSound(SoundEntry *sound) { const GRFFile *file; - uint32_t grfid = _cur.file->ReadDword(); - SoundID sound_id = _cur.file->ReadWord(); + uint32_t grfid = _cur_gps.file->ReadDword(); + SoundID sound_id = _cur_gps.file->ReadWord(); file = GetFileByGRFID(grfid); if (file == nullptr || file->sound_offset == 0) { @@ -60,10 +60,10 @@ static void LoadGRFSound(size_t offs, SoundEntry *sound) if (offs != SIZE_MAX) { /* Sound is present in the NewGRF. */ - sound->file = _cur.file; + sound->file = _cur_gps.file; sound->file_offset = offs; sound->source = SoundSource::NewGRF; - sound->grf_container_ver = _cur.file->GetContainerVersion(); + sound->grf_container_ver = _cur_gps.file->GetContainerVersion(); } } @@ -78,22 +78,22 @@ static void GRFSound(ByteReader &buf) if (num == 0) return; SoundEntry *sound; - if (_cur.grffile->sound_offset == 0) { - _cur.grffile->sound_offset = GetNumSounds(); - _cur.grffile->num_sounds = num; + if (_cur_gps.grffile->sound_offset == 0) { + _cur_gps.grffile->sound_offset = GetNumSounds(); + _cur_gps.grffile->num_sounds = num; sound = AllocateSound(num); } else { - sound = GetSound(_cur.grffile->sound_offset); + sound = GetSound(_cur_gps.grffile->sound_offset); } - SpriteFile &file = *_cur.file; + SpriteFile &file = *_cur_gps.file; uint8_t grf_container_version = file.GetContainerVersion(); for (int i = 0; i < num; i++) { - _cur.nfo_line++; + _cur_gps.nfo_line++; /* Check whether the index is in range. This might happen if multiple action 11 are present. * While this is invalid, we do not check for this. But we should prevent it from causing bigger trouble */ - bool invalid = i >= _cur.grffile->num_sounds; + bool invalid = i >= _cur_gps.grffile->num_sounds; size_t offs = file.GetPos(); @@ -110,7 +110,7 @@ static void GRFSound(ByteReader &buf) file.SkipBytes(len); } else { uint32_t id = file.ReadDword(); - if (_cur.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i); + if (_cur_gps.stage == GLS_INIT) LoadGRFSound(GetGRFSpriteOffset(id), sound + i); } continue; } @@ -118,7 +118,7 @@ static void GRFSound(ByteReader &buf) if (type != 0xFF) { GrfMsg(1, "GRFSound: Unexpected RealSprite found, skipping"); file.SkipBytes(7); - SkipSpriteData(*_cur.file, type, len - 8); + SkipSpriteData(*_cur_gps.file, type, len - 8); continue; } @@ -131,7 +131,7 @@ static void GRFSound(ByteReader &buf) switch (action) { case 0xFF: /* Allocate sound only in init stage. */ - if (_cur.stage == GLS_INIT) { + if (_cur_gps.stage == GLS_INIT) { if (grf_container_version >= 2) { GrfMsg(1, "GRFSound: Inline sounds are not supported for container version >= 2"); } else { @@ -142,7 +142,7 @@ static void GRFSound(ByteReader &buf) break; case 0xFE: - if (_cur.stage == GLS_ACTIVATION) { + if (_cur_gps.stage == GLS_ACTIVATION) { /* XXX 'Action 0xFE' isn't really specified. It is only mentioned for * importing sounds, so this is probably all wrong... */ if (file.ReadByte() != 0) GrfMsg(1, "GRFSound: Import type mismatch"); @@ -167,9 +167,9 @@ static void SkipAct11(ByteReader &buf) * * W num Number of sound files that follow */ - _cur.skip_sprites = buf.ReadWord(); + _cur_gps.skip_sprites = buf.ReadWord(); - GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur.skip_sprites); + GrfMsg(3, "SkipAct11: Skipping {} sprites", _cur_gps.skip_sprites); } template <> void GrfActionHandler<0x11>::FileScan(ByteReader &buf) { SkipAct11(buf); } diff --git a/src/newgrf/newgrf_act12.cpp b/src/newgrf/newgrf_act12.cpp index 65d2b2825f..2e0250775b 100644 --- a/src/newgrf/newgrf_act12.cpp +++ b/src/newgrf/newgrf_act12.cpp @@ -39,9 +39,9 @@ static void LoadFontGlyph(ByteReader &buf) GrfMsg(7, "LoadFontGlyph: Loading {} glyph(s) at 0x{:04X} for size {}", num_char, base_char, size); for (uint c = 0; c < num_char; c++) { - if (size < FS_END) SetUnicodeGlyph(size, base_char + c, _cur.spriteid); - _cur.nfo_line++; - LoadNextSprite(_cur.spriteid++, *_cur.file, _cur.nfo_line); + if (size < FS_END) SetUnicodeGlyph(size, base_char + c, _cur_gps.spriteid); + _cur_gps.nfo_line++; + LoadNextSprite(_cur_gps.spriteid++, *_cur_gps.file, _cur_gps.nfo_line); } } } @@ -63,13 +63,13 @@ static void SkipAct12(ByteReader &buf) buf.ReadByte(); /* Sum up number of characters */ - _cur.skip_sprites += buf.ReadByte(); + _cur_gps.skip_sprites += buf.ReadByte(); /* Ignore 'base_char' word */ buf.ReadWord(); } - GrfMsg(3, "SkipAct12: Skipping {} sprites", _cur.skip_sprites); + GrfMsg(3, "SkipAct12: Skipping {} sprites", _cur_gps.skip_sprites); } template <> void GrfActionHandler<0x12>::FileScan(ByteReader &buf) { SkipAct12(buf); } diff --git a/src/newgrf/newgrf_act13.cpp b/src/newgrf/newgrf_act13.cpp index 9f8f08beb0..d9bcab51e7 100644 --- a/src/newgrf/newgrf_act13.cpp +++ b/src/newgrf/newgrf_act13.cpp @@ -50,7 +50,7 @@ static void TranslateGRFStrings(ByteReader &buf) * new_scheme has to be true as well, which will also be implicitly the case for version 8 * and higher. A language id of 0x7F will be overridden by a non-generic id, so this will * not change anything if a string has been provided specifically for this language. */ - uint8_t language = _cur.grffile->grf_version >= 8 ? buf.ReadByte() : 0x7F; + uint8_t language = _cur_gps.grffile->grf_version >= 8 ? buf.ReadByte() : 0x7F; uint8_t num_strings = buf.ReadByte(); uint16_t first_id = buf.ReadWord(); diff --git a/src/newgrf/newgrf_act14.cpp b/src/newgrf/newgrf_act14.cpp index 3d7ae47570..824cb58905 100644 --- a/src/newgrf/newgrf_act14.cpp +++ b/src/newgrf/newgrf_act14.cpp @@ -18,21 +18,21 @@ /** Callback function for 'INFO'->'NAME' to add a translation to the newgrf name. */ static bool ChangeGRFName(uint8_t langid, std::string_view str) { - AddGRFTextToList(_cur.grfconfig->name, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur_gps.grfconfig->name, langid, _cur_gps.grfconfig->ident.grfid, false, str); return true; } /** Callback function for 'INFO'->'DESC' to add a translation to the newgrf description. */ static bool ChangeGRFDescription(uint8_t langid, std::string_view str) { - AddGRFTextToList(_cur.grfconfig->info, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur_gps.grfconfig->info, langid, _cur_gps.grfconfig->ident.grfid, true, str); return true; } /** Callback function for 'INFO'->'URL_' to set the newgrf url. */ static bool ChangeGRFURL(uint8_t langid, std::string_view str) { - AddGRFTextToList(_cur.grfconfig->url, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur_gps.grfconfig->url, langid, _cur_gps.grfconfig->ident.grfid, false, str); return true; } @@ -43,7 +43,7 @@ static bool ChangeGRFNumUsedParams(size_t len, ByteReader &buf) GrfMsg(2, "StaticGRFInfo: expected only 1 byte for 'INFO'->'NPAR' but got {}, ignoring this field", len); buf.Skip(len); } else { - _cur.grfconfig->num_valid_params = std::min(buf.ReadByte(), GRFConfig::MAX_NUM_PARAMS); + _cur_gps.grfconfig->num_valid_params = std::min(buf.ReadByte(), GRFConfig::MAX_NUM_PARAMS); } return true; } @@ -67,8 +67,8 @@ static bool ChangeGRFPalette(size_t len, ByteReader &buf) break; } if (pal != GRFP_GRF_UNSET) { - _cur.grfconfig->palette &= ~GRFP_GRF_MASK; - _cur.grfconfig->palette |= pal; + _cur_gps.grfconfig->palette &= ~GRFP_GRF_MASK; + _cur_gps.grfconfig->palette |= pal; } } return true; @@ -90,8 +90,8 @@ static bool ChangeGRFBlitter(size_t len, ByteReader &buf) GrfMsg(2, "StaticGRFInfo: unexpected value '{:02X}' for 'INFO'->'BLTR', ignoring this field", data); return true; } - _cur.grfconfig->palette &= ~GRFP_BLT_MASK; - _cur.grfconfig->palette |= pal; + _cur_gps.grfconfig->palette &= ~GRFP_BLT_MASK; + _cur_gps.grfconfig->palette |= pal; } return true; } @@ -104,7 +104,7 @@ static bool ChangeGRFVersion(size_t len, ByteReader &buf) buf.Skip(len); } else { /* Set min_loadable_version as well (default to minimal compatibility) */ - _cur.grfconfig->version = _cur.grfconfig->min_loadable_version = buf.ReadDWord(); + _cur_gps.grfconfig->version = _cur_gps.grfconfig->min_loadable_version = buf.ReadDWord(); } return true; } @@ -116,14 +116,14 @@ static bool ChangeGRFMinVersion(size_t len, ByteReader &buf) GrfMsg(2, "StaticGRFInfo: expected 4 bytes for 'INFO'->'MINV' but got {}, ignoring this field", len); buf.Skip(len); } else { - _cur.grfconfig->min_loadable_version = buf.ReadDWord(); - if (_cur.grfconfig->version == 0) { + _cur_gps.grfconfig->min_loadable_version = buf.ReadDWord(); + if (_cur_gps.grfconfig->version == 0) { GrfMsg(2, "StaticGRFInfo: 'MINV' defined before 'VRSN' or 'VRSN' set to 0, ignoring this field"); - _cur.grfconfig->min_loadable_version = 0; + _cur_gps.grfconfig->min_loadable_version = 0; } - if (_cur.grfconfig->version < _cur.grfconfig->min_loadable_version) { - GrfMsg(2, "StaticGRFInfo: 'MINV' defined as {}, limiting it to 'VRSN'", _cur.grfconfig->min_loadable_version); - _cur.grfconfig->min_loadable_version = _cur.grfconfig->version; + if (_cur_gps.grfconfig->version < _cur_gps.grfconfig->min_loadable_version) { + GrfMsg(2, "StaticGRFInfo: 'MINV' defined as {}, limiting it to 'VRSN'", _cur_gps.grfconfig->min_loadable_version); + _cur_gps.grfconfig->min_loadable_version = _cur_gps.grfconfig->version; } } return true; @@ -134,14 +134,14 @@ static GRFParameterInfo *_cur_parameter; ///< The parameter which info is curren /** Callback function for 'INFO'->'PARAM'->param_num->'NAME' to set the name of a parameter. */ static bool ChangeGRFParamName(uint8_t langid, std::string_view str) { - AddGRFTextToList(_cur_parameter->name, langid, _cur.grfconfig->ident.grfid, false, str); + AddGRFTextToList(_cur_parameter->name, langid, _cur_gps.grfconfig->ident.grfid, false, str); return true; } /** Callback function for 'INFO'->'PARAM'->param_num->'DESC' to set the description of a parameter. */ static bool ChangeGRFParamDescription(uint8_t langid, std::string_view str) { - AddGRFTextToList(_cur_parameter->desc, langid, _cur.grfconfig->ident.grfid, true, str); + AddGRFTextToList(_cur_parameter->desc, langid, _cur_gps.grfconfig->ident.grfid, true, str); return true; } @@ -214,7 +214,7 @@ static bool ChangeGRFParamDefault(size_t len, ByteReader &buf) } else { _cur_parameter->def_value = buf.ReadDWord(); } - _cur.grfconfig->has_param_defaults = true; + _cur_gps.grfconfig->has_param_defaults = true; return true; } @@ -265,7 +265,7 @@ static bool ChangeGRFParamValueNames(ByteReader &buf) if (it == std::end(_cur_parameter->value_names) || it->first != id) { it = _cur_parameter->value_names.emplace(it, id, GRFTextList{}); } - AddGRFTextToList(it->second, langid, _cur.grfconfig->ident.grfid, false, name_string); + AddGRFTextToList(it->second, langid, _cur_gps.grfconfig->ident.grfid, false, name_string); type = buf.ReadByte(); } @@ -294,20 +294,20 @@ static bool HandleParameterInfo(ByteReader &buf) uint8_t type = buf.ReadByte(); while (type != 0) { uint32_t id = buf.ReadDWord(); - if (type != 'C' || id >= _cur.grfconfig->num_valid_params) { + if (type != 'C' || id >= _cur_gps.grfconfig->num_valid_params) { GrfMsg(2, "StaticGRFInfo: all child nodes of 'INFO'->'PARA' should have type 'C' and their parameter number as id"); if (!SkipUnknownInfo(buf, type)) return false; type = buf.ReadByte(); continue; } - if (id >= _cur.grfconfig->param_info.size()) { - _cur.grfconfig->param_info.resize(id + 1); + if (id >= _cur_gps.grfconfig->param_info.size()) { + _cur_gps.grfconfig->param_info.resize(id + 1); } - if (!_cur.grfconfig->param_info[id].has_value()) { - _cur.grfconfig->param_info[id] = GRFParameterInfo(id); + if (!_cur_gps.grfconfig->param_info[id].has_value()) { + _cur_gps.grfconfig->param_info[id] = GRFParameterInfo(id); } - _cur_parameter = &_cur.grfconfig->param_info[id].value(); + _cur_parameter = &_cur_gps.grfconfig->param_info[id].value(); /* Read all parameter-data and process each node. */ if (!HandleNodes(buf, _tags_parameters)) return false; type = buf.ReadByte(); diff --git a/src/newgrf/newgrf_act2.cpp b/src/newgrf/newgrf_act2.cpp index acbafcc94e..8c9642b649 100644 --- a/src/newgrf/newgrf_act2.cpp +++ b/src/newgrf/newgrf_act2.cpp @@ -70,13 +70,13 @@ TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool in if (custom_sprite) { /* Use sprite from Action 1 */ uint index = GB(grf_sprite->sprite, 0, 14); - if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) { + if (use_cur_spritesets && (!_cur_gps.IsValidSpriteSet(feature, index) || _cur_gps.GetNumEnts(feature, index) == 0)) { GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {}", index); grf_sprite->sprite = SPR_IMG_QUERY; grf_sprite->pal = PAL_NONE; } else { - SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; - if (max_sprite_offset != nullptr) *max_sprite_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; + SpriteID sprite = use_cur_spritesets ? _cur_gps.GetSprite(feature, index) : index; + if (max_sprite_offset != nullptr) *max_sprite_offset = use_cur_spritesets ? _cur_gps.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->sprite, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->sprite, SPRITE_MODIFIER_CUSTOM_SPRITE); } @@ -89,12 +89,12 @@ TileLayoutFlags ReadSpriteLayoutSprite(ByteReader &buf, bool read_flags, bool in if (flags & TLF_CUSTOM_PALETTE) { /* Use palette from Action 1 */ uint index = GB(grf_sprite->pal, 0, 14); - if (use_cur_spritesets && (!_cur.IsValidSpriteSet(feature, index) || _cur.GetNumEnts(feature, index) == 0)) { + if (use_cur_spritesets && (!_cur_gps.IsValidSpriteSet(feature, index) || _cur_gps.GetNumEnts(feature, index) == 0)) { GrfMsg(1, "ReadSpriteLayoutSprite: Spritelayout uses undefined custom spriteset {} for 'palette'", index); grf_sprite->pal = PAL_NONE; } else { - SpriteID sprite = use_cur_spritesets ? _cur.GetSprite(feature, index) : index; - if (max_palette_offset != nullptr) *max_palette_offset = use_cur_spritesets ? _cur.GetNumEnts(feature, index) : UINT16_MAX; + SpriteID sprite = use_cur_spritesets ? _cur_gps.GetSprite(feature, index) : index; + if (max_palette_offset != nullptr) *max_palette_offset = use_cur_spritesets ? _cur_gps.GetNumEnts(feature, index) : UINT16_MAX; SB(grf_sprite->pal, 0, SPRITE_WIDTH, sprite); SetBit(grf_sprite->pal, SPRITE_MODIFIER_CUSTOM_SPRITE); } @@ -181,7 +181,7 @@ bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_s /* Groundsprite */ TileLayoutFlags flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &dts->ground, max_sprite_offset.data(), max_palette_offset.data()); - if (_cur.skip_sprites < 0) return true; + if (_cur_gps.skip_sprites < 0) return true; if (flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)) { GrfMsg(1, "ReadSpriteLayout: Spritelayout uses invalid flag 0x{:X} for ground sprite", flags & ~(valid_flags & ~TLF_NON_GROUND_FLAGS)); @@ -190,13 +190,13 @@ bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_s } ReadSpriteLayoutRegisters(buf, flags, false, dts, 0); - if (_cur.skip_sprites < 0) return true; + if (_cur_gps.skip_sprites < 0) return true; for (uint i = 0; i < num_building_sprites; i++) { DrawTileSeqStruct *seq = const_cast(&dts->seq[i]); flags = ReadSpriteLayoutSprite(buf, has_flags, false, use_cur_spritesets, feature, &seq->image, max_sprite_offset.data() + i + 1, max_palette_offset.data() + i + 1); - if (_cur.skip_sprites < 0) return true; + if (_cur_gps.skip_sprites < 0) return true; if (flags & ~valid_flags) { GrfMsg(1, "ReadSpriteLayout: Spritelayout uses unknown flag 0x{:X}", flags & ~valid_flags); @@ -216,7 +216,7 @@ bool ReadSpriteLayout(ByteReader &buf, uint num_building_sprites, bool use_cur_s } ReadSpriteLayoutRegisters(buf, flags, seq->IsParentSprite(), dts, i + 1); - if (_cur.skip_sprites < 0) return true; + if (_cur_gps.skip_sprites < 0) return true; } /* Check if the number of sprites per spriteset is consistent */ @@ -271,7 +271,7 @@ static const SpriteGroup *GetCallbackResultGroup(uint16_t value) { /* Old style callback results (only valid for version < 8) have the highest byte 0xFF to signify it is a callback result. * New style ones only have the highest bit set (allows 15-bit results, instead of just 8) */ - if (_cur.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) { + if (_cur_gps.grffile->grf_version < 8 && GB(value, 8, 8) == 0xFF) { value &= ~0xFF00; } else { value &= ~0x8000; @@ -294,12 +294,12 @@ static const SpriteGroup *GetGroupFromGroupID(uint8_t setid, uint8_t type, uint1 { if (HasBit(groupid, 15)) return GetCallbackResultGroup(groupid); - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { + if (groupid > MAX_SPRITEGROUP || _cur_gps.spritegroups[groupid] == nullptr) { GrfMsg(1, "GetGroupFromGroupID(0x{:02X}:0x{:02X}): Groupid 0x{:04X} does not exist, leaving empty", setid, type, groupid); return nullptr; } - return _cur.spritegroups[groupid]; + return _cur_gps.spritegroups[groupid]; } /** @@ -314,16 +314,16 @@ static const SpriteGroup *CreateGroupFromGroupID(uint8_t feature, uint8_t setid, { if (HasBit(spriteid, 15)) return GetCallbackResultGroup(spriteid); - if (!_cur.IsValidSpriteSet(feature, spriteid)) { + if (!_cur_gps.IsValidSpriteSet(feature, spriteid)) { GrfMsg(1, "CreateGroupFromGroupID(0x{:02X}:0x{:02X}): Sprite set {} invalid", setid, type, spriteid); return nullptr; } - SpriteID spriteset_start = _cur.GetSprite(feature, spriteid); - uint num_sprites = _cur.GetNumEnts(feature, spriteid); + SpriteID spriteset_start = _cur_gps.GetSprite(feature, spriteid); + uint num_sprites = _cur_gps.GetNumEnts(feature, spriteid); /* Ensure that the sprites are loeded */ - assert(spriteset_start + num_sprites <= _cur.spriteid); + assert(spriteset_start + num_sprites <= _cur_gps.spriteid); assert(ResultSpriteGroup::CanAllocateItem()); return new ResultSpriteGroup(spriteset_start, num_sprites); @@ -371,7 +371,7 @@ static void NewSpriteGroup(ByteReader &buf) assert(DeterministicSpriteGroup::CanAllocateItem()); DeterministicSpriteGroup *group = new DeterministicSpriteGroup(); - group->nfo_line = _cur.nfo_line; + group->nfo_line = _cur_gps.nfo_line; act_group = group; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; @@ -475,7 +475,7 @@ static void NewSpriteGroup(ByteReader &buf) { assert(RandomizedSpriteGroup::CanAllocateItem()); RandomizedSpriteGroup *group = new RandomizedSpriteGroup(); - group->nfo_line = _cur.nfo_line; + group->nfo_line = _cur_gps.nfo_line; act_group = group; group->var_scope = HasBit(type, 1) ? VSG_SCOPE_PARENT : VSG_SCOPE_SELF; @@ -522,7 +522,7 @@ static void NewSpriteGroup(ByteReader &buf) uint8_t num_loaded = type; uint8_t num_loading = buf.ReadByte(); - if (!_cur.HasValidSpriteSets(feature)) { + if (!_cur_gps.HasValidSpriteSets(feature)) { GrfMsg(0, "NewSpriteGroup: No sprite set to work on! Skipping"); return; } @@ -569,7 +569,7 @@ static void NewSpriteGroup(ByteReader &buf) assert(RealSpriteGroup::CanAllocateItem()); RealSpriteGroup *group = new RealSpriteGroup(); - group->nfo_line = _cur.nfo_line; + group->nfo_line = _cur_gps.nfo_line; act_group = group; if (loaded_same && loaded.size() > 1) loaded.resize(1); @@ -598,7 +598,7 @@ static void NewSpriteGroup(ByteReader &buf) assert(TileLayoutSpriteGroup::CanAllocateItem()); TileLayoutSpriteGroup *group = new TileLayoutSpriteGroup(); - group->nfo_line = _cur.nfo_line; + group->nfo_line = _cur_gps.nfo_line; act_group = group; /* On error, bail out immediately. Temporary GRF data was already freed */ @@ -614,7 +614,7 @@ static void NewSpriteGroup(ByteReader &buf) assert(IndustryProductionSpriteGroup::CanAllocateItem()); IndustryProductionSpriteGroup *group = new IndustryProductionSpriteGroup(); - group->nfo_line = _cur.nfo_line; + group->nfo_line = _cur_gps.nfo_line; act_group = group; group->version = type; if (type == 0) { @@ -646,7 +646,7 @@ static void NewSpriteGroup(ByteReader &buf) } for (uint i = 0; i < group->num_input; i++) { uint8_t rawcargo = buf.ReadByte(); - CargoType cargo = GetCargoTranslation(rawcargo, _cur.grffile); + CargoType cargo = GetCargoTranslation(rawcargo, _cur_gps.grffile); if (!IsValidCargoType(cargo)) { /* The mapped cargo is invalid. This is permitted at this point, * as long as the result is not used. Mark it invalid so this @@ -668,7 +668,7 @@ static void NewSpriteGroup(ByteReader &buf) } for (uint i = 0; i < group->num_output; i++) { uint8_t rawcargo = buf.ReadByte(); - CargoType cargo = GetCargoTranslation(rawcargo, _cur.grffile); + CargoType cargo = GetCargoTranslation(rawcargo, _cur_gps.grffile); if (!IsValidCargoType(cargo)) { /* Mark this result as invalid to use */ group->version = 0xFF; @@ -693,7 +693,7 @@ static void NewSpriteGroup(ByteReader &buf) } } - _cur.spritegroups[setid] = act_group; + _cur_gps.spritegroups[setid] = act_group; } template <> void GrfActionHandler<0x02>::FileScan(ByteReader &) { } diff --git a/src/newgrf/newgrf_act3.cpp b/src/newgrf/newgrf_act3.cpp index 89db8d6868..96fffac525 100644 --- a/src/newgrf/newgrf_act3.cpp +++ b/src/newgrf/newgrf_act3.cpp @@ -39,11 +39,11 @@ static CargoType TranslateCargo(uint8_t feature, uint8_t ctype) if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA; if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE; - auto cargo_list = GetCargoTranslationTable(*_cur.grffile); + auto cargo_list = GetCargoTranslationTable(*_cur_gps.grffile); /* Check if the cargo type is out of bounds of the cargo translation table */ if (ctype >= cargo_list.size()) { - GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1); + GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur_gps.grffile->cargo_list.size() - 1); return INVALID_CARGO; } @@ -67,7 +67,7 @@ static CargoType TranslateCargo(uint8_t feature, uint8_t ctype) static bool IsValidGroupID(uint16_t groupid, const char *function) { - if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) { + if (groupid > MAX_SPRITEGROUP || _cur_gps.spritegroups[groupid] == nullptr) { GrfMsg(1, "{}: Spritegroup 0x{:04X} out of range or empty, skipping.", function, groupid); return false; } @@ -99,7 +99,7 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco std::vector engines; engines.reserve(idcount); for (uint i = 0; i < idcount; i++) { - Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, buf.ReadExtendedByte()); + Engine *e = GetNewEngine(_cur_gps.grffile, (VehicleType)feature, buf.ReadExtendedByte()); if (e == nullptr) { /* No engine could be allocated?!? Deal with it. Okay, * this might look bad. Also make sure this NewGRF @@ -129,9 +129,9 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco GrfMsg(7, "VehicleMapSpriteGroup: [{}] Engine {}...", i, engine); if (wagover) { - SetWagonOverrideSprites(engine, cargo_type, _cur.spritegroups[groupid], last_engines); + SetWagonOverrideSprites(engine, cargo_type, _cur_gps.spritegroups[groupid], last_engines); } else { - SetCustomEngineSprites(engine, cargo_type, _cur.spritegroups[groupid]); + SetCustomEngineSprites(engine, cargo_type, _cur_gps.spritegroups[groupid]); } } } @@ -145,10 +145,10 @@ static void VehicleMapSpriteGroup(ByteReader &buf, uint8_t feature, uint8_t idco EngineID engine = engines[i]; if (wagover) { - SetWagonOverrideSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid], last_engines); + SetWagonOverrideSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur_gps.spritegroups[groupid], last_engines); } else { - SetCustomEngineSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]); - SetEngineGRF(engine, _cur.grffile); + SetCustomEngineSprites(engine, SpriteGroupCargo::SG_DEFAULT, _cur_gps.spritegroups[groupid]); + SetEngineGRF(engine, _cur_gps.grffile); } } } @@ -174,15 +174,15 @@ static void CanalMapSpriteGroup(ByteReader &buf, uint8_t idcount) continue; } - _water_feature[cf].grffile = _cur.grffile; - _water_feature[cf].group = _cur.spritegroups[groupid]; + _water_feature[cf].grffile = _cur_gps.grffile; + _water_feature[cf].group = _cur_gps.spritegroups[groupid]; } } static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->stations.empty()) { + if (_cur_gps.grffile->stations.empty()) { GrfMsg(1, "StationMapSpriteGroup: No stations defined, skipping"); return; } @@ -203,14 +203,14 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidCargoType(ctype)) continue; for (auto &station : stations) { - StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get(); + StationSpec *statspec = station >= _cur_gps.grffile->stations.size() ? nullptr : _cur_gps.grffile->stations[station].get(); if (statspec == nullptr) { GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station); continue; } - statspec->grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]); + statspec->grf_prop.SetSpriteGroup(ctype, _cur_gps.spritegroups[groupid]); } } @@ -218,7 +218,7 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) return; for (auto &station : stations) { - StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get(); + StationSpec *statspec = station >= _cur_gps.grffile->stations.size() ? nullptr : _cur_gps.grffile->stations[station].get(); if (statspec == nullptr) { GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station); @@ -230,8 +230,8 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) continue; } - statspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]); - statspec->grf_prop.SetGRFFile(_cur.grffile); + statspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur_gps.spritegroups[groupid]); + statspec->grf_prop.SetGRFFile(_cur_gps.grffile); statspec->grf_prop.local_id = station; StationClass::Assign(statspec); } @@ -240,7 +240,7 @@ static void StationMapSpriteGroup(ByteReader &buf, uint8_t idcount) static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->housespec.empty()) { + if (_cur_gps.grffile->housespec.empty()) { GrfMsg(1, "TownHouseMapSpriteGroup: No houses defined, skipping"); return; } @@ -259,20 +259,20 @@ static void TownHouseMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "TownHouseMapSpriteGroup")) return; for (auto &house : houses) { - HouseSpec *hs = house >= _cur.grffile->housespec.size() ? nullptr : _cur.grffile->housespec[house].get(); + HouseSpec *hs = house >= _cur_gps.grffile->housespec.size() ? nullptr : _cur_gps.grffile->housespec[house].get(); if (hs == nullptr) { GrfMsg(1, "TownHouseMapSpriteGroup: House {} undefined, skipping.", house); continue; } - hs->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]); + hs->grf_prop.SetSpriteGroup(0, _cur_gps.spritegroups[groupid]); } } static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->industryspec.empty()) { + if (_cur_gps.grffile->industryspec.empty()) { GrfMsg(1, "IndustryMapSpriteGroup: No industries defined, skipping"); return; } @@ -291,20 +291,20 @@ static void IndustryMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "IndustryMapSpriteGroup")) return; for (auto &industry : industries) { - IndustrySpec *indsp = industry >= _cur.grffile->industryspec.size() ? nullptr : _cur.grffile->industryspec[industry].get(); + IndustrySpec *indsp = industry >= _cur_gps.grffile->industryspec.size() ? nullptr : _cur_gps.grffile->industryspec[industry].get(); if (indsp == nullptr) { GrfMsg(1, "IndustryMapSpriteGroup: Industry {} undefined, skipping", industry); continue; } - indsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]); + indsp->grf_prop.SetSpriteGroup(0, _cur_gps.spritegroups[groupid]); } } static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->indtspec.empty()) { + if (_cur_gps.grffile->indtspec.empty()) { GrfMsg(1, "IndustrytileMapSpriteGroup: No industry tiles defined, skipping"); return; } @@ -323,14 +323,14 @@ static void IndustrytileMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "IndustrytileMapSpriteGroup")) return; for (auto &indtile : indtiles) { - IndustryTileSpec *indtsp = indtile >= _cur.grffile->indtspec.size() ? nullptr : _cur.grffile->indtspec[indtile].get(); + IndustryTileSpec *indtsp = indtile >= _cur_gps.grffile->indtspec.size() ? nullptr : _cur_gps.grffile->indtspec[indtile].get(); if (indtsp == nullptr) { GrfMsg(1, "IndustrytileMapSpriteGroup: Industry tile {} undefined, skipping", indtile); continue; } - indtsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]); + indtsp->grf_prop.SetSpriteGroup(0, _cur_gps.spritegroups[groupid]); } } @@ -356,14 +356,14 @@ static void CargoMapSpriteGroup(ByteReader &buf, uint8_t idcount) } CargoSpec *cs = CargoSpec::Get(cargo_type); - cs->grffile = _cur.grffile; - cs->group = _cur.spritegroups[groupid]; + cs->grffile = _cur_gps.grffile; + cs->group = _cur_gps.spritegroups[groupid]; } } static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->objectspec.empty()) { + if (_cur_gps.grffile->objectspec.empty()) { GrfMsg(1, "ObjectMapSpriteGroup: No object tiles defined, skipping"); return; } @@ -387,14 +387,14 @@ static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) } for (auto &object : objects) { - ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get(); + ObjectSpec *spec = object >= _cur_gps.grffile->objectspec.size() ? nullptr : _cur_gps.grffile->objectspec[object].get(); if (spec == nullptr) { GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object); continue; } - spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_PURCHASE, _cur.spritegroups[groupid]); + spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_PURCHASE, _cur_gps.spritegroups[groupid]); } } @@ -402,7 +402,7 @@ static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) return; for (auto &object : objects) { - ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get(); + ObjectSpec *spec = object >= _cur_gps.grffile->objectspec.size() ? nullptr : _cur_gps.grffile->objectspec[object].get(); if (spec == nullptr) { GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object); @@ -414,8 +414,8 @@ static void ObjectMapSpriteGroup(ByteReader &buf, uint8_t idcount) continue; } - spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_DEFAULT, _cur.spritegroups[groupid]); - spec->grf_prop.SetGRFFile(_cur.grffile); + spec->grf_prop.SetSpriteGroup(OBJECT_SPRITE_GROUP_DEFAULT, _cur_gps.spritegroups[groupid]); + spec->grf_prop.SetGRFFile(_cur_gps.grffile); spec->grf_prop.local_id = object; } } @@ -426,7 +426,7 @@ static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) railtypes.reserve(idcount); for (uint i = 0; i < idcount; i++) { uint16_t id = buf.ReadExtendedByte(); - railtypes.push_back(id < RAILTYPE_END ? _cur.grffile->railtype_map[id] : INVALID_RAILTYPE); + railtypes.push_back(id < RAILTYPE_END ? _cur_gps.grffile->railtype_map[id] : INVALID_RAILTYPE); } uint8_t cidcount = buf.ReadByte(); @@ -442,8 +442,8 @@ static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (railtype != INVALID_RAILTYPE) { RailTypeInfo *rti = &_railtypes[railtype]; - rti->grffile[ctype] = _cur.grffile; - rti->group[ctype] = _cur.spritegroups[groupid]; + rti->grffile[ctype] = _cur_gps.grffile; + rti->group[ctype] = _cur_gps.spritegroups[groupid]; } } } @@ -454,7 +454,7 @@ static void RailTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount) static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramType rtt) { - std::array &type_map = (rtt == RTT_TRAM) ? _cur.grffile->tramtype_map : _cur.grffile->roadtype_map; + std::array &type_map = (rtt == RTT_TRAM) ? _cur_gps.grffile->tramtype_map : _cur_gps.grffile->roadtype_map; std::vector roadtypes; roadtypes.reserve(idcount); @@ -476,8 +476,8 @@ static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramTyp if (roadtype != INVALID_ROADTYPE) { RoadTypeInfo *rti = &_roadtypes[roadtype]; - rti->grffile[ctype] = _cur.grffile; - rti->group[ctype] = _cur.spritegroups[groupid]; + rti->grffile[ctype] = _cur_gps.grffile; + rti->group[ctype] = _cur_gps.spritegroups[groupid]; } } } @@ -488,7 +488,7 @@ static void RoadTypeMapSpriteGroup(ByteReader &buf, uint8_t idcount, RoadTramTyp static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->airportspec.empty()) { + if (_cur_gps.grffile->airportspec.empty()) { GrfMsg(1, "AirportMapSpriteGroup: No airports defined, skipping"); return; } @@ -507,20 +507,20 @@ static void AirportMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "AirportMapSpriteGroup")) return; for (auto &airport : airports) { - AirportSpec *as = airport >= _cur.grffile->airportspec.size() ? nullptr : _cur.grffile->airportspec[airport].get(); + AirportSpec *as = airport >= _cur_gps.grffile->airportspec.size() ? nullptr : _cur_gps.grffile->airportspec[airport].get(); if (as == nullptr) { GrfMsg(1, "AirportMapSpriteGroup: Airport {} undefined, skipping", airport); continue; } - as->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]); + as->grf_prop.SetSpriteGroup(0, _cur_gps.spritegroups[groupid]); } } static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->airtspec.empty()) { + if (_cur_gps.grffile->airtspec.empty()) { GrfMsg(1, "AirportTileMapSpriteGroup: No airport tiles defined, skipping"); return; } @@ -539,20 +539,20 @@ static void AirportTileMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "AirportTileMapSpriteGroup")) return; for (auto &airptile : airptiles) { - AirportTileSpec *airtsp = airptile >= _cur.grffile->airtspec.size() ? nullptr : _cur.grffile->airtspec[airptile].get(); + AirportTileSpec *airtsp = airptile >= _cur_gps.grffile->airtspec.size() ? nullptr : _cur_gps.grffile->airtspec[airptile].get(); if (airtsp == nullptr) { GrfMsg(1, "AirportTileMapSpriteGroup: Airport tile {} undefined, skipping", airptile); continue; } - airtsp->grf_prop.SetSpriteGroup(0, _cur.spritegroups[groupid]); + airtsp->grf_prop.SetSpriteGroup(0, _cur_gps.spritegroups[groupid]); } } static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->roadstops.empty()) { + if (_cur_gps.grffile->roadstops.empty()) { GrfMsg(1, "RoadStopMapSpriteGroup: No roadstops defined, skipping"); return; } @@ -573,14 +573,14 @@ static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidCargoType(ctype)) continue; for (auto &roadstop : roadstops) { - RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get(); + RoadStopSpec *roadstopspec = roadstop >= _cur_gps.grffile->roadstops.size() ? nullptr : _cur_gps.grffile->roadstops[roadstop].get(); if (roadstopspec == nullptr) { GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop); continue; } - roadstopspec->grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]); + roadstopspec->grf_prop.SetSpriteGroup(ctype, _cur_gps.spritegroups[groupid]); } } @@ -588,7 +588,7 @@ static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) return; for (auto &roadstop : roadstops) { - RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get(); + RoadStopSpec *roadstopspec = roadstop >= _cur_gps.grffile->roadstops.size() ? nullptr : _cur_gps.grffile->roadstops[roadstop].get(); if (roadstopspec == nullptr) { GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping.", roadstop); @@ -600,8 +600,8 @@ static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) continue; } - roadstopspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur.spritegroups[groupid]); - roadstopspec->grf_prop.SetGRFFile(_cur.grffile); + roadstopspec->grf_prop.SetSpriteGroup(SpriteGroupCargo::SG_DEFAULT, _cur_gps.spritegroups[groupid]); + roadstopspec->grf_prop.SetGRFFile(_cur_gps.grffile); roadstopspec->grf_prop.local_id = roadstop; RoadStopClass::Assign(roadstopspec); } @@ -609,7 +609,7 @@ static void RoadStopMapSpriteGroup(ByteReader &buf, uint8_t idcount) static void BadgeMapSpriteGroup(ByteReader &buf, uint8_t idcount) { - if (_cur.grffile->badge_map.empty()) { + if (_cur_gps.grffile->badge_map.empty()) { GrfMsg(1, "BadgeMapSpriteGroup: No badges defined, skipping"); return; } @@ -629,14 +629,14 @@ static void BadgeMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (ctype >= GSF_END) continue; for (const auto &local_id : local_ids) { - auto found = _cur.grffile->badge_map.find(local_id); - if (found == std::end(_cur.grffile->badge_map)) { + auto found = _cur_gps.grffile->badge_map.find(local_id); + if (found == std::end(_cur_gps.grffile->badge_map)) { GrfMsg(1, "BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id); continue; } auto &badge = *GetBadge(found->second); - badge.grf_prop.SetSpriteGroup(ctype, _cur.spritegroups[groupid]); + badge.grf_prop.SetSpriteGroup(ctype, _cur_gps.spritegroups[groupid]); } } @@ -644,15 +644,15 @@ static void BadgeMapSpriteGroup(ByteReader &buf, uint8_t idcount) if (!IsValidGroupID(groupid, "BadgeMapSpriteGroup")) return; for (auto &local_id : local_ids) { - auto found = _cur.grffile->badge_map.find(local_id); - if (found == std::end(_cur.grffile->badge_map)) { + auto found = _cur_gps.grffile->badge_map.find(local_id); + if (found == std::end(_cur_gps.grffile->badge_map)) { GrfMsg(1, "BadgeMapSpriteGroup: Badge {} undefined, skipping", local_id); continue; } auto &badge = *GetBadge(found->second); - badge.grf_prop.SetSpriteGroup(GSF_END, _cur.spritegroups[groupid]); - badge.grf_prop.SetGRFFile(_cur.grffile); + badge.grf_prop.SetSpriteGroup(GSF_END, _cur_gps.spritegroups[groupid]); + badge.grf_prop.SetGRFFile(_cur_gps.grffile); badge.grf_prop.local_id = local_id; } } @@ -691,12 +691,12 @@ static void FeatureMapSpriteGroup(ByteReader &buf) GrfMsg(6, "FeatureMapSpriteGroup: Adding generic feature callback for feature 0x{:02X}", feature); - AddGenericCallback(feature, _cur.grffile, _cur.spritegroups[groupid]); + AddGenericCallback(feature, _cur_gps.grffile, _cur_gps.spritegroups[groupid]); return; } /* Mark the feature as used by the grf (generic callbacks do not count) */ - SetBit(_cur.grffile->grf_features, feature); + SetBit(_cur_gps.grffile->grf_features, feature); GrfMsg(6, "FeatureMapSpriteGroup: Feature 0x{:02X}, {} ids", feature, idcount); diff --git a/src/newgrf/newgrf_act4.cpp b/src/newgrf/newgrf_act4.cpp index 38c6701d67..6a4fedf3ea 100644 --- a/src/newgrf/newgrf_act4.cpp +++ b/src/newgrf/newgrf_act4.cpp @@ -46,7 +46,7 @@ static void FeatureNewName(ByteReader &buf) * S data new texts, each of them zero-terminated, after * which the next name begins. */ - bool new_scheme = _cur.grffile->grf_version >= 7; + bool new_scheme = _cur_gps.grffile->grf_version >= 7; uint8_t feature = buf.ReadByte(); if (feature >= GSF_END && feature != 0x48) { @@ -86,67 +86,67 @@ static void FeatureNewName(ByteReader &buf) case GSF_SHIPS: case GSF_AIRCRAFT: if (!generic) { - Engine *e = GetNewEngine(_cur.grffile, (VehicleType)feature, id, _cur.grfconfig->flags.Test(GRFConfigFlag::Static)); + Engine *e = GetNewEngine(_cur_gps.grffile, (VehicleType)feature, id, _cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static)); if (e == nullptr) break; - StringID string = AddGRFString(_cur.grffile->grfid, GRFStringID{feature_overlay | e->index.base()}, lang, new_scheme, false, name, e->info.string_id); + StringID string = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{feature_overlay | e->index.base()}, lang, new_scheme, false, name, e->info.string_id); e->info.string_id = string; } else { - AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); + AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); } break; case GSF_BADGES: { if (!generic) { - auto found = _cur.grffile->badge_map.find(id); - if (found == std::end(_cur.grffile->badge_map)) { + auto found = _cur_gps.grffile->badge_map.find(id); + if (found == std::end(_cur_gps.grffile->badge_map)) { GrfMsg(1, "FeatureNewName: Attempt to name undefined badge 0x{:X}, ignoring", id); } else { Badge &badge = *GetBadge(found->second); - badge.name = AddGRFString(_cur.grffile->grfid, GRFStringID{feature_overlay | id}, lang, true, false, name, STR_UNDEFINED); + badge.name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{feature_overlay | id}, lang, true, false, name, STR_UNDEFINED); } } else { - AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); + AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); } break; } default: if (IsInsideMM(id, 0xD000, 0xD400) || IsInsideMM(id, 0xD800, 0x10000)) { - AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); + AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, true, name, STR_UNDEFINED); break; } switch (GB(id, 8, 8)) { case 0xC4: // Station class name - if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) { + if (GB(id, 0, 8) >= _cur_gps.grffile->stations.size() || _cur_gps.grffile->stations[GB(id, 0, 8)] == nullptr) { GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8)); } else { - StationClassID class_index = _cur.grffile->stations[GB(id, 0, 8)]->class_index; - StationClass::Get(class_index)->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); + StationClassID class_index = _cur_gps.grffile->stations[GB(id, 0, 8)]->class_index; + StationClass::Get(class_index)->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC5: // Station name - if (GB(id, 0, 8) >= _cur.grffile->stations.size() || _cur.grffile->stations[GB(id, 0, 8)] == nullptr) { + if (GB(id, 0, 8) >= _cur_gps.grffile->stations.size() || _cur_gps.grffile->stations[GB(id, 0, 8)] == nullptr) { GrfMsg(1, "FeatureNewName: Attempt to name undefined station 0x{:X}, ignoring", GB(id, 0, 8)); } else { - _cur.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); + _cur_gps.grffile->stations[GB(id, 0, 8)]->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC7: // Airporttile name - if (GB(id, 0, 8) >= _cur.grffile->airtspec.size() || _cur.grffile->airtspec[GB(id, 0, 8)] == nullptr) { + if (GB(id, 0, 8) >= _cur_gps.grffile->airtspec.size() || _cur_gps.grffile->airtspec[GB(id, 0, 8)] == nullptr) { GrfMsg(1, "FeatureNewName: Attempt to name undefined airport tile 0x{:X}, ignoring", GB(id, 0, 8)); } else { - _cur.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); + _cur_gps.grffile->airtspec[GB(id, 0, 8)]->name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); } break; case 0xC9: // House name - if (GB(id, 0, 8) >= _cur.grffile->housespec.size() || _cur.grffile->housespec[GB(id, 0, 8)] == nullptr) { + if (GB(id, 0, 8) >= _cur_gps.grffile->housespec.size() || _cur_gps.grffile->housespec[GB(id, 0, 8)] == nullptr) { GrfMsg(1, "FeatureNewName: Attempt to name undefined house 0x{:X}, ignoring.", GB(id, 0, 8)); } else { - _cur.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); + _cur_gps.grffile->housespec[GB(id, 0, 8)]->building_name = AddGRFString(_cur_gps.grffile->grfid, GRFStringID{id}, lang, new_scheme, false, name, STR_UNDEFINED); } break; diff --git a/src/newgrf/newgrf_act5.cpp b/src/newgrf/newgrf_act5.cpp index 751ef0aa97..00a2427b3c 100644 --- a/src/newgrf/newgrf_act5.cpp +++ b/src/newgrf/newgrf_act5.cpp @@ -103,20 +103,20 @@ static void GraphicsNew(ByteReader &buf) uint16_t offset = HasBit(type, 7) ? buf.ReadExtendedByte() : 0; ClrBit(type, 7); // Clear the high bit as that only indicates whether there is an offset. - if ((type == 0x0D) && (num == 10) && _cur.grfconfig->flags.Test(GRFConfigFlag::System)) { + if ((type == 0x0D) && (num == 10) && _cur_gps.grfconfig->flags.Test(GRFConfigFlag::System)) { /* Special not-TTDP-compatible case used in openttd.grf * Missing shore sprites and initialisation of SPR_SHORE_BASE */ GrfMsg(2, "GraphicsNew: Loading 10 missing shore sprites from extra grf."); - LoadNextSprite(SPR_SHORE_BASE + 0, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_S - LoadNextSprite(SPR_SHORE_BASE + 5, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_W - LoadNextSprite(SPR_SHORE_BASE + 7, *_cur.file, _cur.nfo_line++); // SLOPE_WSE - LoadNextSprite(SPR_SHORE_BASE + 10, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_N - LoadNextSprite(SPR_SHORE_BASE + 11, *_cur.file, _cur.nfo_line++); // SLOPE_NWS - LoadNextSprite(SPR_SHORE_BASE + 13, *_cur.file, _cur.nfo_line++); // SLOPE_ENW - LoadNextSprite(SPR_SHORE_BASE + 14, *_cur.file, _cur.nfo_line++); // SLOPE_SEN - LoadNextSprite(SPR_SHORE_BASE + 15, *_cur.file, _cur.nfo_line++); // SLOPE_STEEP_E - LoadNextSprite(SPR_SHORE_BASE + 16, *_cur.file, _cur.nfo_line++); // SLOPE_EW - LoadNextSprite(SPR_SHORE_BASE + 17, *_cur.file, _cur.nfo_line++); // SLOPE_NS + LoadNextSprite(SPR_SHORE_BASE + 0, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_S + LoadNextSprite(SPR_SHORE_BASE + 5, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_W + LoadNextSprite(SPR_SHORE_BASE + 7, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_WSE + LoadNextSprite(SPR_SHORE_BASE + 10, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_N + LoadNextSprite(SPR_SHORE_BASE + 11, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_NWS + LoadNextSprite(SPR_SHORE_BASE + 13, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_ENW + LoadNextSprite(SPR_SHORE_BASE + 14, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_SEN + LoadNextSprite(SPR_SHORE_BASE + 15, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_STEEP_E + LoadNextSprite(SPR_SHORE_BASE + 16, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_EW + LoadNextSprite(SPR_SHORE_BASE + 17, *_cur_gps.file, _cur_gps.nfo_line++); // SLOPE_NS if (_loaded_newgrf_features.shore == SHORE_REPLACE_NONE) _loaded_newgrf_features.shore = SHORE_REPLACE_ONLY_NEW; return; } @@ -124,7 +124,7 @@ static void GraphicsNew(ByteReader &buf) /* Supported type? */ if ((type >= std::size(_action5_types)) || (_action5_types[type].block_type == A5BLOCK_INVALID)) { GrfMsg(2, "GraphicsNew: Custom graphics (type 0x{:02X}) sprite block of length {} (unimplemented, ignoring)", type, num); - _cur.skip_sprites = num; + _cur_gps.skip_sprites = num; return; } @@ -142,7 +142,7 @@ static void GraphicsNew(ByteReader &buf) * This does not make sense, if is allowed */ if ((action5_type->block_type == A5BLOCK_FIXED) && (num < action5_type->min_sprites)) { GrfMsg(1, "GraphicsNew: {} (type 0x{:02X}) count must be at least {}. Only {} were specified. Skipping.", action5_type->name, type, action5_type->min_sprites, num); - _cur.skip_sprites = num; + _cur_gps.skip_sprites = num; return; } @@ -166,16 +166,16 @@ static void GraphicsNew(ByteReader &buf) bool dup_oneway_sprites = ((type == 0x09) && (offset + num <= ONEWAY_SLOPE_N_OFFSET)); for (; num > 0; num--) { - _cur.nfo_line++; - SpriteID load_index = (replace == 0 ? _cur.spriteid++ : replace++); - LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); + _cur_gps.nfo_line++; + SpriteID load_index = (replace == 0 ? _cur_gps.spriteid++ : replace++); + LoadNextSprite(load_index, *_cur_gps.file, _cur_gps.nfo_line); if (dup_oneway_sprites) { DupSprite(load_index, load_index + ONEWAY_SLOPE_N_OFFSET); DupSprite(load_index, load_index + ONEWAY_SLOPE_S_OFFSET); } } - _cur.skip_sprites = skip_num; + _cur_gps.skip_sprites = skip_num; } /* Action 0x05 (SKIP) */ @@ -185,9 +185,9 @@ static void SkipAct5(ByteReader &buf) buf.ReadByte(); /* Skip the sprites of this action */ - _cur.skip_sprites = buf.ReadExtendedByte(); + _cur_gps.skip_sprites = buf.ReadExtendedByte(); - GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur.skip_sprites); + GrfMsg(3, "SkipAct5: Skipping {} sprites", _cur_gps.skip_sprites); } template <> void GrfActionHandler<0x05>::FileScan(ByteReader &buf) { SkipAct5(buf); } diff --git a/src/newgrf/newgrf_act6.cpp b/src/newgrf/newgrf_act6.cpp index 34390adc95..a30dcb2092 100644 --- a/src/newgrf/newgrf_act6.cpp +++ b/src/newgrf/newgrf_act6.cpp @@ -32,7 +32,7 @@ static void CfgApply(ByteReader &buf) * to place where parameter is to be stored. */ /* Preload the next sprite */ - SpriteFile &file = *_cur.file; + SpriteFile &file = *_cur_gps.file; size_t pos = file.GetPos(); uint32_t num = file.GetContainerVersion() >= 2 ? file.ReadDword() : file.ReadWord(); uint8_t type = file.ReadByte(); @@ -47,7 +47,7 @@ static void CfgApply(ByteReader &buf) } /* Get (or create) the override for the next sprite. */ - GRFLocation location(_cur.grfconfig->ident.grfid, _cur.nfo_line + 1); + GRFLocation location(_cur_gps.grfconfig->ident.grfid, _cur_gps.nfo_line + 1); std::vector &preload_sprite = _grf_line_to_action6_sprite_override[location]; /* Load new sprite data if it hasn't already been loaded. */ @@ -85,7 +85,7 @@ static void CfgApply(ByteReader &buf) /* If the parameter is a GRF parameter (not an internal variable) check * if it (and all further sequential parameters) has been defined. */ - if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur.grffile->param)) { + if (param_num < 0x80 && (param_num + (param_size - 1) / 4) >= std::size(_cur_gps.grffile->param)) { GrfMsg(2, "CfgApply: Ignoring (param {} not set)", (param_num + (param_size - 1) / 4)); break; } diff --git a/src/newgrf/newgrf_act7_9.cpp b/src/newgrf/newgrf_act7_9.cpp index bb36fc0781..4d08d2e67e 100644 --- a/src/newgrf/newgrf_act7_9.cpp +++ b/src/newgrf/newgrf_act7_9.cpp @@ -117,7 +117,7 @@ uint32_t GetParamVal(uint8_t param, uint32_t *cond_val) { /* First handle variable common with VarAction2 */ uint32_t value; - if (GetGlobalVariable(param - 0x80, &value, _cur.grffile)) return value; + if (GetGlobalVariable(param - 0x80, &value, _cur_gps.grffile)) return value; /* Non-common variable */ @@ -125,9 +125,9 @@ uint32_t GetParamVal(uint8_t param, uint32_t *cond_val) case 0x84: { // GRF loading stage uint32_t res = 0; - if (_cur.stage > GLS_INIT) SetBit(res, 0); - if (_cur.stage == GLS_RESERVE) SetBit(res, 8); - if (_cur.stage == GLS_ACTIVATION) SetBit(res, 9); + if (_cur_gps.stage > GLS_INIT) SetBit(res, 0); + if (_cur_gps.stage == GLS_RESERVE) SetBit(res, 8); + if (_cur_gps.stage == GLS_ACTIVATION) SetBit(res, 9); return res; } @@ -149,7 +149,7 @@ uint32_t GetParamVal(uint8_t param, uint32_t *cond_val) default: /* GRF Parameter */ - if (param < 0x80) return _cur.grffile->GetParam(param); + if (param < 0x80) return _cur_gps.grffile->GetParam(param); /* In-game variable. */ GrfMsg(1, "Unsupported in-game variable 0x{:02X}", param); @@ -189,7 +189,7 @@ static void SkipIf(ByteReader &buf) default: break; } - if (param < 0x80 && std::size(_cur.grffile->param) <= param) { + if (param < 0x80 && std::size(_cur_gps.grffile->param) <= param) { GrfMsg(7, "SkipIf: Param {} undefined, skipping test", param); return; } @@ -237,7 +237,7 @@ static void SkipIf(ByteReader &buf) GRFConfig *c = GetGRFConfig(cond_val, mask); - if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) { + if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) { DisableStaticNewGRFInfluencingNonStaticNewGRFs(*c); c = nullptr; } @@ -304,13 +304,13 @@ static void SkipIf(ByteReader &buf) * the current nfo_line. If no matching label is found, the first matching * label in the file is used. */ const GRFLabel *choice = nullptr; - for (const auto &label : _cur.grffile->labels) { + for (const auto &label : _cur_gps.grffile->labels) { if (label.label != numsprites) continue; /* Remember a goto before the current line */ if (choice == nullptr) choice = &label; /* If we find a label here, this is definitely good */ - if (label.nfo_line > _cur.nfo_line) { + if (label.nfo_line > _cur_gps.nfo_line) { choice = &label; break; } @@ -318,21 +318,21 @@ static void SkipIf(ByteReader &buf) if (choice != nullptr) { GrfMsg(2, "SkipIf: Jumping to label 0x{:X} at line {}, test was true", choice->label, choice->nfo_line); - _cur.file->SeekTo(choice->pos, SEEK_SET); - _cur.nfo_line = choice->nfo_line; + _cur_gps.file->SeekTo(choice->pos, SEEK_SET); + _cur_gps.nfo_line = choice->nfo_line; return; } GrfMsg(2, "SkipIf: Skipping {} sprites, test was true", numsprites); - _cur.skip_sprites = numsprites; - if (_cur.skip_sprites == 0) { + _cur_gps.skip_sprites = numsprites; + if (_cur_gps.skip_sprites == 0) { /* Zero means there are no sprites to skip, so * we use -1 to indicate that all further * sprites should be skipped. */ - _cur.skip_sprites = -1; + _cur_gps.skip_sprites = -1; /* If an action 8 hasn't been encountered yet, disable the grf. */ - if (_cur.grfconfig->status != (_cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED)) { + if (_cur_gps.grfconfig->status != (_cur_gps.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED)) { DisableGrf(); } } diff --git a/src/newgrf/newgrf_act8.cpp b/src/newgrf/newgrf_act8.cpp index d71365070a..9466efcedb 100644 --- a/src/newgrf/newgrf_act8.cpp +++ b/src/newgrf/newgrf_act8.cpp @@ -24,25 +24,25 @@ static void ScanInfo(ByteReader &buf) uint32_t grfid = buf.ReadDWord(); std::string_view name = buf.ReadString(); - _cur.grfconfig->ident.grfid = grfid; + _cur_gps.grfconfig->ident.grfid = grfid; if (grf_version < 2 || grf_version > 8) { - _cur.grfconfig->flags.Set(GRFConfigFlag::Invalid); - Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID {:08X}) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur.grfconfig->filename, StrMakeValid(name), std::byteswap(grfid), grf_version); + _cur_gps.grfconfig->flags.Set(GRFConfigFlag::Invalid); + Debug(grf, 0, "{}: NewGRF \"{}\" (GRFID {:08X}) uses GRF version {}, which is incompatible with this version of OpenTTD.", _cur_gps.grfconfig->filename, StrMakeValid(name), std::byteswap(grfid), grf_version); } /* GRF IDs starting with 0xFF are reserved for internal TTDPatch use */ - if (GB(grfid, 0, 8) == 0xFF) _cur.grfconfig->flags.Set(GRFConfigFlag::System); + if (GB(grfid, 0, 8) == 0xFF) _cur_gps.grfconfig->flags.Set(GRFConfigFlag::System); - AddGRFTextToList(_cur.grfconfig->name, 0x7F, grfid, false, name); + AddGRFTextToList(_cur_gps.grfconfig->name, 0x7F, grfid, false, name); if (buf.HasData()) { std::string_view info = buf.ReadString(); - AddGRFTextToList(_cur.grfconfig->info, 0x7F, grfid, true, info); + AddGRFTextToList(_cur_gps.grfconfig->info, 0x7F, grfid, true, info); } /* GLS_INFOSCAN only looks for the action 8, so we can skip the rest of the file */ - _cur.skip_sprites = -1; + _cur_gps.skip_sprites = -1; } /* Action 0x08 */ @@ -59,21 +59,21 @@ static void GRFInfo(ByteReader &buf) uint32_t grfid = buf.ReadDWord(); std::string_view name = buf.ReadString(); - if (_cur.stage < GLS_RESERVE && _cur.grfconfig->status != GCS_UNKNOWN) { + if (_cur_gps.stage < GLS_RESERVE && _cur_gps.grfconfig->status != GCS_UNKNOWN) { DisableGrf(STR_NEWGRF_ERROR_MULTIPLE_ACTION_8); return; } - if (_cur.grffile->grfid != grfid) { - Debug(grf, 0, "GRFInfo: GRFID {:08X} in FILESCAN stage does not match GRFID {:08X} in INIT/RESERVE/ACTIVATION stage", std::byteswap(_cur.grffile->grfid), std::byteswap(grfid)); - _cur.grffile->grfid = grfid; + if (_cur_gps.grffile->grfid != grfid) { + Debug(grf, 0, "GRFInfo: GRFID {:08X} in FILESCAN stage does not match GRFID {:08X} in INIT/RESERVE/ACTIVATION stage", std::byteswap(_cur_gps.grffile->grfid), std::byteswap(grfid)); + _cur_gps.grffile->grfid = grfid; } - _cur.grffile->grf_version = version; - _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; + _cur_gps.grffile->grf_version = version; + _cur_gps.grfconfig->status = _cur_gps.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; /* Do swap the GRFID for displaying purposes since people expect that */ - Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, std::byteswap(grfid), StrMakeValid(name), (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version); + Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, std::byteswap(grfid), StrMakeValid(name), (_cur_gps.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur_gps.grfconfig->version); } template <> void GrfActionHandler<0x08>::FileScan(ByteReader &buf) { ScanInfo(buf); } diff --git a/src/newgrf/newgrf_acta.cpp b/src/newgrf/newgrf_acta.cpp index b66bd35837..ba4e509bc4 100644 --- a/src/newgrf/newgrf_acta.cpp +++ b/src/newgrf/newgrf_acta.cpp @@ -26,7 +26,7 @@ static bool IsGRMReservedSprite(SpriteID first_sprite, uint16_t num_sprites) { for (const auto &grm_sprite : _grm_sprites) { - if (grm_sprite.first.grfid != _cur.grffile->grfid) continue; + if (grm_sprite.first.grfid != _cur_gps.grffile->grfid) continue; if (grm_sprite.second.first <= first_sprite && grm_sprite.second.first + grm_sprite.second.second >= first_sprite + num_sprites) return true; } return false; @@ -60,15 +60,15 @@ static void SpriteReplace(ByteReader &buf) i, num_sprites, first_sprite, SPR_OPENTTD_BASE); /* Load the sprites at the current location so they will do nothing instead of appearing to work. */ - first_sprite = _cur.spriteid; - _cur.spriteid += num_sprites; + first_sprite = _cur_gps.spriteid; + _cur_gps.spriteid += num_sprites; } } for (uint j = 0; j < num_sprites; j++) { SpriteID load_index = first_sprite + j; - _cur.nfo_line++; - LoadNextSprite(load_index, *_cur.file, _cur.nfo_line); // XXX + _cur_gps.nfo_line++; + LoadNextSprite(load_index, *_cur_gps.file, _cur_gps.nfo_line); // XXX /* Shore sprites now located at different addresses. * So detect when the old ones get replaced. */ @@ -86,12 +86,12 @@ static void SkipActA(ByteReader &buf) for (uint i = 0; i < num_sets; i++) { /* Skip the sprites this replaces */ - _cur.skip_sprites += buf.ReadByte(); + _cur_gps.skip_sprites += buf.ReadByte(); /* But ignore where they go */ buf.ReadWord(); } - GrfMsg(3, "SkipActA: Skipping {} sprites", _cur.skip_sprites); + GrfMsg(3, "SkipActA: Skipping {} sprites", _cur_gps.skip_sprites); } template <> void GrfActionHandler<0x0A>::FileScan(ByteReader &buf) { SkipActA(buf); } diff --git a/src/newgrf/newgrf_actb.cpp b/src/newgrf/newgrf_actb.cpp index a462bbf0c2..53aed45267 100644 --- a/src/newgrf/newgrf_actb.cpp +++ b/src/newgrf/newgrf_actb.cpp @@ -56,12 +56,12 @@ static void GRFLoadError(ByteReader &buf) uint8_t message_id = buf.ReadByte(); /* Skip the error if it isn't valid for the current language. */ - if (!CheckGrfLangID(lang, _cur.grffile->grf_version)) return; + if (!CheckGrfLangID(lang, _cur_gps.grffile->grf_version)) return; /* Skip the error until the activation stage unless bit 7 of the severity * is set. */ - if (!HasBit(severity, 7) && _cur.stage == GLS_INIT) { - GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur.stage); + if (!HasBit(severity, 7) && _cur_gps.stage == GLS_INIT) { + GrfMsg(7, "GRFLoadError: Skipping non-fatal GRFLoadError in stage {}", _cur_gps.stage); return; } ClrBit(severity, 7); @@ -75,7 +75,7 @@ static void GRFLoadError(ByteReader &buf) DisableGrf(); /* Make sure we show fatal errors, instead of silly infos from before */ - _cur.grfconfig->error.reset(); + _cur_gps.grfconfig->error.reset(); } if (message_id >= lengthof(msgstr) && message_id != 0xFF) { @@ -89,17 +89,17 @@ static void GRFLoadError(ByteReader &buf) } /* For now we can only show one message per newgrf file. */ - if (_cur.grfconfig->error.has_value()) return; + if (_cur_gps.grfconfig->error.has_value()) return; - _cur.grfconfig->error = {sevstr[severity]}; - GRFError *error = &_cur.grfconfig->error.value(); + _cur_gps.grfconfig->error = {sevstr[severity]}; + GRFError *error = &_cur_gps.grfconfig->error.value(); if (message_id == 0xFF) { /* This is a custom error message. */ if (buf.HasData()) { std::string_view message = buf.ReadString(); - error->custom_message = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER); + error->custom_message = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, message, SCC_RAW_STRING_POINTER); } else { GrfMsg(7, "GRFLoadError: No custom message supplied."); error->custom_message.clear(); @@ -111,7 +111,7 @@ static void GRFLoadError(ByteReader &buf) if (buf.HasData()) { std::string_view data = buf.ReadString(); - error->data = TranslateTTDPatchCodes(_cur.grffile->grfid, lang, true, data); + error->data = TranslateTTDPatchCodes(_cur_gps.grffile->grfid, lang, true, data); } else { GrfMsg(7, "GRFLoadError: No message data supplied."); error->data.clear(); @@ -120,7 +120,7 @@ static void GRFLoadError(ByteReader &buf) /* Only two parameter numbers can be used in the string. */ for (uint i = 0; i < error->param_value.size() && buf.HasData(); i++) { uint param_number = buf.ReadByte(); - error->param_value[i] = _cur.grffile->GetParam(param_number); + error->param_value[i] = _cur_gps.grffile->GetParam(param_number); } } diff --git a/src/newgrf/newgrf_actd.cpp b/src/newgrf/newgrf_actd.cpp index 62bfa546e3..8425f82eb9 100644 --- a/src/newgrf/newgrf_actd.cpp +++ b/src/newgrf/newgrf_actd.cpp @@ -139,11 +139,11 @@ static uint32_t PerformGRM(std::span grm, uint16_t count, uint8_t op, if (op == 6) { /* Return GRFID of set that reserved ID */ - return grm[_cur.grffile->GetParam(target)]; + return grm[_cur_gps.grffile->GetParam(target)]; } /* With an operation of 2 or 3, we want to reserve a specific block of IDs */ - if (op == 2 || op == 3) start = _cur.grffile->GetParam(target); + if (op == 2 || op == 3) start = _cur_gps.grffile->GetParam(target); for (uint i = start; i < std::size(grm); i++) { if (grm[i] == 0) { @@ -161,7 +161,7 @@ static uint32_t PerformGRM(std::span grm, uint16_t count, uint8_t op, /* Got the slot... */ if (op == 0 || op == 3) { GrfMsg(2, "ParamSet: GRM: Reserving {} {} at {}", count, type, start); - for (uint i = 0; i < count; i++) grm[start + i] = _cur.grffile->grfid; + for (uint i = 0; i < count; i++) grm[start + i] = _cur_gps.grffile->grfid; } return start; } @@ -218,7 +218,7 @@ static void ParamSet(ByteReader &buf) * - it OR A PARAMETER WITH HIGHER NUMBER has been set to any value by * an earlier action D */ if (HasBit(oper, 7)) { - if (target < 0x80 && target < std::size(_cur.grffile->param)) { + if (target < 0x80 && target < std::size(_cur_gps.grffile->param)) { GrfMsg(7, "ParamSet: Param {} already defined, skipping", target); return; } @@ -237,26 +237,26 @@ static void ParamSet(ByteReader &buf) uint8_t feature = GB(data, 8, 8); uint16_t count = GB(data, 16, 16); - if (_cur.stage == GLS_RESERVE) { + if (_cur_gps.stage == GLS_RESERVE) { if (feature == 0x08) { /* General sprites */ if (op == 0) { /* Check if the allocated sprites will fit below the original sprite limit */ - if (_cur.spriteid + count >= 16384) { + if (_cur_gps.spriteid + count >= 16384) { GrfMsg(0, "ParamSet: GRM: Unable to allocate {} sprites; try changing NewGRF order", count); DisableGrf(STR_NEWGRF_ERROR_GRM_FAILED); return; } /* Reserve space at the current sprite ID */ - GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur.spriteid); - _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)] = std::make_pair(_cur.spriteid, count); - _cur.spriteid += count; + GrfMsg(4, "ParamSet: GRM: Allocated {} sprites at {}", count, _cur_gps.spriteid); + _grm_sprites[GRFLocation(_cur_gps.grffile->grfid, _cur_gps.nfo_line)] = std::make_pair(_cur_gps.spriteid, count); + _cur_gps.spriteid += count; } } /* Ignore GRM result during reservation */ src1 = 0; - } else if (_cur.stage == GLS_ACTIVATION) { + } else if (_cur_gps.stage == GLS_ACTIVATION) { switch (feature) { case 0x00: // Trains case 0x01: // Road Vehicles @@ -264,13 +264,13 @@ static void ParamSet(ByteReader &buf) case 0x03: // Aircraft if (!_settings_game.vehicle.dynamic_engines) { src1 = PerformGRM({std::begin(_grm_engines) + _engine_offsets[feature], _engine_counts[feature]}, count, op, target, "vehicles"); - if (_cur.skip_sprites == -1) return; + if (_cur_gps.skip_sprites == -1) return; } else { /* GRM does not apply for dynamic engine allocation. */ switch (op) { case 2: case 3: - src1 = _cur.grffile->GetParam(target); + src1 = _cur_gps.grffile->GetParam(target); break; default: @@ -284,12 +284,12 @@ static void ParamSet(ByteReader &buf) switch (op) { case 0: /* Return space reserved during reservation stage */ - src1 = _grm_sprites[GRFLocation(_cur.grffile->grfid, _cur.nfo_line)].first; + src1 = _grm_sprites[GRFLocation(_cur_gps.grffile->grfid, _cur_gps.nfo_line)].first; GrfMsg(4, "ParamSet: GRM: Using pre-allocated sprites at {}", src1); break; case 1: - src1 = _cur.spriteid; + src1 = _cur_gps.spriteid; break; default: @@ -301,7 +301,7 @@ static void ParamSet(ByteReader &buf) case 0x0B: // Cargo /* There are two ranges: one for cargo IDs and one for cargo bitmasks */ src1 = PerformGRM(_grm_cargoes, count, op, target, "cargoes"); - if (_cur.skip_sprites == -1) return; + if (_cur_gps.skip_sprites == -1) return; break; default: GrfMsg(1, "ParamSet: GRM: Unsupported feature 0x{:X}", feature); return; @@ -315,7 +315,7 @@ static void ParamSet(ByteReader &buf) /* Read another GRF File's parameter */ const GRFFile *file = GetFileByGRFID(data); GRFConfig *c = GetGRFConfig(data); - if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) { + if (c != nullptr && c->flags.Test(GRFConfigFlag::Static) && !_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static) && _networking) { /* Disable the read GRF if it is a static NewGRF. */ DisableStaticNewGRFInfluencingNonStaticNewGRFs(*c); src1 = 0; @@ -420,7 +420,7 @@ static void ParamSet(ByteReader &buf) switch (target) { case 0x8E: // Y-Offset for train sprites - _cur.grffile->traininfo_vehicle_pitch = res; + _cur_gps.grffile->traininfo_vehicle_pitch = res; break; case 0x8F: { // Rail track type cost factors @@ -451,12 +451,12 @@ static void ParamSet(ByteReader &buf) GrfMiscBits bits(res); /* Set train list engine width */ - _cur.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH; + _cur_gps.grffile->traininfo_vehicle_width = bits.Test(GrfMiscBit::TrainWidth32Pixels) ? VEHICLEINFO_FULL_VEHICLE_WIDTH : TRAININFO_DEFAULT_VEHICLE_WIDTH; /* Remove the local flags from the global flags */ bits.Reset(GrfMiscBit::TrainWidth32Pixels); /* Only copy safe bits for static grfs */ - if (_cur.grfconfig->flags.Test(GRFConfigFlag::Static)) { + if (_cur_gps.grfconfig->flags.Test(GRFConfigFlag::Static)) { GrfMiscBits safe_bits = GrfMiscBit::SecondRockyTileSet; _misc_grf_features.Reset(safe_bits); @@ -474,8 +474,8 @@ static void ParamSet(ByteReader &buf) default: if (target < 0x80) { /* Resize (and fill with zeroes) if needed. */ - if (target >= std::size(_cur.grffile->param)) _cur.grffile->param.resize(target + 1); - _cur.grffile->param[target] = res; + if (target >= std::size(_cur_gps.grffile->param)) _cur_gps.grffile->param.resize(target + 1); + _cur_gps.grffile->param[target] = res; } else { GrfMsg(7, "ParamSet: Skipping unknown target 0x{:02X}", target); } diff --git a/src/newgrf/newgrf_acte.cpp b/src/newgrf/newgrf_acte.cpp index 6270fe4559..fdd923ce7b 100644 --- a/src/newgrf/newgrf_acte.cpp +++ b/src/newgrf/newgrf_acte.cpp @@ -30,7 +30,7 @@ static void SafeGRFInhibit(ByteReader &buf) uint32_t grfid = buf.ReadDWord(); /* GRF is unsafe it if tries to deactivate other GRFs */ - if (grfid != _cur.grfconfig->ident.grfid) { + if (grfid != _cur_gps.grfconfig->ident.grfid) { GRFUnsafe(buf); return; } @@ -52,10 +52,10 @@ static void GRFInhibit(ByteReader &buf) GRFConfig *file = GetGRFConfig(grfid); /* Unset activation flag */ - if (file != nullptr && file != _cur.grfconfig) { + if (file != nullptr && file != _cur_gps.grfconfig) { GrfMsg(2, "GRFInhibit: Deactivating file '{}'", file->filename); GRFError *error = DisableGrf(STR_NEWGRF_ERROR_FORCEFULLY_DISABLED, file); - error->data = _cur.grfconfig->GetName(); + error->data = _cur_gps.grfconfig->GetName(); } } } diff --git a/src/newgrf/newgrf_actf.cpp b/src/newgrf/newgrf_actf.cpp index 82503b4fd5..473ab023c6 100644 --- a/src/newgrf/newgrf_actf.cpp +++ b/src/newgrf/newgrf_actf.cpp @@ -27,7 +27,7 @@ static void FeatureTownName(ByteReader &buf) * B num-parts Number of parts in this definition * V parts The parts */ - uint32_t grfid = _cur.grffile->grfid; + uint32_t grfid = _cur_gps.grffile->grfid; GRFTownName *townname = AddGRFTownName(grfid); @@ -37,7 +37,7 @@ static void FeatureTownName(ByteReader &buf) if (HasBit(id, 7)) { /* Final definition */ ClrBit(id, 7); - bool new_scheme = _cur.grffile->grf_version >= 7; + bool new_scheme = _cur_gps.grffile->grf_version >= 7; uint8_t lang = buf.ReadByte(); StringID style = STR_UNDEFINED; diff --git a/src/newgrf/newgrf_internal.h b/src/newgrf/newgrf_internal.h index 642535198a..7f179b0c36 100644 --- a/src/newgrf/newgrf_internal.h +++ b/src/newgrf/newgrf_internal.h @@ -155,7 +155,7 @@ public: } }; -extern GrfProcessingState _cur; +extern GrfProcessingState _cur_gps; struct GRFLocation { uint32_t grfid; diff --git a/src/newgrf/newgrf_stringmapping.cpp b/src/newgrf/newgrf_stringmapping.cpp index 2063325d86..8441689488 100644 --- a/src/newgrf/newgrf_stringmapping.cpp +++ b/src/newgrf/newgrf_stringmapping.cpp @@ -42,7 +42,7 @@ static std::vector _string_to_grf_mapping; void AddStringForMapping(GRFStringID source, std::function &&func) { func(STR_UNDEFINED); - _string_to_grf_mapping.emplace_back(_cur.grffile->grfid, source, std::move(func)); + _string_to_grf_mapping.emplace_back(_cur_gps.grffile->grfid, source, std::move(func)); } /** From 7b31f266117ac90883037f80fb33f77d87980a79 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 10 Apr 2025 07:37:28 +0100 Subject: [PATCH 009/572] Codechange: Pass ContentInfo by reference. Many functions take a ContentInfo pointer, but do not check for nullptr. Pass by reference instead to assure it is present. --- src/ai/ai.hpp | 4 +- src/ai/ai_core.cpp | 4 +- src/base_media_base.h | 4 +- src/base_media_func.h | 8 ++-- src/bootstrap_gui.cpp | 10 ++--- src/console_cmds.cpp | 8 ++-- src/fios.cpp | 8 ++-- src/fios.h | 2 +- src/game/game.hpp | 4 +- src/game/game_core.cpp | 4 +- src/network/core/tcp_content.cpp | 16 +++---- src/network/network_content.cpp | 66 ++++++++++++++--------------- src/network/network_content.h | 14 +++--- src/network/network_content_gui.cpp | 20 ++++----- src/network/network_content_gui.h | 2 +- src/script/script_scanner.cpp | 10 ++--- src/script/script_scanner.hpp | 4 +- 17 files changed, 94 insertions(+), 94 deletions(-) diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp index 286c78f0e9..7a2d9fcb3d 100644 --- a/src/ai/ai.hpp +++ b/src/ai/ai.hpp @@ -135,8 +135,8 @@ public: static AIScannerLibrary *GetScannerLibrary(); /** Wrapper function for AIScanner::HasAI */ - static bool HasAI(const struct ContentInfo *ci, bool md5sum); - static bool HasAILibrary(const ContentInfo *ci, bool md5sum); + static bool HasAI(const ContentInfo &ci, bool md5sum); + static bool HasAILibrary(const ContentInfo &ci, bool md5sum); private: static uint frame_counter; ///< Tick counter for the AI code static std::unique_ptr scanner_info; ///< ScriptScanner instance that is used to find AIs diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp index f6fc28c68b..0283b38f66 100644 --- a/src/ai/ai_core.cpp +++ b/src/ai/ai_core.cpp @@ -334,12 +334,12 @@ * @param md5sum whether to check the MD5 checksum * @return true iff we have an AI (library) matching. */ -/* static */ bool AI::HasAI(const ContentInfo *ci, bool md5sum) +/* static */ bool AI::HasAI(const ContentInfo &ci, bool md5sum) { return AI::scanner_info->HasScript(ci, md5sum); } -/* static */ bool AI::HasAILibrary(const ContentInfo *ci, bool md5sum) +/* static */ bool AI::HasAILibrary(const ContentInfo &ci, bool md5sum) { return AI::scanner_library->HasScript(ci, md5sum); } diff --git a/src/base_media_base.h b/src/base_media_base.h index cd77cef4df..2c645ccfae 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -211,7 +211,7 @@ public: * @param md5sum whether to check the MD5 checksum * @return true iff we have an set matching. */ - static bool HasSet(const ContentInfo *ci, bool md5sum); + static bool HasSet(const ContentInfo &ci, bool md5sum); }; /** @@ -222,6 +222,6 @@ public: * @return The filename of the first file of the base set, or \c nullptr if there is no match. */ template -const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s); +const char *TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, const Tbase_set *s); #endif /* BASE_MEDIA_BASE_H */ diff --git a/src/base_media_func.h b/src/base_media_func.h index 4e32a12e94..2e0d644ff9 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -319,25 +319,25 @@ template #include "network/core/tcp_content_type.h" -template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) +template const char *TryGetBaseSetFile(const ContentInfo &ci, bool md5sum, const Tbase_set *s) { for (; s != nullptr; s = s->next) { if (s->GetNumMissing() != 0) continue; - if (s->shortname != ci->unique_id) continue; + if (s->shortname != ci.unique_id) continue; if (!md5sum) return s->files[0].filename.c_str(); MD5Hash md5; for (const auto &file : s->files) { md5 ^= file.hash; } - if (md5 == ci->md5sum) return s->files[0].filename.c_str(); + if (md5 == ci.md5sum) return s->files[0].filename.c_str(); } return nullptr; } template -/* static */ bool BaseMedia::HasSet(const ContentInfo *ci, bool md5sum) +/* static */ bool BaseMedia::HasSet(const ContentInfo &ci, bool md5sum) { return (TryGetBaseSetFile(ci, md5sum, BaseMedia::available_sets) != nullptr) || (TryGetBaseSetFile(ci, md5sum, BaseMedia::duplicate_sets) != nullptr); diff --git a/src/bootstrap_gui.cpp b/src/bootstrap_gui.cpp index b5d03fb506..44bce54ca8 100644 --- a/src/bootstrap_gui.cpp +++ b/src/bootstrap_gui.cpp @@ -273,10 +273,10 @@ public: _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); } - void OnReceiveContentInfo(const ContentInfo *ci) override + void OnReceiveContentInfo(const ContentInfo &ci) override { /* And once the meta data is received, start downloading it. */ - _network_content_client.Select(ci->id); + _network_content_client.Select(ci.id); new BootstrapContentDownloadStatusWindow(); this->Close(); } @@ -320,19 +320,19 @@ public: _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS); } - void OnReceiveContentInfo(const ContentInfo *ci) override + void OnReceiveContentInfo(const ContentInfo &ci) override { if (this->downloading) return; /* And once the metadata is received, start downloading it. */ - _network_content_client.Select(ci->id); + _network_content_client.Select(ci.id); _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes); this->downloading = true; EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes); } - void OnDownloadProgress(const ContentInfo *, int bytes) override + void OnDownloadProgress(const ContentInfo &, int bytes) override { /* A negative value means we are resetting; for example, when retrying or using a fallback. */ if (bytes < 0) { diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 93151f364b..327cb7eb54 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2128,14 +2128,14 @@ struct ConsoleContentCallback : public ContentCallback { * Outputs content state information to console * @param ci the content info */ -static void OutputContentState(const ContentInfo *const ci) +static void OutputContentState(const ContentInfo &ci) { static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" }; static_assert(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN); static const char * const states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" }; static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR }; - IConsolePrint(state_to_colour[ci->state], "{}, {}, {}, {}, {:08X}, {}", ci->id, types[ci->type - 1], states[ci->state], ci->name, ci->unique_id, FormatArrayAsHex(ci->md5sum)); + IConsolePrint(state_to_colour[ci.state], "{}, {}, {}, {}, {:08X}, {}", ci.id, types[ci.type - 1], states[ci.state], ci.name, ci.unique_id, FormatArrayAsHex(ci.md5sum)); } DEF_CONSOLE_CMD(ConContent) @@ -2173,7 +2173,7 @@ DEF_CONSOLE_CMD(ConContent) IConsolePrint(CC_WHITE, "id, type, state, name"); for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { if ((*iter)->state != ContentInfo::SELECTED && (*iter)->state != ContentInfo::AUTOSELECTED) continue; - OutputContentState(*iter); + OutputContentState(**iter); } } else if (StrEqualsIgnoreCase(argv[2], "all")) { /* The intention of this function was that you could download @@ -2206,7 +2206,7 @@ DEF_CONSOLE_CMD(ConContent) IConsolePrint(CC_WHITE, "id, type, state, name"); for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { if (argc > 2 && !StrContainsIgnoreCase((*iter)->name, argv[2])) continue; - OutputContentState(*iter); + OutputContentState(**iter); } return true; } diff --git a/src/fios.cpp b/src/fios.cpp index 760ca1e066..9206aa101a 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -680,13 +680,13 @@ static ScenarioScanner _scanner; * @param md5sum Whether to look at the md5sum or the id. * @return The filename of the file, else \c nullptr. */ -const char *FindScenario(const ContentInfo *ci, bool md5sum) +const char *FindScenario(const ContentInfo &ci, bool md5sum) { _scanner.Scan(false); for (ScenarioIdentifier &id : _scanner) { - if (md5sum ? (id.md5sum == ci->md5sum) - : (id.scenid == ci->unique_id)) { + if (md5sum ? (id.md5sum == ci.md5sum) + : (id.scenid == ci.unique_id)) { return id.filename.c_str(); } } @@ -700,7 +700,7 @@ const char *FindScenario(const ContentInfo *ci, bool md5sum) * @param md5sum Whether to look at the md5sum or the id. * @return True iff we've got the scenario. */ -bool HasScenario(const ContentInfo *ci, bool md5sum) +bool HasScenario(const ContentInfo &ci, bool md5sum) { return (FindScenario(ci, md5sum) != nullptr); } diff --git a/src/fios.h b/src/fios.h index e65b97141b..f73915f698 100644 --- a/src/fios.h +++ b/src/fios.h @@ -121,7 +121,7 @@ std::tuple FiosGetScenarioListCallback(SaveLoadOperation std::tuple FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext); void ScanScenarios(); -const char *FindScenario(const ContentInfo *ci, bool md5sum); +const char *FindScenario(const ContentInfo &ci, bool md5sum); /** * A savegame name automatically numbered. diff --git a/src/game/game.hpp b/src/game/game.hpp index d6e8ba65c5..e4931712a3 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -101,8 +101,8 @@ public: static void ResetInstance(); /** Wrapper function for GameScanner::HasGame */ - static bool HasGame(const struct ContentInfo *ci, bool md5sum); - static bool HasGameLibrary(const ContentInfo *ci, bool md5sum); + static bool HasGame(const ContentInfo &ci, bool md5sum); + static bool HasGameLibrary(const ContentInfo &ci, bool md5sum); /** Gets the ScriptScanner instance that is used to find Game scripts */ static GameScannerInfo *GetScannerInfo(); /** Gets the ScriptScanner instance that is used to find Game Libraries */ diff --git a/src/game/game_core.cpp b/src/game/game_core.cpp index dbd1b672c8..14ebcd9ab9 100644 --- a/src/game/game_core.cpp +++ b/src/game/game_core.cpp @@ -242,12 +242,12 @@ * @param md5sum whether to check the MD5 checksum * @return true iff we have an Game (library) matching. */ -/* static */ bool Game::HasGame(const ContentInfo *ci, bool md5sum) +/* static */ bool Game::HasGame(const ContentInfo &ci, bool md5sum) { return Game::scanner_info->HasScript(ci, md5sum); } -/* static */ bool Game::HasGameLibrary(const ContentInfo *ci, bool md5sum) +/* static */ bool Game::HasGameLibrary(const ContentInfo &ci, bool md5sum) { return Game::scanner_library->HasScript(ci, md5sum); } diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index c8e24547db..ea55a30542 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -63,16 +63,16 @@ std::optional ContentInfo::GetTextfile(TextfileType type) const switch (this->type) { default: NOT_REACHED(); case CONTENT_TYPE_AI: - tmp = AI::GetScannerInfo()->FindMainScript(this, true); + tmp = AI::GetScannerInfo()->FindMainScript(*this, true); break; case CONTENT_TYPE_AI_LIBRARY: - tmp = AI::GetScannerLibrary()->FindMainScript(this, true); + tmp = AI::GetScannerLibrary()->FindMainScript(*this, true); break; case CONTENT_TYPE_GAME: - tmp = Game::GetScannerInfo()->FindMainScript(this, true); + tmp = Game::GetScannerInfo()->FindMainScript(*this, true); break; case CONTENT_TYPE_GAME_LIBRARY: - tmp = Game::GetScannerLibrary()->FindMainScript(this, true); + tmp = Game::GetScannerLibrary()->FindMainScript(*this, true); break; case CONTENT_TYPE_NEWGRF: { const GRFConfig *gc = FindGRFConfig(std::byteswap(this->unique_id), FGCM_EXACT, &this->md5sum); @@ -80,17 +80,17 @@ std::optional ContentInfo::GetTextfile(TextfileType type) const break; } case CONTENT_TYPE_BASE_GRAPHICS: - tmp = TryGetBaseSetFile(this, true, BaseGraphics::GetAvailableSets()); + tmp = TryGetBaseSetFile(*this, true, BaseGraphics::GetAvailableSets()); break; case CONTENT_TYPE_BASE_SOUNDS: - tmp = TryGetBaseSetFile(this, true, BaseSounds::GetAvailableSets()); + tmp = TryGetBaseSetFile(*this, true, BaseSounds::GetAvailableSets()); break; case CONTENT_TYPE_BASE_MUSIC: - tmp = TryGetBaseSetFile(this, true, BaseMusic::GetAvailableSets()); + tmp = TryGetBaseSetFile(*this, true, BaseMusic::GetAvailableSets()); break; case CONTENT_TYPE_SCENARIO: case CONTENT_TYPE_HEIGHTMAP: - tmp = FindScenario(this, true); + tmp = FindScenario(*this, true); break; } if (tmp == nullptr) return std::nullopt; diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 3848ffc6ca..eb6bc31db4 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -38,15 +38,15 @@ #include "../safeguards.h" -extern bool HasScenario(const ContentInfo *ci, bool md5sum); +extern bool HasScenario(const ContentInfo &ci, bool md5sum); /** The client we use to connect to the server. */ ClientNetworkContentSocketHandler _network_content_client; /** Wrapper function for the HasProc */ -static bool HasGRFConfig(const ContentInfo *ci, bool md5sum) +static bool HasGRFConfig(const ContentInfo &ci, bool md5sum) { - return FindGRFConfig(std::byteswap(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? &ci->md5sum : nullptr) != nullptr; + return FindGRFConfig(std::byteswap(ci.unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? &ci.md5sum : nullptr) != nullptr; } /** @@ -56,7 +56,7 @@ static bool HasGRFConfig(const ContentInfo *ci, bool md5sum) * @param md5sum also match the MD5 checksum? * @return true iff it's known */ -using HasContentProc = bool(const ContentInfo *ci, bool md5sum); +using HasContentProc = bool(const ContentInfo &ci, bool md5sum); /** * Get the has-content check function for the given content type. @@ -115,11 +115,11 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) HasContentProc *proc = GetHasContentProcforContentType(ci->type); if (proc != nullptr) { - if (proc(ci, true)) { + if (proc(*ci, true)) { ci->state = ContentInfo::ALREADY_HERE; } else { ci->state = ContentInfo::UNSELECTED; - if (proc(ci, false)) ci->upgrade = true; + if (proc(*ci, false)) ci->upgrade = true; } } else { ci->state = ContentInfo::UNSELECTED; @@ -143,7 +143,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) *ici = *ci; delete ci; - this->OnReceiveContentInfo(ici); + this->OnReceiveContentInfo(*ici); return true; } } @@ -160,10 +160,10 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) ConstContentVector parents; this->ReverseLookupTreeDependency(parents, ci); for (const ContentInfo *ici : parents) { - this->CheckDependencyState(ici); + this->CheckDependencyState(*ici); } - this->OnReceiveContentInfo(ci); + this->OnReceiveContentInfo(*ci); return true; } @@ -489,7 +489,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p) return false; } - this->OnDownloadProgress(this->cur_info, (int)to_read); + this->OnDownloadProgress(*this->cur_info, (int)to_read); if (to_read == 0) this->AfterDownload(); } @@ -574,7 +574,7 @@ void ClientNetworkContentSocketHandler::OnFailure() this->http_response_index = -2; if (this->cur_file.has_value()) { - this->OnDownloadProgress(this->cur_info, -1); + this->OnDownloadProgress(*this->cur_info, -1); this->cur_file.reset(); } @@ -617,7 +617,7 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr da this->OnFailure(); } else { /* Just received the data. */ - this->OnDownloadProgress(this->cur_info, (int)length); + this->OnDownloadProgress(*this->cur_info, (int)length); } /* Nothing more to do now. */ @@ -861,7 +861,7 @@ void ClientNetworkContentSocketHandler::Select(ContentID cid) if (ci == nullptr || ci->state != ContentInfo::UNSELECTED) return; ci->state = ContentInfo::SELECTED; - this->CheckDependencyState(ci); + this->CheckDependencyState(*ci); } /** @@ -874,7 +874,7 @@ void ClientNetworkContentSocketHandler::Unselect(ContentID cid) if (ci == nullptr || !ci->IsSelected()) return; ci->state = ContentInfo::UNSELECTED; - this->CheckDependencyState(ci); + this->CheckDependencyState(*ci); } /** Select everything we can select */ @@ -883,7 +883,7 @@ void ClientNetworkContentSocketHandler::SelectAll() for (ContentInfo *ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED) { ci->state = ContentInfo::SELECTED; - this->CheckDependencyState(ci); + this->CheckDependencyState(*ci); } } } @@ -894,7 +894,7 @@ void ClientNetworkContentSocketHandler::SelectUpgrade() for (ContentInfo *ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) { ci->state = ContentInfo::SELECTED; - this->CheckDependencyState(ci); + this->CheckDependencyState(*ci); } } } @@ -908,16 +908,16 @@ void ClientNetworkContentSocketHandler::UnselectAll() } /** Toggle the state of a content info and check its dependencies */ -void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *ci) +void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo &ci) { - switch (ci->state) { + switch (ci.state) { case ContentInfo::SELECTED: case ContentInfo::AUTOSELECTED: - this->Unselect(ci->id); + this->Unselect(ci.id); break; case ContentInfo::UNSELECTED: - this->Select(ci->id); + this->Select(ci.id); break; default: @@ -930,9 +930,9 @@ void ClientNetworkContentSocketHandler::ToggleSelectedState(const ContentInfo *c * @param parents list to store all parents in (is not cleared) * @param child the child to search the parents' dependencies for */ -void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const +void ClientNetworkContentSocketHandler::ReverseLookupDependency(ConstContentVector &parents, const ContentInfo &child) const { - auto range = this->reverse_dependency_map.equal_range(child->id); + auto range = this->reverse_dependency_map.equal_range(child.id); for (auto iter = range.first; iter != range.second; ++iter) { parents.push_back(GetContent(iter->second)); @@ -954,7 +954,7 @@ void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContent * pointer gets invalid. So fall back to the indices. */ for (uint i = 0; i < tree.size(); i++) { ConstContentVector parents; - this->ReverseLookupDependency(parents, tree[i]); + this->ReverseLookupDependency(parents, *tree[i]); for (const ContentInfo *ci : parents) { include(tree, ci); @@ -966,25 +966,25 @@ void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContent * Check the dependencies (recursively) of this content info * @param ci the content info to check the dependencies of */ -void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo *ci) +void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo &ci) { - if (ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) { + if (ci.IsSelected() || ci.state == ContentInfo::ALREADY_HERE) { /* Selection is easy; just walk all children and set the * autoselected state. That way we can see what we automatically * selected and thus can unselect when a dependency is removed. */ - for (auto &dependency : ci->dependencies) { + for (auto &dependency : ci.dependencies) { ContentInfo *c = this->GetContent(dependency); if (c == nullptr) { this->DownloadContentInfo(dependency); } else if (c->state == ContentInfo::UNSELECTED) { c->state = ContentInfo::AUTOSELECTED; - this->CheckDependencyState(c); + this->CheckDependencyState(*c); } } return; } - if (ci->state != ContentInfo::UNSELECTED) return; + if (ci.state != ContentInfo::UNSELECTED) return; /* For unselection we need to find the parents of us. We need to * unselect them. After that we unselect all children that we @@ -998,7 +998,7 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo * this->Unselect(c->id); } - for (auto &dependency : ci->dependencies) { + for (auto &dependency : ci.dependencies) { const ContentInfo *c = this->GetContent(dependency); if (c == nullptr) { DownloadContentInfo(dependency); @@ -1008,7 +1008,7 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo * /* Only unselect when WE are the only parent. */ parents.clear(); - this->ReverseLookupDependency(parents, c); + this->ReverseLookupDependency(parents, *c); /* First check whether anything depends on us */ int sel_count = 0; @@ -1048,7 +1048,7 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo * if (parent->state == ContentInfo::AUTOSELECTED) this->Unselect(parent->id); } for (const ContentInfo *parent : parents) { - this->CheckDependencyState(this->GetContent(parent->id)); + this->CheckDependencyState(*this->GetContent(parent->id)); } } } @@ -1084,7 +1084,7 @@ void ClientNetworkContentSocketHandler::OnDisconnect() } } -void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo *ci) +void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo &ci) { for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { ContentCallback *cb = this->callbacks[i]; @@ -1094,7 +1094,7 @@ void ClientNetworkContentSocketHandler::OnReceiveContentInfo(const ContentInfo * } } -void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo *ci, int bytes) +void ClientNetworkContentSocketHandler::OnDownloadProgress(const ContentInfo &ci, int bytes) { for (size_t i = 0; i < this->callbacks.size(); /* nothing */) { ContentCallback *cb = this->callbacks[i]; diff --git a/src/network/network_content.h b/src/network/network_content.h index ee145ff6a4..0f09ee958c 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -42,14 +42,14 @@ struct ContentCallback { * We received a content info. * @param ci the content info */ - virtual void OnReceiveContentInfo([[maybe_unused]] const ContentInfo *ci) {} + virtual void OnReceiveContentInfo([[maybe_unused]] const ContentInfo &ci) {} /** * We have progress in the download of a file * @param ci the content info of the file * @param bytes the number of bytes downloaded since the previous call */ - virtual void OnDownloadProgress([[maybe_unused]] const ContentInfo *ci, [[maybe_unused]] int bytes) {} + virtual void OnDownloadProgress([[maybe_unused]] const ContentInfo &ci, [[maybe_unused]] int bytes) {} /** * We have finished downloading a file @@ -90,8 +90,8 @@ protected: void OnConnect(bool success) override; void OnDisconnect() override; - void OnReceiveContentInfo(const ContentInfo *ci) override; - void OnDownloadProgress(const ContentInfo *ci, int bytes) override; + void OnReceiveContentInfo(const ContentInfo &ci) override; + void OnDownloadProgress(const ContentInfo &ci, int bytes) override; void OnDownloadComplete(ContentID cid) override; void OnFailure() override; @@ -126,11 +126,11 @@ public: void SelectAll(); void SelectUpgrade(); void UnselectAll(); - void ToggleSelectedState(const ContentInfo *ci); + void ToggleSelectedState(const ContentInfo &ci); - void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo *child) const; + void ReverseLookupDependency(ConstContentVector &parents, const ContentInfo &child) const; void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const; - void CheckDependencyState(const ContentInfo *ci); + void CheckDependencyState(const ContentInfo &ci); /** Get the number of content items we know locally. */ uint Length() const { return (uint)this->infos.size(); } diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 7a9ff3d124..c795ef8e0c 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -165,11 +165,11 @@ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, WidgetID } } -void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo *ci, int bytes) +void BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(const ContentInfo &ci, int bytes) { - if (ci->id != this->cur_id) { - this->name = ci->filename; - this->cur_id = ci->id; + if (ci.id != this->cur_id) { + this->name = ci.filename; + this->cur_id = ci.id; this->downloaded_files++; } @@ -298,10 +298,10 @@ public: } } - void OnDownloadProgress(const ContentInfo *ci, int bytes) override + void OnDownloadProgress(const ContentInfo &ci, int bytes) override { BaseNetworkContentDownloadStatusWindow::OnDownloadProgress(ci, bytes); - include(this->receivedTypes, ci->type); + include(this->receivedTypes, ci.type); /* When downloading is finished change cancel in ok */ if (this->downloaded_bytes == this->total_bytes) { @@ -792,7 +792,7 @@ public: const NWidgetBase *checkbox = this->GetWidget(WID_NCL_CHECKBOX); if (click_count > 1 || IsInsideBS(pt.x, checkbox->pos_x, checkbox->current_x)) { - _network_content_client.ToggleSelectedState(this->selected); + _network_content_client.ToggleSelectedState(*this->selected); this->content.ForceResort(); this->content.ForceRebuild(); } @@ -870,7 +870,7 @@ public: case WKC_RETURN: if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { if (this->selected != nullptr) { - _network_content_client.ToggleSelectedState(this->selected); + _network_content_client.ToggleSelectedState(*this->selected); this->content.ForceResort(); this->InvalidateData(); } @@ -925,9 +925,9 @@ public: this->vscroll->SetCapacityFromWidget(this, WID_NCL_MATRIX); } - void OnReceiveContentInfo(const ContentInfo *rci) override + void OnReceiveContentInfo(const ContentInfo &rci) override { - if (this->auto_select && !rci->IsSelected()) _network_content_client.ToggleSelectedState(rci); + if (this->auto_select && !rci.IsSelected()) _network_content_client.ToggleSelectedState(rci); this->content.ForceRebuild(); this->InvalidateData(0, false); } diff --git a/src/network/network_content_gui.h b/src/network/network_content_gui.h index 2de7b262df..6fd71d0ad8 100644 --- a/src/network/network_content_gui.h +++ b/src/network/network_content_gui.h @@ -35,7 +35,7 @@ public: void Close([[maybe_unused]] int data = 0) override; void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override; void DrawWidget(const Rect &r, WidgetID widget) const override; - void OnDownloadProgress(const ContentInfo *ci, int bytes) override; + void OnDownloadProgress(const ContentInfo &ci, int bytes) override; }; void BuildContentTypeStringList(); diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index f21ffa1dc5..0f9daac8c9 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -195,13 +195,13 @@ struct ScriptFileChecksumCreator : FileScanner { * @param info The script to get the shortname and md5 sum from. * @return True iff they're the same. */ -static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir) +static bool IsSameScript(const ContentInfo &ci, bool md5sum, ScriptInfo *info, Subdirectory dir) { uint32_t id = 0; const char *str = info->GetShortName().c_str(); for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j); - if (id != ci->unique_id) return false; + if (id != ci.unique_id) return false; if (!md5sum) return true; ScriptFileChecksumCreator checksum(dir); @@ -229,10 +229,10 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S checksum.Scan(".nut", path); } - return ci->md5sum == checksum.md5sum; + return ci.md5sum == checksum.md5sum; } -bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum) +bool ScriptScanner::HasScript(const ContentInfo &ci, bool md5sum) { for (const auto &item : this->info_list) { if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return true; @@ -240,7 +240,7 @@ bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum) return false; } -const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum) +const char *ScriptScanner::FindMainScript(const ContentInfo &ci, bool md5sum) { for (const auto &item : this->info_list) { if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript().c_str(); diff --git a/src/script/script_scanner.hpp b/src/script/script_scanner.hpp index 1f5dca0485..30a9b5f018 100644 --- a/src/script/script_scanner.hpp +++ b/src/script/script_scanner.hpp @@ -66,7 +66,7 @@ public: * @param md5sum Whether to check the MD5 checksum. * @return True iff we have a script matching. */ - bool HasScript(const struct ContentInfo *ci, bool md5sum); + bool HasScript(const struct ContentInfo &ci, bool md5sum); /** * Find a script of a #ContentInfo @@ -74,7 +74,7 @@ public: * @param md5sum Whether to check the MD5 checksum. * @return A filename of a file of the content, else \c nullptr. */ - const char *FindMainScript(const ContentInfo *ci, bool md5sum); + const char *FindMainScript(const ContentInfo &ci, bool md5sum); bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; From 20d83677ebdb6a1c5233ce10e7b1e2c7bb5d6872 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Thu, 10 Apr 2025 08:34:59 +0100 Subject: [PATCH 010/572] Codechange: Use unique_ptr to manage ContentInfo lifetime. Removes manually managed new/delete. --- src/console_cmds.cpp | 12 ++--- src/network/network_content.cpp | 69 ++++++++++++----------------- src/network/network_content.h | 27 +++++------ src/network/network_content_gui.cpp | 18 +++----- src/newgrf_gui.cpp | 4 +- 5 files changed, 52 insertions(+), 78 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 327cb7eb54..cb091832ff 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -2171,9 +2171,9 @@ DEF_CONSOLE_CMD(ConContent) if (argc <= 2) { /* List selected content */ IConsolePrint(CC_WHITE, "id, type, state, name"); - for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { - if ((*iter)->state != ContentInfo::SELECTED && (*iter)->state != ContentInfo::AUTOSELECTED) continue; - OutputContentState(**iter); + for (const ContentInfo &ci : _network_content_client.Info()) { + if (ci.state != ContentInfo::SELECTED && ci.state != ContentInfo::AUTOSELECTED) continue; + OutputContentState(ci); } } else if (StrEqualsIgnoreCase(argv[2], "all")) { /* The intention of this function was that you could download @@ -2204,9 +2204,9 @@ DEF_CONSOLE_CMD(ConContent) if (StrEqualsIgnoreCase(argv[1], "state")) { IConsolePrint(CC_WHITE, "id, type, state, name"); - for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { - if (argc > 2 && !StrContainsIgnoreCase((*iter)->name, argv[2])) continue; - OutputContentState(**iter); + for (const ContentInfo &ci : _network_content_client.Info()) { + if (argc > 2 && !StrContainsIgnoreCase(ci.name, argv[2])) continue; + OutputContentState(ci); } return true; } diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index eb6bc31db4..d93fc012e7 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -82,7 +82,7 @@ static HasContentProc *GetHasContentProcforContentType(ContentType type) bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) { - ContentInfo *ci = new ContentInfo(); + auto ci = std::make_unique(); ci->type = (ContentType)p.Recv_uint8(); ci->id = (ContentID)p.Recv_uint32(); ci->filesize = p.Recv_uint32(); @@ -108,7 +108,6 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) for (uint i = 0; i < tag_count; i++) ci->tags.push_back(p.Recv_string(NETWORK_CONTENT_TAG_LENGTH)); if (!ci->IsValid()) { - delete ci; this->CloseConnection(); return false; } @@ -129,7 +128,7 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST; /* Do we already have a stub for this? */ - for (ContentInfo *ici : this->infos) { + for (const auto &ici : this->infos) { if (ici->type == ci->type && ici->unique_id == ci->unique_id && ci->md5sum == ici->md5sum) { /* Preserve the name if possible */ if (ci->name.empty()) ci->name = ici->name; @@ -141,7 +140,6 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) * we (just) already preserved. */ *ici = *ci; - delete ci; this->OnReceiveContentInfo(*ici); return true; @@ -150,20 +148,19 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_INFO(Packet &p) /* Missing content info? Don't list it */ if (ci->filesize == 0) { - delete ci; return true; } - this->infos.push_back(ci); + ContentInfo *info = this->infos.emplace_back(std::move(ci)).get(); /* Incoming data means that we might need to reconsider dependencies */ ConstContentVector parents; - this->ReverseLookupTreeDependency(parents, ci); + this->ReverseLookupTreeDependency(parents, info); for (const ContentInfo *ici : parents) { this->CheckDependencyState(*ici); } - this->OnReceiveContentInfo(*ci); + this->OnReceiveContentInfo(*info); return true; } @@ -257,7 +254,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo auto p = std::make_unique(this, send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU); p->Send_uint8((uint8_t)cv->size()); - for (const ContentInfo *ci : *cv) { + for (const auto &ci : *cv) { p->Send_uint8((uint8_t)ci->type); p->Send_uint32(ci->unique_id); if (!send_md5sum) continue; @@ -266,9 +263,9 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo this->SendPacket(std::move(p)); - for (ContentInfo *ci : *cv) { + for (auto &ci : *cv) { bool found = false; - for (ContentInfo *ci2 : this->infos) { + for (const auto &ci2 : this->infos) { if (ci->type == ci2->type && ci->unique_id == ci2->unique_id && (!send_md5sum || ci->md5sum == ci2->md5sum)) { found = true; @@ -276,9 +273,7 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo } } if (!found) { - this->infos.push_back(ci); - } else { - delete ci; + this->infos.push_back(std::move(ci)); } } } @@ -294,7 +289,7 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContent(uint &files, uin bytes = 0; ContentIDList content; - for (const ContentInfo *ci : this->infos) { + for (const auto &ci : this->infos) { if (!ci->IsSelected() || ci->state == ContentInfo::ALREADY_HERE) continue; content.push_back(ci->id); @@ -368,13 +363,13 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co * @return a statically allocated buffer with the filename or * nullptr when no filename could be made. */ -static std::string GetFullFilename(const ContentInfo *ci, bool compressed) +static std::string GetFullFilename(const ContentInfo &ci, bool compressed) { - Subdirectory dir = GetContentInfoSubDir(ci->type); + Subdirectory dir = GetContentInfoSubDir(ci.type); if (dir == NO_DIRECTORY) return {}; std::string buf = FioGetDirectory(SP_AUTODOWNLOAD_DIR, dir); - buf += ci->filename; + buf += ci.filename; buf += compressed ? ".tar.gz" : ".tar"; return buf; @@ -385,7 +380,7 @@ static std::string GetFullFilename(const ContentInfo *ci, bool compressed) * @param ci container with filename * @return true if the gunzip completed */ -static bool GunzipFile(const ContentInfo *ci) +static bool GunzipFile(const ContentInfo &ci) { #if defined(WITH_ZLIB) bool ret = true; @@ -462,9 +457,8 @@ static inline ssize_t TransferOutFWrite(std::optional &file, const c bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p) { if (!this->cur_file.has_value()) { - delete this->cur_info; /* When we haven't opened a file this must be our first packet with metadata. */ - this->cur_info = new ContentInfo; + this->cur_info = std::make_unique(); this->cur_info->type = (ContentType)p.Recv_uint8(); this->cur_info->id = (ContentID)p.Recv_uint32(); this->cur_info->filesize = p.Recv_uint32(); @@ -504,14 +498,13 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p) bool ClientNetworkContentSocketHandler::BeforeDownload() { if (!this->cur_info->IsValid()) { - delete this->cur_info; - this->cur_info = nullptr; + this->cur_info.reset(); return false; } if (this->cur_info->filesize != 0) { /* The filesize is > 0, so we are going to download it */ - std::string filename = GetFullFilename(this->cur_info, true); + std::string filename = GetFullFilename(*this->cur_info, true); if (filename.empty() || !(this->cur_file = FileHandle::Open(filename, "wb")).has_value()) { /* Unless that fails of course... */ CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); @@ -535,14 +528,14 @@ void ClientNetworkContentSocketHandler::AfterDownload() * Now gunzip the tar and make it known. */ this->cur_file.reset(); - if (GunzipFile(this->cur_info)) { - FioRemove(GetFullFilename(this->cur_info, true)); + if (GunzipFile(*this->cur_info)) { + FioRemove(GetFullFilename(*this->cur_info, true)); Subdirectory sd = GetContentInfoSubDir(this->cur_info->type); if (sd == NO_DIRECTORY) NOT_REACHED(); TarScanner ts; - std::string fname = GetFullFilename(this->cur_info, false); + std::string fname = GetFullFilename(*this->cur_info, false); ts.AddFile(sd, fname); if (this->cur_info->type == CONTENT_TYPE_BASE_MUSIC) { @@ -637,9 +630,8 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr da return; } - delete this->cur_info; /* When we haven't opened a file this must be our first packet with metadata. */ - this->cur_info = new ContentInfo; + this->cur_info = std::make_unique(); /** Check p for not being null and return calling OnFailure if that's not the case. */ #define check_not_null(p) { if ((p) == nullptr) { this->OnFailure(); return; } } @@ -732,9 +724,6 @@ ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() : /** Clear up the mess ;) */ ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler() { - delete this->cur_info; - - for (ContentInfo *ci : this->infos) delete ci; } /** Connect to the content server. */ @@ -844,8 +833,8 @@ void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid) */ ContentInfo *ClientNetworkContentSocketHandler::GetContent(ContentID cid) const { - for (ContentInfo *ci : this->infos) { - if (ci->id == cid) return ci; + for (const auto &ci : this->infos) { + if (ci->id == cid) return ci.get(); } return nullptr; } @@ -880,7 +869,7 @@ void ClientNetworkContentSocketHandler::Unselect(ContentID cid) /** Select everything we can select */ void ClientNetworkContentSocketHandler::SelectAll() { - for (ContentInfo *ci : this->infos) { + for (const auto &ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(*ci); @@ -891,7 +880,7 @@ void ClientNetworkContentSocketHandler::SelectAll() /** Select everything that's an update for something we've got */ void ClientNetworkContentSocketHandler::SelectUpgrade() { - for (ContentInfo *ci : this->infos) { + for (const auto &ci : this->infos) { if (ci->state == ContentInfo::UNSELECTED && ci->upgrade) { ci->state = ContentInfo::SELECTED; this->CheckDependencyState(*ci); @@ -902,7 +891,7 @@ void ClientNetworkContentSocketHandler::SelectUpgrade() /** Unselect everything that we've not downloaded so far. */ void ClientNetworkContentSocketHandler::UnselectAll() { - for (ContentInfo *ci : this->infos) { + for (const auto &ci : this->infos) { if (ci->IsSelected() && ci->state != ContentInfo::ALREADY_HERE) ci->state = ContentInfo::UNSELECTED; } } @@ -952,9 +941,9 @@ void ClientNetworkContentSocketHandler::ReverseLookupTreeDependency(ConstContent * we are including stuff into the vector and as such the vector's data * store can be reallocated (and thus move), which means out iterating * pointer gets invalid. So fall back to the indices. */ - for (uint i = 0; i < tree.size(); i++) { + for (const ContentInfo *ci : tree) { ConstContentVector parents; - this->ReverseLookupDependency(parents, *tree[i]); + this->ReverseLookupDependency(parents, *ci); for (const ContentInfo *ci : parents) { include(tree, ci); @@ -1056,8 +1045,6 @@ void ClientNetworkContentSocketHandler::CheckDependencyState(const ContentInfo & /** Clear all downloaded content information. */ void ClientNetworkContentSocketHandler::Clear() { - for (ContentInfo *c : this->infos) delete c; - this->infos.clear(); this->requested.clear(); this->reverse_dependency_map.clear(); diff --git a/src/network/network_content.h b/src/network/network_content.h index 0f09ee958c..e905b21b97 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -10,20 +10,16 @@ #ifndef NETWORK_CONTENT_H #define NETWORK_CONTENT_H +#include #include "core/tcp_content.h" #include "core/http.h" #include #include "../core/container_func.hpp" /** Vector with content info */ -typedef std::vector ContentVector; +using ContentVector = std::vector>; /** Vector with constant content info */ -typedef std::vector ConstContentVector; - -/** Iterator for the content vector */ -typedef ContentInfo **ContentIterator; -/** Iterator for the constant content vector */ -typedef const ContentInfo * const * ConstContentIterator; +using ConstContentVector = std::vector; /** Callbacks for notifying others about incoming data */ struct ContentCallback { @@ -66,7 +62,7 @@ struct ContentCallback { */ class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback, HTTPCallback { protected: - typedef std::vector ContentIDList; ///< List of content IDs to (possibly) select. + using ContentIDList = std::vector; ///< List of content IDs to (possibly) select. std::vector callbacks; ///< Callbacks to notify "the world" ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) ContentVector infos; ///< All content info we received @@ -75,7 +71,7 @@ protected: int http_response_index; ///< Where we are, in the response, with handling it std::optional cur_file; ///< Currently downloaded file - ContentInfo *cur_info; ///< Information about the currently downloaded file + std::unique_ptr cur_info; ///< Information about the currently downloaded file bool is_connecting; ///< Whether we're connecting bool is_cancelled; ///< Whether the download has been cancelled std::chrono::steady_clock::time_point last_activity; ///< The last time there was network activity @@ -132,14 +128,11 @@ public: void ReverseLookupTreeDependency(ConstContentVector &tree, const ContentInfo *child) const; void CheckDependencyState(const ContentInfo &ci); - /** Get the number of content items we know locally. */ - uint Length() const { return (uint)this->infos.size(); } - /** Get the begin of the content inf iterator. */ - ConstContentIterator Begin() const { return this->infos.data(); } - /** Get the nth position of the content inf iterator. */ - ConstContentIterator Get(uint32_t index) const { return this->infos.data() + index; } - /** Get the end of the content inf iterator. */ - ConstContentIterator End() const { return this->Begin() + this->Length(); } + /** + * Get a read-only view of content info for iterating externally. + * @return Read-only view of content info. + */ + auto Info() const { return this->infos | std::views::transform([](const auto &ci) -> const ContentInfo & { return *ci; }); } void Clear(); diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index c795ef8e0c..de77cc6dd7 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -410,9 +410,9 @@ class NetworkContentListWindow : public Window, ContentCallback { bool all_available = true; - for (ConstContentIterator iter = _network_content_client.Begin(); iter != _network_content_client.End(); iter++) { - if ((*iter)->state == ContentInfo::DOES_NOT_EXIST) all_available = false; - this->content.push_back(*iter); + for (const ContentInfo &ci : _network_content_client.Info()) { + if (ci.state == ContentInfo::DOES_NOT_EXIST) all_available = false; + this->content.push_back(&ci); } this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select && all_available); @@ -732,13 +732,11 @@ public: std::string buf; for (auto &cid : this->selected->dependencies) { /* Try to find the dependency */ - ConstContentIterator iter = _network_content_client.Begin(); - for (; iter != _network_content_client.End(); iter++) { - const ContentInfo *ci = *iter; - if (ci->id != cid) continue; + for (const ContentInfo &ci : _network_content_client.Info()) { + if (ci.id != cid) continue; if (!buf.empty()) buf += list_separator; - buf += (*iter)->name; + buf += ci.name; break; } } @@ -1138,9 +1136,5 @@ void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentT GetEncodedString(STR_CONTENT_NO_ZLIB), GetEncodedString(STR_CONTENT_NO_ZLIB_SUB), WL_ERROR); - /* Connection failed... clean up the mess */ - if (cv != nullptr) { - for (ContentInfo *ci : *cv) delete ci; - } #endif /* WITH_ZLIB */ } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 9a36c269d2..2b145522d3 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1517,13 +1517,13 @@ void ShowMissingContentWindow(const GRFConfigList &list) for (const auto &c : list) { if (c->status != GCS_NOT_FOUND && !c->flags.Test(GRFConfigFlag::Compatible)) continue; - ContentInfo *ci = new ContentInfo(); + auto ci = std::make_unique(); ci->type = CONTENT_TYPE_NEWGRF; ci->state = ContentInfo::DOES_NOT_EXIST; ci->name = c->GetName(); ci->unique_id = std::byteswap(c->ident.grfid); ci->md5sum = c->flags.Test(GRFConfigFlag::Compatible) ? c->original_md5sum : c->ident.md5sum; - cv.push_back(ci); + cv.push_back(std::move(ci)); } ShowNetworkContentListWindow(cv.empty() ? nullptr : &cv, CONTENT_TYPE_NEWGRF); } From 3347919fb2242eebcd32c8cf6358807d15e63b39 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 11 Apr 2025 21:19:42 +0100 Subject: [PATCH 011/572] Codechange: Remove empty destructor and use member init for ClientNetworkContentSocketHandler. --- src/network/network_content.cpp | 19 ------------------- src/network/network_content.h | 19 ++++++++----------- 2 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index d93fc012e7..362fedfd62 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -707,25 +707,6 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr da #undef check_and_terminate } -/** - * Create a socket handler to handle the connection. - */ -ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() : - NetworkContentSocketHandler(), - http_response_index(-2), - cur_file(std::nullopt), - cur_info(nullptr), - is_connecting(false), - is_cancelled(false) -{ - this->last_activity = std::chrono::steady_clock::now(); -} - -/** Clear up the mess ;) */ -ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler() -{ -} - /** Connect to the content server. */ class NetworkContentConnecter : public TCPConnecter { public: diff --git a/src/network/network_content.h b/src/network/network_content.h index e905b21b97..b00047abdd 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -63,18 +63,18 @@ struct ContentCallback { class ClientNetworkContentSocketHandler : public NetworkContentSocketHandler, ContentCallback, HTTPCallback { protected: using ContentIDList = std::vector; ///< List of content IDs to (possibly) select. - std::vector callbacks; ///< Callbacks to notify "the world" - ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) - ContentVector infos; ///< All content info we received + std::vector callbacks; ///< Callbacks to notify "the world" + ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) + ContentVector infos; ///< All content info we received std::unordered_multimap reverse_dependency_map; ///< Content reverse dependency map - std::vector http_response; ///< The HTTP response to the requests we've been doing - int http_response_index; ///< Where we are, in the response, with handling it + std::vector http_response; ///< The HTTP response to the requests we've been doing + int http_response_index = -2; ///< Where we are, in the response, with handling it std::optional cur_file; ///< Currently downloaded file std::unique_ptr cur_info; ///< Information about the currently downloaded file - bool is_connecting; ///< Whether we're connecting - bool is_cancelled; ///< Whether the download has been cancelled - std::chrono::steady_clock::time_point last_activity; ///< The last time there was network activity + bool is_connecting = false; ///< Whether we're connecting + bool is_cancelled = false; ///< Whether the download has been cancelled + std::chrono::steady_clock::time_point last_activity = std::chrono::steady_clock::now(); ///< The last time there was network activity friend class NetworkContentConnecter; @@ -103,9 +103,6 @@ public: /** The idle timeout; when to close the connection because it's idle. */ static constexpr std::chrono::seconds IDLE_TIMEOUT = std::chrono::seconds(60); - ClientNetworkContentSocketHandler(); - ~ClientNetworkContentSocketHandler(); - void Connect(); void SendReceive(); NetworkRecvStatus CloseConnection(bool error = true) override; From c29ef5cfc2b66b4acac44c60d6698e8351cba28a Mon Sep 17 00:00:00 2001 From: translators Date: Sat, 12 Apr 2025 04:44:34 +0000 Subject: [PATCH 012/572] Update: Translations from eints english (us): 1 change by 2TallTyler --- src/lang/english_US.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 09cbd73417..5fd0bc5f08 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -2020,7 +2020,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Maximum number STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Number of non-sticky open windows before old windows get automatically closed to make room for new windows STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :disabled +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Disabled STR_CONFIG_SETTING_ZOOM_MIN :Maximum zoom in level: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :The maximum zoom-in level for viewports. Note that enabling higher zoom-in levels increases memory requirements From 1744156149074ba9df6fae753c46600fbc4f034e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 12 Apr 2025 12:50:36 +0100 Subject: [PATCH 013/572] Change: Queue content ID information requests. (#13990) Instead of requesting content one ID at a time, queue them up to be requested in one go. * Avoids sending many small requests. * Avoids sending requests for content which is likely to be arriving anyway. --- src/network/network_content.cpp | 64 ++++++++++++++++++++++++++------- src/network/network_content.h | 4 ++- src/timer/timer_window.cpp | 2 +- 3 files changed, 55 insertions(+), 15 deletions(-) diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 362fedfd62..33225011da 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -20,6 +20,8 @@ #include "../base_media_sounds.h" #include "../settings_type.h" #include "../strings_func.h" +#include "../timer/timer.h" +#include "../timer/timer_window.h" #include "network_content.h" #include "table/strings.h" @@ -212,27 +214,29 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentType type) * @param count The number of IDs to request. * @param content_ids The unique identifiers of the content to request information about. */ -void ClientNetworkContentSocketHandler::RequestContentList(uint count, const ContentID *content_ids) +void ClientNetworkContentSocketHandler::RequestContentList(std::span content_ids) { + /* We can "only" send a limited number of IDs in a single packet. + * A packet begins with the packet size and a byte for the type. + * Then this packet adds a uint16_t for the count in this packet. + * The rest of the packet can be used for the IDs. */ + static constexpr size_t MAX_CONTENT_IDS_PER_PACKET = (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t); + + if (content_ids.empty()) return; + this->Connect(); - while (count > 0) { - /* We can "only" send a limited number of IDs in a single packet. - * A packet begins with the packet size and a byte for the type. - * Then this packet adds a uint16_t for the count in this packet. - * The rest of the packet can be used for the IDs. */ - uint p_count = std::min(count, (TCP_MTU - sizeof(PacketSize) - sizeof(uint8_t) - sizeof(uint16_t)) / sizeof(uint32_t)); + for (auto it = std::begin(content_ids); it != std::end(content_ids); /* nothing */) { + auto last = std::ranges::next(it, MAX_CONTENT_IDS_PER_PACKET, std::end(content_ids)); auto p = std::make_unique(this, PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU); - p->Send_uint16(p_count); + p->Send_uint16(std::distance(it, last)); - for (uint i = 0; i < p_count; i++) { - p->Send_uint32(content_ids[i]); + for (; it != last; ++it) { + p->Send_uint32(*it); } this->SendPacket(std::move(p)); - count -= p_count; - content_ids += p_count; } } @@ -794,6 +798,13 @@ void ClientNetworkContentSocketHandler::SendReceive() this->SendPackets(); } +/** Timeout after queueing content for it to try to be requested. */ +static constexpr auto CONTENT_QUEUE_TIMEOUT = std::chrono::milliseconds(100); + +static TimeoutTimer _request_queue_timeout = {CONTENT_QUEUE_TIMEOUT, []() { + _network_content_client.RequestQueuedContentInfo(); +}}; + /** * Download information of a given Content ID if not already tried * @param cid the ID to try @@ -804,7 +815,33 @@ void ClientNetworkContentSocketHandler::DownloadContentInfo(ContentID cid) if (std::ranges::find(this->requested, cid) != this->requested.end()) return; this->requested.push_back(cid); - this->RequestContentList(1, &cid); + this->queued.push_back(cid); + _request_queue_timeout.Reset(); +} + +/** + * Send a content request for queued content info download. + */ +void ClientNetworkContentSocketHandler::RequestQueuedContentInfo() +{ + if (this->queued.empty()) return; + + /* Wait until we've briefly stopped receiving data (which will contain more content) before making the request. */ + if (std::chrono::steady_clock::now() <= this->last_activity + CONTENT_QUEUE_TIMEOUT) { + _request_queue_timeout.Reset(); + return; + } + + /* Move the queue locally so more ids can be queued for later. */ + ContentIDList queue; + queue.swap(this->queued); + + /* Remove ids that have since been received since the request was queued. */ + queue.erase(std::remove_if(std::begin(queue), std::end(queue), [this](ContentID content_id) { + return std::ranges::find(this->infos, content_id, &ContentInfo::id) != std::end(this->infos); + }), std::end(queue)); + + this->RequestContentList(queue); } /** @@ -1028,6 +1065,7 @@ void ClientNetworkContentSocketHandler::Clear() { this->infos.clear(); this->requested.clear(); + this->queued.clear(); this->reverse_dependency_map.clear(); } diff --git a/src/network/network_content.h b/src/network/network_content.h index b00047abdd..2ed54fbd65 100644 --- a/src/network/network_content.h +++ b/src/network/network_content.h @@ -65,6 +65,7 @@ protected: using ContentIDList = std::vector; ///< List of content IDs to (possibly) select. std::vector callbacks; ///< Callbacks to notify "the world" ContentIDList requested; ///< ContentIDs we already requested (so we don't do it again) + ContentIDList queued; ///< ContentID queue to be requested. ContentVector infos; ///< All content info we received std::unordered_multimap reverse_dependency_map; ///< Content reverse dependency map std::vector http_response; ///< The HTTP response to the requests we've been doing @@ -109,10 +110,11 @@ public: void Cancel(); void RequestContentList(ContentType type); - void RequestContentList(uint count, const ContentID *content_ids); + void RequestContentList(std::span content_ids); void RequestContentList(ContentVector *cv, bool send_md5sum = true); void DownloadSelectedContent(uint &files, uint &bytes, bool fallback = false); + void RequestQueuedContentInfo(); void Select(ContentID cid); void Unselect(ContentID cid); diff --git a/src/timer/timer_window.cpp b/src/timer/timer_window.cpp index 2016d19f5d..9ec0f0163d 100644 --- a/src/timer/timer_window.cpp +++ b/src/timer/timer_window.cpp @@ -43,8 +43,8 @@ void TimeoutTimer::Elapsed(TimerWindow::TElapsed delta) this->storage.elapsed += delta; if (this->storage.elapsed >= this->period) { - this->callback(); this->fired = true; + this->callback(); } } From 34b1f7a99206d841b0a6aa9472034b1f546b8ce6 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 12 Apr 2025 13:05:33 +0100 Subject: [PATCH 014/572] Fix: Make GrfMsg() behave like Debug() when not loading NewGRFs. (#13991) GrfMsg() outputs the currently loading NewGRF and current line/sprite number. This is invalid when not NewGRFs are not actually being loaded. --- src/newgrf.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 55182b8b5a..3dc4fca19f 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -87,7 +87,11 @@ ReferenceThroughBaseContainer> _gted; ///< Tempo */ void GrfMsgI(int severity, const std::string &msg) { - Debug(grf, severity, "[{}:{}] {}", _cur_gps.grfconfig->filename, _cur_gps.nfo_line, msg); + if (_cur_gps.grfconfig == nullptr) { + Debug(grf, severity, "{}", msg); + } else { + Debug(grf, severity, "[{}:{}] {}", _cur_gps.grfconfig->filename, _cur_gps.nfo_line, msg); + } } /** @@ -371,6 +375,7 @@ void GRFUnsafe(ByteReader &) /** Reset and clear all NewGRFs */ static void ResetNewGRF() { + _cur_gps.grfconfig = nullptr; _cur_gps.grffile = nullptr; _grf_files.clear(); @@ -1823,6 +1828,10 @@ void LoadNewGRF(SpriteID load_index, uint num_baseset) } } + /* We've finished reading files. */ + _cur_gps.grfconfig = nullptr; + _cur_gps.grffile = nullptr; + /* Pseudo sprite processing is finished; free temporary stuff */ _cur_gps.ClearDataForNextFile(); From 319a657454582cd2b379cde769dbe43839bb0eeb Mon Sep 17 00:00:00 2001 From: Kuhnovic <68320206+Kuhnovic@users.noreply.github.com> Date: Sat, 12 Apr 2025 16:09:10 +0200 Subject: [PATCH 015/572] Fix 42fbcec76f41: Fixed accidental changes to autorail/road AI behavior (#13968) * Revert 4bd72e4a7846af, Fix #11528: Starting autorail dragging from existing track tiles resulted in adding non-continuous tracks. * Fix 4bd72e4a7846af: Fixed accidental changes to autorail/road AI behavior --- src/rail_cmd.cpp | 4 ++-- src/road_cmd.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 1287eac16b..46ccda7303 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -888,11 +888,11 @@ static CommandCost CmdRailTrackHelper(DoCommandFlags flags, TileIndex tile, Tile CommandCost last_error = CMD_ERROR; for (;;) { ret = remove ? Command::Do(flags, tile, TrackdirToTrack(trackdir)) : Command::Do(flags, tile, railtype, TrackdirToTrack(trackdir), auto_remove_signals); - if (!remove && ret.Failed() && ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) ret = CommandCost(); // Treat "already built" as success + if (!remove && !fail_on_obstacle && last_error.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) had_success = true; if (ret.Failed()) { last_error = std::move(ret); - if (!remove) { + if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT && !remove) { if (fail_on_obstacle) return last_error; if (had_success) break; // Keep going if we haven't constructed any rail yet, skipping the start of the drag } diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 211186114c..0d974bbdf5 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1020,12 +1020,13 @@ CommandCost CmdBuildLongRoad(DoCommandFlags flags, TileIndex end_tile, TileIndex } CommandCost ret = Command::Do(flags, tile, bits, rt, drd, TownID::Invalid()); - if (ret.Failed() && ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) ret = CommandCost(); // Treat "already built" as success - + if (!is_ai && ret.GetErrorMessage() == STR_ERROR_ALREADY_BUILT) had_success = true; if (ret.Failed()) { last_error = std::move(ret); - if (is_ai) return last_error; - if (had_success) break; // Keep going if we haven't constructed any road yet, skipping the start of the drag + if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) { + if (is_ai) return last_error; + if (had_success) break; // Keep going if we haven't constructed any road yet, skipping the start of the drag + } } else { had_success = true; /* Only pay for the upgrade on one side of the bridges and tunnels */ From a93087ec5cd1be7bcc9b8a0277680aadf640071a Mon Sep 17 00:00:00 2001 From: Richard Wheeler <2762690+zephyris@users.noreply.github.com> Date: Sat, 12 Apr 2025 18:50:11 +0100 Subject: [PATCH 016/572] Fix #13980: Allow diagonal selection for road convert (#13983) Fixes #13980 --- src/road_cmd.cpp | 12 ++++++++---- src/road_cmd.h | 2 +- src/road_gui.cpp | 4 ++-- src/script/api/script_road.cpp | 2 +- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 0d974bbdf5..2d9a6d2de5 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -857,7 +857,7 @@ do_clear:; if (HasPowerOnRoad(rt, existing_rt)) { rt = existing_rt; } else if (HasPowerOnRoad(existing_rt, rt)) { - ret = Command::Do(flags, tile, tile, rt); + ret = Command::Do(flags, tile, tile, rt, false); if (ret.Failed()) return ret; cost.AddCost(ret.GetCost()); } else { @@ -2435,7 +2435,7 @@ static void ConvertRoadTypeOwner(TileIndex tile, uint num_pieces, Owner owner, R * @param to_type new roadtype to convert to. * @return the cost of this operation or an error */ -CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_start, RoadType to_type) +CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_start, RoadType to_type, bool diagonal) { TileIndex area_end = tile; @@ -2449,7 +2449,7 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_ CommandCost error = CommandCost((rtt == RTT_TRAM) ? STR_ERROR_NO_SUITABLE_TRAMWAY : STR_ERROR_NO_SUITABLE_ROAD); // by default, there is no road to convert. bool found_convertible_road = false; // whether we actually did convert any road/tram (see bug #7633) - std::unique_ptr iter = std::make_unique(area_start, area_end); + std::unique_ptr iter = TileIterator::Create(area_start, area_end, diagonal); for (; (tile = *iter) != INVALID_TILE; ++(*iter)) { /* Is road present on tile? */ if (!MayHaveRoad(tile)) continue; @@ -2552,7 +2552,11 @@ CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_ /* If both ends of tunnel/bridge are in the range, do not try to convert twice - * it would cause assert because of different test and exec runs */ if (endtile < tile) { - if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue; + if (diagonal) { + if (DiagonalTileArea(area_start, area_end).Contains(endtile)) continue; + } else { + if (OrthogonalTileArea(area_start, area_end).Contains(endtile)) continue; + } } /* When not converting rail <-> el. rail, any vehicle cannot be in tunnel/bridge */ diff --git a/src/road_cmd.h b/src/road_cmd.h index ad53a3e111..84f31c3be0 100644 --- a/src/road_cmd.h +++ b/src/road_cmd.h @@ -23,7 +23,7 @@ CommandCost CmdBuildLongRoad(DoCommandFlags flags, TileIndex end_tile, TileIndex std::tuple CmdRemoveLongRoad(DoCommandFlags flags, TileIndex end_tile, TileIndex start_tile, RoadType rt, Axis axis, bool start_half, bool end_half); CommandCost CmdBuildRoad(DoCommandFlags flags, TileIndex tile, RoadBits pieces, RoadType rt, DisallowedRoadDirections toggle_drd, TownID town_id); CommandCost CmdBuildRoadDepot(DoCommandFlags flags, TileIndex tile, RoadType rt, DiagDirection dir); -CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_start, RoadType to_type); +CommandCost CmdConvertRoad(DoCommandFlags flags, TileIndex tile, TileIndex area_start, RoadType to_type, bool diagonal); DEF_CMD_TRAIT(CMD_BUILD_LONG_ROAD, CmdBuildLongRoad, CommandFlags({CommandFlag::Auto, CommandFlag::NoWater, CommandFlag::Deity}), CMDT_LANDSCAPE_CONSTRUCTION) DEF_CMD_TRAIT(CMD_REMOVE_LONG_ROAD, CmdRemoveLongRoad, CommandFlags({CommandFlag::Auto, CommandFlag::NoTest}), CMDT_LANDSCAPE_CONSTRUCTION) // towns may disallow removing road bits (as they are connected) in test, but in exec they're removed and thus removing is allowed. diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 70406eaecf..0eb0cec738 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -586,7 +586,7 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_CONVERT_ROAD: - HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, GetRoadTypeInfo(this->roadtype)->cursor.convert_road, HT_RECT); + HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD, GetRoadTypeInfo(this->roadtype)->cursor.convert_road, HT_RECT | HT_DIAGONAL); this->last_started_action = widget; break; @@ -805,7 +805,7 @@ struct BuildRoadToolbarWindow : Window { break; case DDSP_CONVERT_ROAD: - Command::Post(GetRoadTypeInfo(this->roadtype)->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype); + Command::Post(GetRoadTypeInfo(this->roadtype)->strings.err_convert_road, CcPlaySound_CONSTRUCTION_OTHER, end_tile, start_tile, _cur_roadtype, _ctrl_pressed); break; } } diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index b2152b409b..b6a3cceb14 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -132,7 +132,7 @@ EnforcePrecondition(false, ::IsValidTile(end_tile)); EnforcePrecondition(false, IsRoadTypeAvailable(road_type)); - return ScriptObject::Command::Do(start_tile, end_tile, (::RoadType)road_type); + return ScriptObject::Command::Do(start_tile, end_tile, (::RoadType)road_type, false); } /* Helper functions for ScriptRoad::CanBuildConnectedRoadParts(). */ From 04c41bf731ebeeafc00edb4b5aa7acfe655b81d3 Mon Sep 17 00:00:00 2001 From: translators Date: Sun, 13 Apr 2025 05:04:53 +0000 Subject: [PATCH 017/572] Update: Translations from eints galician: 63 changes by pvillaverde --- src/lang/galician.txt | 114 +++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 51 deletions(-) diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 1d88295ce8..87c4ae63c8 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -1218,7 +1218,7 @@ STR_CITY_APPROVAL_TOLERANT :Tolerante STR_CITY_APPROVAL_HOSTILE :Hostil STR_CITY_APPROVAL_PERMISSIVE :Permisiva (sen efecto nas accións da compañía) -STR_WARNING_NO_SUITABLE_AI :{WHITE}Non hai IA adecuada dispoñíbel...{}Podes descargar varias IAs a través do sistema de contidos online +STR_WARNING_NO_SUITABLE_AI :{WHITE}Non hai IA adecuada dispoñíbel...{}{}Podes descargar varias IAs a través do sistema de contidos online # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Opcións @@ -2651,7 +2651,7 @@ STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} sa STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} cambiou o seu nome a {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} deu {CURRENCY_LONG} a {STRING} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}O servidor pechou a sesión -STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}O servidor estase a reiniciar...{}Agarda por favor... +STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}O servidor estase a reiniciar...{}{}Agarda por favor... STR_NETWORK_MESSAGE_KICKED :*** {STRING} foi expulsado. Motivo: ({STRING}) STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Fallou o rexistro do servidor @@ -2904,6 +2904,7 @@ STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Seleccio STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Selección de pontes - pincha na ponte seleccionada para construíla STR_SELECT_BRIDGE_INFO_NAME :{GOLD}{STRING} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED :{GOLD}{STRING},{} {VELOCITY} +STR_SELECT_BRIDGE_INFO_NAME_COST :{GOLD}{STRING},{} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED_COST :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_BRIDGE_NAME_SUSPENSION_STEEL :Colgante, aceiro STR_BRIDGE_NAME_GIRDER_STEEL :Vigas, aceiro @@ -3157,6 +3158,9 @@ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Terra deserta STR_LAI_CLEAR_DESCRIPTION_GRASS :Herba STR_LAI_CLEAR_DESCRIPTION_FIELDS :Leiras STR_LAI_CLEAR_DESCRIPTION_DESERT :Deserto +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROCKS :rochas cubertas de neve +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROUGH_LAND :terra árida cuberta de neve +STR_LAI_CLEAR_DESCRIPTION_SNOWY_GRASS :herba cuberta de neve STR_LAI_RAIL_DESCRIPTION_TRACK :Vía de ferrocarril STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Vía de ferrocarril con sinais de bloqueo @@ -3628,17 +3632,17 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Atopado STR_NEWGRF_LIST_MISSING :{RED}Faltan arquivos # NewGRF 'it's broken' warnings -STR_NEWGRF_BROKEN :{WHITE}O comportamento do NewGRF '{0:STRING}' pode causar desincronizacións e/ou colgues -STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Cambiou o estado 'vagón con potencia' para '{1:ENGINE}' fóra dun depósito -STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Cambiou a lonxitude do vehículo a '{1:ENGINE}' cando non está nun depósito -STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Cambiou a capacidade do vehículo en '{1:ENGINE}' cando non está nun depósito ou modificándose +STR_NEWGRF_BROKEN :{WHITE}O comportamento do NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' pode causar desincronizacións e/ou colgues +STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Cambiou o estado 'vagón con potencia' para '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}'' fóra dun depósito +STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Cambiou a lonxitude do vehículo a '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' cando non está nun depósito +STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Cambiou a capacidade do vehículo en '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' cando non está nun depósito ou modificándose STR_BROKEN_VEHICLE_LENGTH :{WHITE}O tren '{VEHICLE}' pertencente a '{COMPANY}' ten unha lonxitude inválida. Isto está causado probabelmente por problemas con NewGRFs. O xogo pode desincronizarse ou colgarse -STR_NEWGRF_BUGGY :{WHITE}O NewGRF '{0:STRING}' proporciona información incorrecta. -STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Información de carga/reforma para '{1:ENGINE}' difiire da lista de compra despois da construción. Isto pode causar que a renovación/reemprazo automáticos non reformen correctamente -STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' produciu un bucle sen fin na chamada de retorno de produción +STR_NEWGRF_BUGGY :{WHITE}O NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' proporciona información incorrecta. +STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Información de carga/reforma para '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' difiire da lista de compra despois da construción. Isto pode causar que a renovación/reemprazo automáticos non reformen correctamente +STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' produciu un bucle sen fin na chamada de retorno de produción STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}A chamada {1:HEX} devolveu o resultado inválido ou descoñecido {2:HEX} -STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' tipo de produción inválido {2:HEX} +STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' devolveu un tipo de carga inválido na devolución de chamada de produción en {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : @@ -4034,6 +4038,10 @@ STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Produce: STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Require: +STR_INDUSTRY_VIEW_ACCEPT_CARGO_SUFFIX :{YELLOW}{0:STRING}{BLACK}{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_SUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} agardando{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_NOSUFFIX :{YELLOW}{0:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_NOSUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} agardando STR_CONFIG_GAME_PRODUCTION :{WHITE}Cambiar produción (múltiplo de 8, ata 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Cambiar o nivel de produción (porcentaxe, ata 800%) @@ -4691,54 +4699,56 @@ STR_ORDER_ROAD_VEHICLE_DEPOT :Depósito de Ve STR_ORDER_SHIP_DEPOT :Depósito de Barcos ###next-name-looks-similar +STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING} o hangar máis cercano +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} o {STRING} mais cercano STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} -STR_ORDER_REFIT_ORDER :(Reaxustar a {STRING}) -STR_ORDER_REFIT_STOP_ORDER :(Reaxustar a {STRING} e parar) -STR_ORDER_STOP_ORDER :(Parar) +STR_ORDER_REFIT_ORDER :{SPACE}(Reaxustar a {STRING}) +STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Reaxustar a {STRING} e parar) +STR_ORDER_STOP_ORDER :{SPACE}(Parar) -STR_ORDER_WAIT_TO_UNBUNCH :(agarda para desagrupar) +STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(agarda para desagrupar) STR_ORDER_GO_TO_STATION :{STRING} {STATION} STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Non pode usar a estación){POP_COLOUR} {STRING} {STATION} -STR_ORDER_IMPLICIT :(Implícito) +STR_ORDER_IMPLICIT :{SPACE}(Implícito) -STR_ORDER_FULL_LOAD :(Carga completa) -STR_ORDER_FULL_LOAD_ANY :(Carga completa de calquera carga) -STR_ORDER_NO_LOAD :(Non cargar) -STR_ORDER_UNLOAD :(Descargar e tomar carga) -STR_ORDER_UNLOAD_FULL_LOAD :(Descargar e esperar a carga completa) -STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Descargar e esperar a calquera carga completa) -STR_ORDER_UNLOAD_NO_LOAD :(Descargar e saír baleiro) -STR_ORDER_TRANSFER :(Transferir e tomar carga) -STR_ORDER_TRANSFER_FULL_LOAD :(Transferir e esperar a carga completa) -STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transferir e esperar a calquera carga completa) -STR_ORDER_TRANSFER_NO_LOAD :(Transferir e saír baleiro) -STR_ORDER_NO_UNLOAD :(Non descargar e tomar carga) -STR_ORDER_NO_UNLOAD_FULL_LOAD :(Non descargar e esperar a carga completa) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Non descargar e esperar a calquera carga completa) -STR_ORDER_NO_UNLOAD_NO_LOAD :(Non descargar nin cargar) +STR_ORDER_FULL_LOAD :{SPACE}(Carga completa) +STR_ORDER_FULL_LOAD_ANY :{SPACE}(Carga completa de calquera carga) +STR_ORDER_NO_LOAD :{SPACE}(Non cargar) +STR_ORDER_UNLOAD :{SPACE}(Descargar e tomar carga) +STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Descargar e esperar a carga completa) +STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Descargar e esperar a calquera carga completa) +STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Descargar e saír baleiro) +STR_ORDER_TRANSFER :{SPACE}(Transferir e tomar carga) +STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Transferir e esperar a carga completa) +STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Transferir e esperar a calquera carga completa) +STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Transferir e saír baleiro) +STR_ORDER_NO_UNLOAD :{SPACE}(Non descargar e tomar carga) +STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(Non descargar e esperar a carga completa) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(Non descargar e esperar a calquera carga completa) +STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(Non descargar nin cargar) -STR_ORDER_AUTO_REFIT :(Auto-axuste a {STRING}) -STR_ORDER_FULL_LOAD_REFIT :(Carga completa con auto-axuste a {STRING}) -STR_ORDER_FULL_LOAD_ANY_REFIT :(Carga completa de calquera carga con auto-axuste a {STRING}) -STR_ORDER_UNLOAD_REFIT :(Descargar e tomar cargo con autoaxuste para {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Descargar e agardar por carga completa con auto-axuste a {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Descargar e esperar a calquera carga completa con auto-axuste a {STRING}) -STR_ORDER_TRANSFER_REFIT :(Transferir e tomar carga con autoaxuste para {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transferir e esperar a carga completa con auto-axuste a {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transferir e esperar por calquera carga completa con auto-axuste a {STRING}) -STR_ORDER_NO_UNLOAD_REFIT :(Non descargar e tomar carga con auto-axuste a {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Non descargar e esperar a carga completa con auto-axuste a {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Non descargar e esperar a calquera carga completa con auto-axuste a {STRING}) +STR_ORDER_AUTO_REFIT :{SPACE}(Auto-axuste a {STRING}) +STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Carga completa con auto-axuste a {STRING}) +STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Carga completa de calquera carga con auto-axuste a {STRING}) +STR_ORDER_UNLOAD_REFIT :{SPACE}(Descargar e tomar cargo con autoaxuste para {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Descargar e agardar por carga completa con auto-axuste a {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Descargar e esperar a calquera carga completa con auto-axuste a {STRING}) +STR_ORDER_TRANSFER_REFIT :{SPACE}(Transferir e tomar carga con autoaxuste para {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Transferir e esperar a carga completa con auto-axuste a {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Transferir e esperar por calquera carga completa con auto-axuste a {STRING}) +STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(Non descargar e tomar carga con auto-axuste a {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Non descargar e esperar a carga completa con auto-axuste a {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Non descargar e esperar a calquera carga completa con auto-axuste a {STRING}) STR_ORDER_AUTO_REFIT_ANY :carga dispoñible ###length 3 -STR_ORDER_STOP_LOCATION_NEAR_END :[preto do final] -STR_ORDER_STOP_LOCATION_MIDDLE :[medio] -STR_ORDER_STOP_LOCATION_FAR_END :[lonxe do final] +STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[preto do final] +STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[medio] +STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[lonxe do final] STR_ORDER_OUT_OF_RANGE :{RED} (O próximo destino está fora de alcance) @@ -4763,8 +4773,8 @@ STR_TIMETABLE_TRAVEL_FOR :Viaxar durante STR_TIMETABLE_TRAVEL_FOR_SPEED :Viaxar por {STRING} polo menos a {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Viaxe (para {STRING}, non calendarizada) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Viaxe (para {STRING}, non calendarizado) con como máximo {VELOCITY} -STR_TIMETABLE_STAY_FOR_ESTIMATED :(permanece por {STRING}, non calendarizado) -STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(viaxe para {STRING}, sen calendarizar) +STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(permanece por {STRING}, non calendarizado) +STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(viaxe para {STRING}, sen calendarizar) STR_TIMETABLE_STAY_FOR :e parar durante {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :e viaxar durante {STRING} @@ -4785,12 +4795,14 @@ STR_TIMETABLE_START_SECONDS_QUERY :Segundos até e STR_TIMETABLE_CHANGE_TIME :{BLACK}Cambiar Tempo STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Cambiar o tempo que debería levar a orde seleccionada. Ctrl+Clic cambia o tempo para todas as ordes +STR_TIMETABLE_CHANGE_TIME_QUERY :Cambiar tempo STR_TIMETABLE_CLEAR_TIME :{BLACK}Borrar tempo STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Borrar o tempo para a orde seleccionada. Ctrl+Clic borra o tempo para todas as ordes STR_TIMETABLE_CHANGE_SPEED :{BLACK}Cambiar o límite de velocidade STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambiar a velocidade máxima da orde seleccionada. Ctrl+Click para fixar a velocidade de todas as ordes. +STR_TIMETABLE_CHANGE_SPEED_QUERY :Cambiar o límite de velocidade STR_TIMETABLE_CLEAR_SPEED :{BLACK}Borrar o límite de velocidade STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Borrar a velocidade máxima da orde seleccionada. Ctrl+Clic borra a velocidade para todas as ordes. @@ -4895,8 +4907,8 @@ STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}Captura STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Captura de pantalla do minimapa # Script Parameters -STR_AI_SETTINGS_CAPTION_AI :AI -STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Script do xogo +STR_AI_SETTINGS_CAPTION_AI :{WHITE}Parámetros da IA +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :{WHITE}Parámetros do script do xogo STR_AI_SETTINGS_CLOSE :{BLACK}Pechar STR_AI_SETTINGS_RESET :{BLACK}Restablecer STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -4957,7 +4969,7 @@ STR_GAME_SAVELOAD_NOT_AVAILABLE : Date: Sun, 13 Apr 2025 13:23:10 +0200 Subject: [PATCH 018/572] Add #12939: [NewGRF] Add road-/tram-/rail-type variable 0x45 to get mutual road-/tram-/rail-type on same tile. (#13934) --- src/newgrf_railtype.cpp | 9 +++++++ src/newgrf_roadtype.cpp | 47 +++++++++++++++++++++++++++++++++++ src/newgrf_roadtype.h | 2 ++ src/rail.h | 13 ++++++++++ src/road.h | 13 ++++++++++ src/table/newgrf_debug_data.h | 2 ++ 6 files changed, 86 insertions(+) diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 8c4b5b8a1d..f455904506 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -11,6 +11,7 @@ #include "core/container_func.hpp" #include "debug.h" #include "newgrf_railtype.h" +#include "newgrf_roadtype.h" #include "timer/timer_game_calendar.h" #include "depot_base.h" #include "town.h" @@ -33,6 +34,12 @@ case 0x42: return 0; case 0x43: return TimerGameCalendar::date.base(); case 0x44: return HZB_TOWN_EDGE; + case 0x45: { + auto rt = GetRailTypeInfoIndex(this->rti); + uint8_t local = GetReverseRailTypeTranslation(rt, this->ro.grffile); + if (local == 0xFF) local = 0xFE; + return 0xFFFF | local << 16; + } } } @@ -52,6 +59,8 @@ } return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; } + case 0x45: + return GetTrackTypes(this->tile, ro.grffile); } Debug(grf, 1, "Unhandled rail type tile variable 0x{:X}", variable); diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp index a4ffa8f948..4498cc0507 100644 --- a/src/newgrf_roadtype.cpp +++ b/src/newgrf_roadtype.cpp @@ -11,6 +11,7 @@ #include "core/container_func.hpp" #include "debug.h" #include "newgrf_roadtype.h" +#include "newgrf_railtype.h" #include "timer/timer_game_calendar.h" #include "depot_base.h" #include "town.h" @@ -18,6 +19,40 @@ #include "safeguards.h" +/** + * Variable 0x45 of road-/tram-/rail-types to query track types on a tile. + * + * Format: __RRttrr + * - rr: Translated roadtype. + * - tt: Translated tramtype. + * - RR: Translated railtype. + * + * Special values for rr, tt, RR: + * - 0xFF: Track not present on tile. + * - 0xFE: Track present, but no matching entry in translation table. + */ +uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile) +{ + uint8_t road = 0xFF; + uint8_t tram = 0xFF; + if (MayHaveRoad(tile)) { + if (auto tt = GetRoadTypeRoad(tile); tt != INVALID_ROADTYPE) { + road = GetReverseRoadTypeTranslation(tt, grffile); + if (road == 0xFF) road = 0xFE; + } + if (auto tt = GetRoadTypeTram(tile); tt != INVALID_ROADTYPE) { + tram = GetReverseRoadTypeTranslation(tt, grffile); + if (tram == 0xFF) tram = 0xFE; + } + } + uint8_t rail = 0xFF; + if (auto tt = GetTileRailType(tile); tt != INVALID_RAILTYPE) { + rail = GetReverseRailTypeTranslation(tt, grffile); + if (rail == 0xFF) rail = 0xFE; + } + return road | tram << 8 | rail << 16; +} + /* virtual */ uint32_t RoadTypeScopeResolver::GetRandomBits() const { uint tmp = CountBits(this->tile.base() + (TileX(this->tile) + TileY(this->tile)) * TILE_SIZE); @@ -33,6 +68,16 @@ case 0x42: return 0; case 0x43: return TimerGameCalendar::date.base(); case 0x44: return HZB_TOWN_EDGE; + case 0x45: { + auto rt = GetRoadTypeInfoIndex(this->rti); + uint8_t local = GetReverseRoadTypeTranslation(rt, this->ro.grffile); + if (local == 0xFF) local = 0xFE; + if (RoadTypeIsRoad(rt)) { + return 0xFFFF00 | local; + } else { + return 0xFF00FF | local << 8; + } + } } } @@ -52,6 +97,8 @@ } return t != nullptr ? GetTownRadiusGroup(t, this->tile) : HZB_TOWN_EDGE; } + case 0x45: + return GetTrackTypes(this->tile, ro.grffile); } Debug(grf, 1, "Unhandled road type tile variable 0x{:X}", variable); diff --git a/src/newgrf_roadtype.h b/src/newgrf_roadtype.h index 3fef3bd112..e0fc039856 100644 --- a/src/newgrf_roadtype.h +++ b/src/newgrf_roadtype.h @@ -59,6 +59,8 @@ SpriteID GetCustomRoadSprite(const RoadTypeInfo *rti, TileIndex tile, RoadTypeSp RoadType GetRoadTypeTranslation(RoadTramType rtt, uint8_t tracktype, const GRFFile *grffile); uint8_t GetReverseRoadTypeTranslation(RoadType roadtype, const GRFFile *grffile); +uint32_t GetTrackTypes(TileIndex tile, const GRFFile *grffile); + void ConvertRoadTypes(); void SetCurrentRoadTypeLabelList(); void ClearRoadTypeLabelList(); diff --git a/src/rail.h b/src/rail.h index 5b896f8e9f..323dd00c24 100644 --- a/src/rail.h +++ b/src/rail.h @@ -304,6 +304,19 @@ inline const RailTypeInfo *GetRailTypeInfo(RailType railtype) return &_railtypes[railtype]; } +/** + * Returns the railtype for a Railtype information. + * @param rti Pointer to static RailTypeInfo + * @return Railtype in static railtype definitions + */ +inline RailType GetRailTypeInfoIndex(const RailTypeInfo *rti) +{ + extern RailTypeInfo _railtypes[RAILTYPE_END]; + size_t index = rti - _railtypes; + assert(index < RAILTYPE_END && rti == _railtypes + index); + return static_cast(index); +} + /** * Checks if an engine of the given RailType can drive on a tile with a given * RailType. This would normally just be an equality check, but for electric diff --git a/src/road.h b/src/road.h index 07da18d97e..68c1aefdcf 100644 --- a/src/road.h +++ b/src/road.h @@ -234,6 +234,19 @@ inline const RoadTypeInfo *GetRoadTypeInfo(RoadType roadtype) return &_roadtypes[roadtype]; } +/** + * Returns the railtype for a Railtype information. + * @param rti Pointer to static RailTypeInfo + * @return Railtype in static railtype definitions + */ +inline RoadType GetRoadTypeInfoIndex(const RoadTypeInfo *rti) +{ + extern RoadTypeInfo _roadtypes[ROADTYPE_END]; + size_t index = rti - _roadtypes; + assert(index < ROADTYPE_END && rti == _roadtypes + index); + return static_cast(index); +} + /** * Checks if an engine of the given RoadType got power on a tile with a given * RoadType. This would normally just be an equality check, but for electrified diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index b083758506..0d0da8254a 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -451,6 +451,7 @@ static const NIVariable _niv_railtypes[] = { NIV(0x42, "level crossing status"), NIV(0x43, "construction date"), NIV(0x44, "town zone"), + NIV(0x45, "track types"), }; class NIHRailType : public NIHelper { @@ -620,6 +621,7 @@ static const NIVariable _niv_roadtypes[] = { NIV(0x42, "level crossing status"), NIV(0x43, "construction date"), NIV(0x44, "town zone"), + NIV(0x45, "track types"), }; template From 7157e9666498d6a500b718a363dbcf16ed62b667 Mon Sep 17 00:00:00 2001 From: frosch Date: Sun, 13 Apr 2025 15:52:01 +0200 Subject: [PATCH 019/572] Remove: Drop support for UCS2/UTF-16 encoded scripts. (#13992) --- src/script/squirrel.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index b933a3537a..af65a993f5 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -587,23 +587,6 @@ static char32_t _io_file_lexfeed_UTF8(SQUserPointer file) return c; } -static char32_t _io_file_lexfeed_UCS2_no_swap(SQUserPointer file) -{ - unsigned short c; - if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return (char32_t)c; - return 0; -} - -static char32_t _io_file_lexfeed_UCS2_swap(SQUserPointer file) -{ - unsigned short c; - if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) { - c = ((c >> 8) & 0x00FF)| ((c << 8) & 0xFF00); - return (char32_t)c; - } - return 0; -} - static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger size) { SQInteger ret = ((SQFile *)file)->Read(buf, 1, size); @@ -648,17 +631,6 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool } return sq_throwerror(vm, "Couldn't read bytecode"); } - case 0xFFFE: - /* Either this file is encoded as big-endian and we're on a little-endian - * machine, or this file is encoded as little-endian and we're on a big-endian - * machine. Either way, swap the bytes of every word we read. */ - func = _io_file_lexfeed_UCS2_swap; - size -= 2; // Skip BOM - break; - case 0xFEFF: - func = _io_file_lexfeed_UCS2_no_swap; - size -= 2; // Skip BOM - break; case 0xBBEF: // UTF-8 case 0xEFBB: { // UTF-8 on big-endian machine /* Similarly, check the file is actually big enough to finish checking BOM */ From 369983846a82bdd87e911bdd940ec49f3316c6ac Mon Sep 17 00:00:00 2001 From: rubidium42 Date: Sun, 13 Apr 2025 17:45:41 +0200 Subject: [PATCH 020/572] Update: Changelog for 15.0-beta2 (#13738) Co-authored-by: Michael Lutz --- changelog.md | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/changelog.md b/changelog.md index 8ed27438a8..e70a8b5069 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,107 @@ ## 15.x +### 15.0-beta2 (2025-04-13) + +- Feature: Snow-covered rocks are now visible (#13627) +- Feature: Generate more rocks on steep slopes during map generation or heightmap import (#13462) +- Feature: Prevent towns from upgrading individually-placed houses (#13270) +- Feature: [Win32] Touchpad two-finger map scrolling (#13172) +- Feature: NewGRF Badges (#13073) +- Add: [NewGRF] Add road-/tram-/rail-type variable 0x45 to get mutual road-/tram-/rail-type on same tile (#13934) +- Add: [Script] Newer Cargo Classes (#13779) +- Add: Show hyperlink destination tooltips in text window (#13742) +- Add: [Script] Saving/loading ScriptList (#13556) +- Add: Press Ctrl to build diagonal canals in game mode (#13432) +- Add: Sandbox settings to Sandbox Options window (#13268) +- Add: Setting to allow placing houses manually in-game (#13266) +- Add: [Script] Event for when a company's president name changes (#13208) +- Add: Ability to toggle visibility of station signs by facility (#13207) +- Add: [Script] ScriptEventCompanyRename (#12878) +- Add: Ukrainian Hryvnia currency (#12877) +- Add: Convert 32bpp-only sprites to 8bpp when needed (#11602) +- Change: [Script] Start GS (but don't run it) when generating world in scenario editor (#13961) +- Change: Make tree placement at world generation look more organic (#13515) +- Change: [MacOS] Put the icon in a rounded rectangle (#13446) +- Change: [Script] GetWaypointID to return the StationID of any waypoint (#13407) +- Change: Draw company manager face jacket after collar (#13390) +- Change: Don't distinguish between bus and truck stops when removing them (#13384) +- Change: [Script] Rename BridgeID to BridgeType in the script API (#13352) +- Change: Add fonts document to help window (#13305) +- Change: Log changes to sandbox settings (#13267) +- Change: When player joins network company, use its name instead of number in chat (#13263) +- Change: [Win32] Draw window title bar according to current Windows light/dark theme (#13196) +- Change: Restore wider spacers in main toolbars (#12039) +- Fix: NewGRF Global variables 0D, 0E and 1E refer to wrong GRFFile (#13986) +- Fix #13980: Allow diagonal selection for road convert (#13983) +- Fix: Validate raw strings from game-scripts, and strip invalid and control characters (#13976) +- Fix: Capitalise "Disabled" for the "maximum non-sticky open windows" setting (#13975) +- Fix: Frame widget with label had incorrect spacing (#13967) +- Fix: StringFilter included quotes in the search and failed (#13965) +- Fix #13955: Make graphs respect RTL (#13957) +- Fix: Numbers were left-aligned for RTL languages in several windows (#13959) +- Fix: MayHaveRoad claimed rail station tiles had road, so the custom stationspec index would be read as roadtype (#13949) +- Fix: [Script] Prevent cloning of API instances (#13947) +- Fix: Reference to the correct section of the README, if a graphics or a sound set is incomplete (#13946) +- Fix: Draw the bevel around the music track name as inset (#13935) +- Fix #13923: Padding in music GUI was asymmetric, so it looked different for LTR and RTL languages (#13933) +- Fix #13928: BuildOilRig did not properly set airport rotation (#13929) +- Fix: SDL2 application name hint was not effective (#13926) +- Fix #13921: [Win32] Don't try close an already closed event handle during destruction (#13924) +- Fix #13921: Don't reject MIDI files with a valid file magic value (#13924) +- Fix #13912: Multitile buildings break apart in house picker (#13914) +- Fix #13908: Require double click on order to change stop location (#13913) +- Fix #13910: Invalidate content of house picker window if language is changed (#13911) +- Fix: [Script] Reset instance when changing running scripts in scenario editor (#13906) +- Fix: [Script] Only run the gamescript GameLoop() in-game (#13896) +- Fix #13893: Reversed all x-axis labels for company related and industry production graphs in wallclock mode (#13894) +- Fix #13842: Close industry production graph if industry is removed (#13890) +- Fix #11528: Starting autorail dragging from existing track tiles resulted in adding non-continuous tracks (#13885) +- Fix: Autoreplace rail/road list only listed buildable types (#13887) +- Fix: [NewGRF] Display an error, if NewGRF reference out-of-bounds string parameters in gender/plural choices (#13881) +- Fix #13849: Settings in old saves could be overridden by defaults (#13874) +- Fix #13562: Removed cost estimation message from money cheat (#13857) +- Fix: [NewGRF] Plurals and genders did not work in strings with cases or substrings (#13853, #13852) +- Fix: [NewGRF] String parameter stack and case selection were not processed for control code 0x81 (#13851) +- Fix #13839: Incorrect colour of first company legend in smallmap window (#13841) +- Fix: i circumflex width in TrueType small font (#13836) +- Fix: Don't show owner of non-existent road (#13824) +- Fix: Error message window timeout doesn't match setting (#13812) +- Fix #13795: Crash in vehicle list of 32-bit platforms (#13796) +- Fix: [Script] Company rename event sometimes had the wrong name (#13794) +- Fix: Improve manager face randomisation (#13776) +- Fix #13740: [Script] Handle implicit orders for jump orders (#13753) +- Fix #13749: Default service intervals were not updated when changing timekeeping unit (#13751) +- Fix #13725: Use proper query strings for changing timetable values (#13737) +- Fix #11226: Don't draw story page elements that won't be visible (#13736) +- Fix: More AI than max_no_competitors could start with competitors_interval=0 (#13670) +- Fix: League table window ignored the minimal size in its widget description (#13629) +- Fix: Incorrect snow density when making rocks snowy (#13626) +- Fix: NewGRF vehicles display loading sprites when not actually loading or unloading (#13554) +- Fix #12925: Prevent cost estimates for settings changes (#13550) +- Fix: [Script] Report errors happening during 'Load()' (#13537) +- Fix: [Script] Improve type checking of parameters (#13522) +- Fix: [Script] Don't set CommandCallback for asynchronous commands (#13501) +- Fix: Missing error messages with sell- and autoreplace-all commands (#13469) +- Fix: Too many trees when generating trees at same height (#13460) +- Fix #12912: Company inaugurated year in wallclock mode was not saved (#13448) +- Fix: [Script] Wrong return value for failed preconditions Vehicle::CloneVehicle (#13445) +- Fix #13140: Scale initial industry production estimate by cargo scale (#13427) +- Fix #13384: Crash when remove bus/truck stop tool used on road waypoints (#13391) +- Fix #12987: Historical houses now always spawn completed (#13332) +- Fix: [Win32] Font detection didn't work for locales not supporting code pages (#13306) +- Fix: Restore ability to disable service interval (#13281) +- Fix: Hide company settings from console commands (#13269) +- Fix: Disable service interval widgets for non-owned vehicles (#13260) +- Fix #13225: Cargo payment graph key toggled wrong data sets (#13226) +- Fix: Rail station tile flags were not set early enough (#13203) +- Fix #13199: -f command line parameter does not need a value (#13200) +- Fix: Missing water region invalidation after flooding a half tile with rail in the highest corner (#13047) +- Fix: Strip control codes before sorting NewGRF names (#13034) +- Fix #12968: Added back ability to create unremovable houses (#12989) +- Remove: Drop support for UCS2/UTF-16 encoded scripts (#13992) +- Remove: Support for SDL1.2 (#13298) + + ### 15.0-beta1 (2024-12-24) - Feature: Town, industry and vehicle window zoom with mouse wheel (#12810, #12809, #12797) From 4721a1f93ecb490fb1ecee768729792f4b8bad91 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 13 Apr 2025 18:00:41 +0100 Subject: [PATCH 021/572] Fix: Don't display badges if the class has no name. (#13994) Unnamed badges are intended to be for internal-use, not for player information. Additionally if there is no name to the class, then is causes problems when user configuration comes. --- src/newgrf_badge.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/newgrf_badge.cpp b/src/newgrf_badge.cpp index 94aa72d966..b1269a02fe 100644 --- a/src/newgrf_badge.cpp +++ b/src/newgrf_badge.cpp @@ -353,6 +353,9 @@ GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) uint max_column = 0; for (BadgeClassID class_index : used.Classes()) { + const Badge *class_badge = GetClassBadge(class_index); + if (class_badge->name == STR_NULL) continue; + Dimension size = GetBadgeMaximalDimension(class_index, feature); if (size.width == 0) continue; @@ -360,9 +363,7 @@ GUIBadgeClasses::GUIBadgeClasses(GrfSpecFeature feature) bool visible = true; uint sort_order = UINT_MAX; - std::string_view label = GetClassBadge(class_index)->label; - - this->gui_classes.emplace_back(class_index, column, visible, sort_order, size, label); + this->gui_classes.emplace_back(class_index, column, visible, sort_order, size, class_badge->label); if (visible) max_column = std::max(max_column, column); } From 800d6e339d1cdcaa96b4af5118a6046860806365 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 27 Mar 2025 18:15:56 +0100 Subject: [PATCH 022/572] Codechange: Add StringConsumer. --- src/core/CMakeLists.txt | 2 + src/core/string_consumer.cpp | 196 ++++++++ src/core/string_consumer.hpp | 895 +++++++++++++++++++++++++++++++++ src/settingsgen/CMakeLists.txt | 1 + src/strgen/CMakeLists.txt | 1 + src/tests/CMakeLists.txt | 1 + src/tests/string_consumer.cpp | 487 ++++++++++++++++++ 7 files changed, 1583 insertions(+) create mode 100644 src/core/string_consumer.cpp create mode 100644 src/core/string_consumer.hpp create mode 100644 src/tests/string_consumer.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c14d10bf39..d21ea8da92 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -25,6 +25,8 @@ add_files( smallstack_type.hpp string_builder.cpp string_builder.hpp + string_consumer.cpp + string_consumer.hpp strong_typedef_type.hpp utf8.cpp utf8.hpp diff --git a/src/core/string_consumer.cpp b/src/core/string_consumer.cpp new file mode 100644 index 0000000000..6f2906676e --- /dev/null +++ b/src/core/string_consumer.cpp @@ -0,0 +1,196 @@ +/* + * 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 string_consumer.cpp Implementation of string parsing. */ + +#include "../stdafx.h" +#include "string_consumer.hpp" + +#include "bitmath_func.hpp" +#include "utf8.hpp" +#include "string_builder.hpp" + +#include "../string_func.h" + +#if defined(STRGEN) || defined(SETTINGSGEN) +#include "../error_func.h" +#else +#include "../debug.h" +#endif + +#include "../safeguards.h" + +const std::string_view StringConsumer::WHITESPACE_NO_NEWLINE = "\t\v\f\r "; +const std::string_view StringConsumer::WHITESPACE_OR_NEWLINE = "\t\n\v\f\r "; + +/* static */ void StringConsumer::LogError(std::string &&msg) +{ +#if defined(STRGEN) || defined(SETTINGSGEN) + FatalErrorI(std::move(msg)); +#else + DebugPrint("misc", 0, std::move(msg)); +#endif +} + +std::optional StringConsumer::PeekUint8() const +{ + if (this->GetBytesLeft() < 1) return std::nullopt; + return static_cast(this->src[this->position]); +} + +std::optional StringConsumer::PeekUint16LE() const +{ + if (this->GetBytesLeft() < 2) return std::nullopt; + return static_cast(this->src[this->position]) | + static_cast(this->src[this->position + 1]) << 8; +} + +std::optional StringConsumer::PeekUint32LE() const +{ + if (this->GetBytesLeft() < 4) return std::nullopt; + return static_cast(this->src[this->position]) | + static_cast(this->src[this->position + 1]) << 8 | + static_cast(this->src[this->position + 2]) << 16 | + static_cast(this->src[this->position + 3]) << 24; +} + +std::optional StringConsumer::PeekUint64LE() const +{ + if (this->GetBytesLeft() < 8) return std::nullopt; + return static_cast(static_cast(this->src[this->position])) | + static_cast(static_cast(this->src[this->position + 1])) << 8 | + static_cast(static_cast(this->src[this->position + 2])) << 16 | + static_cast(static_cast(this->src[this->position + 3])) << 24 | + static_cast(static_cast(this->src[this->position + 4])) << 32 | + static_cast(static_cast(this->src[this->position + 5])) << 40 | + static_cast(static_cast(this->src[this->position + 6])) << 48 | + static_cast(static_cast(this->src[this->position + 7])) << 56; +} + +std::optional StringConsumer::PeekChar() const +{ + auto result = this->PeekUint8(); + if (!result.has_value()) return {}; + return static_cast(*result); +} + +std::pair StringConsumer::PeekUtf8() const +{ + auto buf = this->src.substr(this->position); + return DecodeUtf8(buf); +} + +std::string_view StringConsumer::Peek(size_type len) const +{ + auto buf = this->src.substr(this->position); + if (len == std::string_view::npos) { + len = buf.size(); + } else if (len > buf.size()) { + len = buf.size(); + } + return buf.substr(0, len); +} + +void StringConsumer::Skip(size_type len) +{ + if (len == std::string_view::npos) { + this->position = this->src.size(); + } else if (size_type max_len = GetBytesLeft(); len > max_len) { + LogError(fmt::format("Source buffer too short: {} > {}", len, max_len)); + this->position = this->src.size(); + } else { + this->position += len; + } +} + +StringConsumer::size_type StringConsumer::Find(std::string_view str) const +{ + assert(!str.empty()); + auto buf = this->src.substr(this->position); + return buf.find(str); +} + +StringConsumer::size_type StringConsumer::FindUtf8(char32_t c) const +{ + auto [data, len] = EncodeUtf8(c); + return this->Find({data, len}); +} + +StringConsumer::size_type StringConsumer::FindCharIn(std::string_view chars) const +{ + assert(!chars.empty()); + auto buf = this->src.substr(this->position); + return buf.find_first_of(chars); +} + +StringConsumer::size_type StringConsumer::FindCharNotIn(std::string_view chars) const +{ + assert(!chars.empty()); + auto buf = this->src.substr(this->position); + return buf.find_first_not_of(chars); +} + +std::string_view StringConsumer::PeekUntil(std::string_view str, SeparatorUsage sep) const +{ + assert(!str.empty()); + auto buf = this->src.substr(this->position); + auto len = buf.find(str); + if (len != std::string_view::npos) { + switch (sep) { + case READ_ONE_SEPARATOR: + if (buf.compare(len, str.size(), str) == 0) len += str.size(); + break; + case READ_ALL_SEPARATORS: + while (buf.compare(len, str.size(), str) == 0) len += str.size(); + break; + default: + break; + } + } + return buf.substr(0, len); +} + +std::string_view StringConsumer::PeekUntilUtf8(char32_t c, SeparatorUsage sep) const +{ + auto [data, len] = EncodeUtf8(c); + return PeekUntil({data, len}, sep); +} + +std::string_view StringConsumer::ReadUntilUtf8(char32_t c, SeparatorUsage sep) +{ + auto [data, len] = EncodeUtf8(c); + return ReadUntil({data, len}, sep); +} + +void StringConsumer::SkipUntilUtf8(char32_t c, SeparatorUsage sep) +{ + auto [data, len] = EncodeUtf8(c); + return SkipUntil({data, len}, sep); +} + +void StringConsumer::SkipIntegerBase(int base) +{ + this->SkipIf("-"); + if (base == 0) { + if (this->ReadIf("0x") || this->ReadIf("0X")) { // boolean short-circuit ensures only one prefix is read + base = 16; + } else { + base = 10; + } + } + switch (base) { + default: + assert(false); + break; + case 10: + this->SkipUntilCharNotIn("0123456789"); + break; + case 16: + this->SkipUntilCharNotIn("0123456789abcdefABCDEF"); + break; + } +} diff --git a/src/core/string_consumer.hpp b/src/core/string_consumer.hpp new file mode 100644 index 0000000000..b85bf65eb9 --- /dev/null +++ b/src/core/string_consumer.hpp @@ -0,0 +1,895 @@ +/* + * 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 string_consumer.hpp Parse strings. + */ + +#ifndef STRING_CONSUMER_HPP +#define STRING_CONSUMER_HPP + +#include +#include "format.hpp" + +/** + * Parse data from a string / buffer. + * + * There are generally four operations for each data type: + * - Peek: Check and return validity and value. Do not advance read position. + * - TryRead: Check and return validity and value. Advance reader, if valid. + * - Read: Check validity, return value or fallback-value. Advance reader, even if value is invalid, to avoid deadlocks/stalling. + * - Skip: Discard value. Advance reader, even if value is invalid, to avoid deadlocks/stalling. + */ +class StringConsumer { +public: + using size_type = std::string_view::size_type; + + /** + * Special value for "end of data". + */ + static constexpr size_type npos = std::string_view::npos; + + /** + * ASCII whitespace characters, excluding new-line. + * Usable in FindChar(In|NotIn), (Peek|Read|Skip)(If|Until)Char(In|NotIn) + */ + static const std::string_view WHITESPACE_NO_NEWLINE; + /** + * ASCII whitespace characters, including new-line. + * Usable in FindChar(In|NotIn), (Peek|Read|Skip)(If|Until)Char(In|NotIn) + */ + static const std::string_view WHITESPACE_OR_NEWLINE; + +private: + std::string_view src; + size_type position = 0; + + static void LogError(std::string &&msg); + +public: + /** + * Construct parser with data from string. + */ + explicit StringConsumer(std::string_view src) : src(src) {} + /** + * Construct parser with data from string. + */ + explicit StringConsumer(const std::string &src) : src(src) {} + /** + * Construct parser with data from span. + */ + explicit StringConsumer(std::span src) : src(src.data(), src.size()) {} + /** + * Construct parser with data from buffer. + */ + StringConsumer(const char *src, size_type len) : src(src, len) {} + + /** + * Check whether any bytes left to read. + */ + [[nodiscard]] bool AnyBytesLeft() const noexcept { return this->position < this->src.size(); } + /** + * Get number of bytes left to read. + */ + [[nodiscard]] size_type GetBytesLeft() const noexcept { return this->src.size() - this->position; } + + /** + * Check wheter any bytes were already read. + */ + [[nodiscard]] bool AnyBytesRead() const noexcept { return this->position > 0; } + /** + * Get number of already read bytes. + */ + [[nodiscard]] size_type GetBytesRead() const noexcept { return this->position; } + + /** + * Get the original data, as passed to the constructor. + */ + [[nodiscard]] std::string_view GetOrigData() const noexcept { return this->src; } + /** + * Get already read data. + */ + [[nodiscard]] std::string_view GetReadData() const noexcept { return this->src.substr(0, this->position); } + /** + * Get data left to read. + */ + [[nodiscard]] std::string_view GetLeftData() const noexcept { return this->src.substr(this->position); } + + /** + * Discard all remaining data. + */ + void SkipAll() { this->position = this->src.size(); } + + /** + * Peek binary uint8. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekUint8() const; + /** + * Try to read binary uint8, and then advance reader. + */ + [[nodiscard]] std::optional TryReadUint8() + { + auto value = this->PeekUint8(); + if (value.has_value()) this->SkipUint8(); + return value; + } + /** + * Read binary uint8, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + */ + [[nodiscard]] uint8_t ReadUint8(uint8_t def = 0) + { + auto value = this->PeekUint8(); + this->SkipUint8(); // always advance + return value.value_or(def); + } + /** + * Skip binary uint8. + */ + void SkipUint8() { this->Skip(1); } + + /** + * Peek binary int8. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekSint8() const + { + auto result = PeekUint8(); + if (!result.has_value()) return std::nullopt; + return static_cast(*result); + } + /** + * Try to read binary int8, and then advance reader. + */ + [[nodiscard]] std::optional TryReadSint8() + { + auto value = this->PeekSint8(); + if (value.has_value()) this->SkipSint8(); + return value; + } + /** + * Read binary int8, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + */ + [[nodiscard]] int8_t ReadSint8(int8_t def = 0) + { + auto value = this->PeekSint8(); + this->SkipSint8(); // always advance + return value.value_or(def); + } + /** + * Skip binary int8. + */ + void SkipSint8() { this->Skip(1); } + + /** + * Peek binary uint16 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekUint16LE() const; + /** + * Try to read binary uint16, and then advance reader. + */ + [[nodiscard]] std::optional TryReadUint16LE() + { + auto value = this->PeekUint16LE(); + if (value.has_value()) this->SkipUint16LE(); + return value; + } + /** + * Read binary uint16 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] uint16_t ReadUint16LE(uint16_t def = 0) + { + auto value = this->PeekUint16LE(); + this->SkipUint16LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary uint16, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipUint16LE() { this->Skip(2); } + + /** + * Peek binary int16 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekSint16LE() const + { + auto result = PeekUint16LE(); + if (!result.has_value()) return std::nullopt; + return static_cast(*result); + } + /** + * Try to read binary int16, and then advance reader. + */ + [[nodiscard]] std::optional TryReadSint16LE() + { + auto value = this->PeekSint16LE(); + if (value.has_value()) this->SkipSint16LE(); + return value; + } + /** + * Read binary int16 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] int16_t ReadSint16LE(int16_t def = 0) + { + auto value = this->PeekSint16LE(); + this->SkipSint16LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary int16, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipSint16LE() { this->Skip(2); } + + /** + * Peek binary uint32 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekUint32LE() const; + /** + * Try to read binary uint32, and then advance reader. + */ + [[nodiscard]] std::optional TryReadUint32LE() + { + auto value = this->PeekUint32LE(); + if (value.has_value()) this->SkipUint32LE(); + return value; + } + /** + * Read binary uint32 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] uint32_t ReadUint32LE(uint32_t def = 0) + { + auto value = this->PeekUint32LE(); + this->SkipUint32LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary uint32, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipUint32LE() { this->Skip(4); } + + /** + * Peek binary int32 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekSint32LE() const + { + auto result = PeekUint32LE(); + if (!result.has_value()) return std::nullopt; + return static_cast(*result); + } + /** + * Try to read binary int32, and then advance reader. + */ + [[nodiscard]] std::optional TryReadSint32LE() + { + auto value = this->PeekSint32LE(); + if (value.has_value()) this->SkipSint32LE(); + return value; + } + /** + * Read binary int32 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] int32_t ReadSint32LE(int32_t def = 0) + { + auto value = this->PeekSint32LE(); + this->SkipSint32LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary int32, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipSint32LE() { this->Skip(4); } + + /** + * Peek binary uint64 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekUint64LE() const; + /** + * Try to read binary uint64, and then advance reader. + */ + [[nodiscard]] std::optional TryReadUint64LE() + { + auto value = this->PeekUint64LE(); + if (value.has_value()) this->SkipUint64LE(); + return value; + } + /** + * Read binary uint64 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] uint64_t ReadUint64LE(uint64_t def = 0) + { + auto value = this->PeekUint64LE(); + this->SkipUint64LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary uint64, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipUint64LE() { this->Skip(8); } + + /** + * Peek binary int64 using little endian. + * @return Read integer, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekSint64LE() const + { + auto result = PeekUint64LE(); + if (!result.has_value()) return std::nullopt; + return static_cast(*result); + } + /** + * Try to read binary int64, and then advance reader. + */ + [[nodiscard]] std::optional TryReadSint64LE() + { + auto value = this->PeekSint64LE(); + if (value.has_value()) this->SkipSint64LE(); + return value; + } + /** + * Read binary int64 using little endian, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read integer, 'def' if not enough data. + * @note The reader is advanced, even if not enough data was present. + */ + [[nodiscard]] int64_t ReadSint64LE(int64_t def = 0) + { + auto value = this->PeekSint64LE(); + this->SkipSint64LE(); // always advance + return value.value_or(def); + } + /** + * Skip binary int64, and advance reader. + * @note The reader is advanced, even if not enough data was present. + */ + void SkipSint64LE() { this->Skip(8); } + + /** + * Peek 8-bit character. + * @return Read char, std::nullopt if not enough data. + */ + [[nodiscard]] std::optional PeekChar() const; + /** + * Try to read a 8-bit character, and then advance reader. + */ + [[nodiscard]] std::optional TryReadChar() + { + auto value = this->PeekChar(); + if (value.has_value()) this->SkipChar(); + return value; + } + /** + * Read 8-bit character, and advance reader. + * @param def Default value to return, if not enough data. + * @return Read character, 'def' if not enough data. + */ + [[nodiscard]] char ReadChar(char def = '?') { + auto value = this->PeekChar(); + this->SkipChar(); // always advance + return value.value_or(def); + } + /** + * Skip 8-bit character, and advance reader. + */ + void SkipChar() { this->Skip(1); } + + /** + * Peek UTF-8 character. + * @return Length and read char, {0, 0} if no valid data. + */ + [[nodiscard]] std::pair PeekUtf8() const; + /** + * Try to read a UTF-8 character, and then advance reader. + */ + [[nodiscard]] std::optional TryReadUtf8() + { + auto [len, value] = this->PeekUtf8(); + if (len == 0) return std::nullopt; + this->Skip(len); + return value; + } + /** + * Read UTF-8 character, and advance reader. + * @param def Default value to return, if no valid data. + * @return Read char, 'def' if no valid data. + * @note The reader is advanced, even if no valid data was present. + */ + [[nodiscard]] char32_t ReadUtf8(char32_t def = '?') + { + auto [len, value] = this->PeekUtf8(); + this->Skip(len > 0 ? len : 1); // advance at least one byte + return len > 0 ? value : def; + } + /** + * Skip UTF-8 character, and advance reader. + * @note The reader is advanced, even if no valid data was present. + * @note This behaves different to Utf8View::iterator. + * Here we do not skip overlong encodings, because we want to + * allow binary data to follow UTF-8 data. + */ + void SkipUtf8() + { + auto len = this->PeekUtf8().first; + this->Skip(len > 0 ? len : 1); // advance at least one byte + } + + /** + * Check whether the next data matches 'str'. + */ + [[nodiscard]] bool PeekIf(std::string_view str) const + { + return this->src.compare(this->position, str.size(), str) == 0; + } + /** + * Check whether the next data matches 'str', and skip it. + */ + [[nodiscard]] bool ReadIf(std::string_view str) + { + bool result = this->PeekIf(str); + if (result) this->Skip(str.size()); + return result; + } + /** + * If the next data matches 'str', then skip it. + */ + void SkipIf(std::string_view str) + { + if (this->PeekIf(str)) this->Skip(str.size()); + } + + /** + * Check whether the next 8-bit char matches 'c'. + */ + [[nodiscard]] bool PeekCharIf(char c) const + { + return this->PeekIf({&c, 1}); + } + /** + * Check whether the next 8-bit char matches 'c', and skip it. + */ + [[nodiscard]] bool ReadCharIf(char c) + { + return this->ReadIf({&c, 1}); + } + /** + * If the next data matches the 8-bit char 'c', then skip it. + */ + void SkipCharIf(char c) + { + return this->SkipIf({&c, 1}); + } + + /** + * Check whether the next UTF-8 char matches 'c'. + */ + [[nodiscard]] bool PeekUtf8If(char32_t c) const + { + auto [len, result] = this->PeekUtf8(); + return len > 0 && result == c; + } + /** + * Check whether the next UTF-8 char matches 'c', and skip it. + */ + [[nodiscard]] bool ReadUtf8If(char32_t c) + { + auto [len, result] = this->PeekUtf8(); + if (len == 0 || result != c) return false; + this->Skip(len); + return true; + } + /** + * If the next data matches the UTF-8 char 'c', then skip it. + */ + void SkipUtf8If(char32_t c) + { + auto [len, result] = this->PeekUtf8(); + if (len > 0 && result == c) { + this->Skip(len); + } + } + + /** + * Peek the next 'len' bytes. + * @param len Bytes to read, 'npos' to read all. + * @return Up to 'len' bytes. + */ + [[nodiscard]] std::string_view Peek(size_type len) const; + /** + * Read the next 'len' bytes, and advance reader. + * @param len Bytes to read, 'npos' to read all. + * @return Up to 'len' bytes. + */ + [[nodiscard]] std::string_view Read(size_type len) + { + auto result = this->Peek(len); + if (len != npos && len != result.size()) { + LogError(fmt::format("Source buffer too short: {} > {}", len, result.size())); + } + this->Skip(result.size()); + return result; + } + /** + * Discard some bytes. + * @param len Number of bytes to skip, 'npos' to skip all. + */ + void Skip(size_type len); + + /** + * Find first occurence of 'str'. + * @return Offset from current reader position. 'npos' if no match found. + */ + [[nodiscard]] size_type Find(std::string_view str) const; + /** + * Find first occurence of 8-bit char 'c'. + * @return Offset from current reader position. 'npos' if no match found. + */ + [[nodiscard]] size_type FindChar(char c) const + { + return this->Find({&c, 1}); + } + /** + * Find first occurence of UTF-8 char 'c'. + * @return Offset from current reader position. 'npos' if no match found. + */ + [[nodiscard]] size_type FindUtf8(char32_t c) const; + + /** + * Find first occurence of any 8-bit char in 'chars'. + * @return Offset from current reader position. 'npos' if no match found. + */ + [[nodiscard]] size_type FindCharIn(std::string_view chars) const; + /** + * Find first occurence of any 8-bit char not in 'chars'. + * @return Offset from current reader position. 'npos' if no match found. + */ + [[nodiscard]] size_type FindCharNotIn(std::string_view chars) const; + + /** + * Check whether the next 8-bit char is in 'chars'. + * @return Matching char, std::nullopt if no match. + */ + [[nodiscard]] std::optional PeekCharIfIn(std::string_view chars) const + { + assert(!chars.empty()); + std::optional c = this->PeekChar(); + if (c.has_value() && chars.find(*c) != std::string_view::npos) return c; + return std::nullopt; + } + /** + * Read next 8-bit char, check whether it is in 'chars', and advance reader. + * @return Matching char, std::nullopt if no match. + */ + [[nodiscard]] std::optional ReadCharIfIn(std::string_view chars) + { + auto result = this->PeekCharIfIn(chars); + if (result.has_value()) this->Skip(1); + return result; + } + /** + * If the next 8-bit char is in 'chars', skip it. + */ + void SkipCharIfIn(std::string_view chars) + { + auto result = this->PeekCharIfIn(chars); + if (result.has_value()) this->Skip(1); + } + + /** + * Check whether the next 8-bit char is not in 'chars'. + * @return Non-matching char, std::nullopt if match. + */ + [[nodiscard]] std::optional PeekCharIfNotIn(std::string_view chars) const + { + assert(!chars.empty()); + std::optional c = this->PeekChar(); + if (c.has_value() && chars.find(*c) == std::string_view::npos) return c; + return std::nullopt; + } + /** + * Read next 8-bit char, check whether it is not in 'chars', and advance reader. + * @return Non-matching char, std::nullopt if match. + */ + [[nodiscard]] std::optional ReadCharIfNotIn(std::string_view chars) + { + auto result = this->PeekCharIfNotIn(chars); + if (result.has_value()) this->Skip(1); + return result; + } + /** + * If the next 8-bit char is not in 'chars', skip it. + */ + void SkipCharIfNotIn(std::string_view chars) + { + auto result = this->PeekCharIfNotIn(chars); + if (result.has_value()) this->Skip(1); + } + + /** + * Peek 8-bit chars, while they are not in 'chars', until they are. + * @return Non-matching chars. + */ + [[nodiscard]] std::string_view PeekUntilCharIn(std::string_view chars) const + { + size_type len = this->FindCharIn(chars); + return this->Peek(len); + } + /** + * Read 8-bit chars, while they are not in 'chars', until they are; and advance reader. + * @return Non-matching chars. + */ + [[nodiscard]] std::string_view ReadUntilCharIn(std::string_view chars) + { + size_type len = this->FindCharIn(chars); + return this->Read(len); + } + /** + * Skip 8-bit chars, while they are not in 'chars', until they are. + */ + void SkipUntilCharIn(std::string_view chars) + { + size_type len = this->FindCharIn(chars); + this->Skip(len); + } + + /** + * Peek 8-bit chars, while they are in 'chars', until they are not. + * @return Matching chars. + */ + [[nodiscard]] std::string_view PeekUntilCharNotIn(std::string_view chars) const + { + size_type len = this->FindCharNotIn(chars); + return this->Peek(len); + } + /** + * Read 8-bit chars, while they are in 'chars', until they are not; and advance reader. + * @return Matching chars. + */ + [[nodiscard]] std::string_view ReadUntilCharNotIn(std::string_view chars) + { + size_type len = this->FindCharNotIn(chars); + return this->Read(len); + } + /** + * Skip 8-bit chars, while they are in 'chars', until they are not. + */ + void SkipUntilCharNotIn(std::string_view chars) + { + size_type len = this->FindCharNotIn(chars); + this->Skip(len); + } + + /** + * Treatment of separator characters. + */ + enum SeparatorUsage { + READ_ALL_SEPARATORS, ///< Read all consecutive separators, and include them all in the result + READ_ONE_SEPARATOR, ///< Read one separator, and include it in the result + KEEP_SEPARATOR, ///< Keep the separator in the data as next value to be read. + SKIP_ONE_SEPARATOR, ///< Read and discard one separator, do not include it in the result. + SKIP_ALL_SEPARATORS, ///< Read and discard all consecutive separators, do not include any in the result. + }; + + /** + * Peek data until the first occurrence of 'str'. + * @param str Separator string. + * @param sep Whether to include/exclude 'str' from the result. + */ + [[nodiscard]] std::string_view PeekUntil(std::string_view str, SeparatorUsage sep) const; + /** + * Read data until the first occurrence of 'str', and advance reader. + * @param str Separator string. + * @param sep Whether to include/exclude 'str' from the result, and/or skip it. + */ + [[nodiscard]] std::string_view ReadUntil(std::string_view str, SeparatorUsage sep) + { + assert(!str.empty()); + auto result = this->PeekUntil(str, sep); + this->Skip(result.size()); + switch (sep) { + default: + break; + case SKIP_ONE_SEPARATOR: + this->SkipIf(str); + break; + case SKIP_ALL_SEPARATORS: + while (this->ReadIf(str)) {} + break; + } + return result; + } + /** + * Skip data until the first occurrence of 'str'. + * @param str Separator string. + * @param sep Whether to also skip 'str'. + */ + void SkipUntil(std::string_view str, SeparatorUsage sep) + { + assert(!str.empty()); + this->Skip(this->Find(str)); + switch (sep) { + default: + break; + case READ_ONE_SEPARATOR: + case SKIP_ONE_SEPARATOR: + this->SkipIf(str); + break; + case READ_ALL_SEPARATORS: + case SKIP_ALL_SEPARATORS: + while (this->ReadIf(str)) {} + break; + } + } + + /** + * Peek data until the first occurrence of 8-bit char 'c'. + * @param c Separator char. + * @param sep Whether to include/exclude 'c' from the result. + */ + [[nodiscard]] std::string_view PeekUntilChar(char c, SeparatorUsage sep) const + { + return this->PeekUntil({&c, 1}, sep); + } + /** + * Read data until the first occurrence of 8-bit char 'c', and advance reader. + * @param c Separator char. + * @param sep Whether to include/exclude 'c' from the result, and/or skip it. + */ + [[nodiscard]] std::string_view ReadUntilChar(char c, SeparatorUsage sep) + { + return this->ReadUntil({&c, 1}, sep); + } + /** + * Skip data until the first occurrence of 8-bit char 'c'. + * @param c Separator char. + * @param sep Whether to also skip 'c'. + */ + void SkipUntilChar(char c, SeparatorUsage sep) + { + this->SkipUntil({&c, 1}, sep); + } + + /** + * Peek data until the first occurrence of UTF-8 char 'c'. + * @param c Separator char. + * @param sep Whether to include/exclude 'c' from the result. + */ + [[nodiscard]] std::string_view PeekUntilUtf8(char32_t c, SeparatorUsage sep) const; + /** + * Read data until the first occurrence of UTF-8 char 'c', and advance reader. + * @param c Separator char. + * @param sep Whether to include/exclude 'c' from the result, and/or skip it. + */ + [[nodiscard]] std::string_view ReadUntilUtf8(char32_t c, SeparatorUsage sep); + /** + * Skip data until the first occurrence of UTF-8 char 'c'. + * @param c Separator char. + * @param sep Whether to also skip 'c'. + */ + void SkipUntilUtf8(char32_t c, SeparatorUsage sep); + +private: + template + [[nodiscard]] static std::pair ParseIntegerBase(std::string_view src, int base, bool log_errors) + { + if (base == 0) { + /* Try positive hex */ + if (src.starts_with("0x") || src.starts_with("0X")) { + auto [len, value] = ParseIntegerBase(src.substr(2), 16, log_errors); + if (len == 0) return {}; + return {len + 2, value}; + } + + /* Try negative hex */ + if (std::is_signed_v && (src.starts_with("-0x") || src.starts_with("-0X"))) { + using Unsigned = std::make_signed_t; + auto [len, uvalue] = ParseIntegerBase(src.substr(3), 16, log_errors); + if (len == 0) return {}; + T value = -uvalue; + if (value > 0) { + if (log_errors) LogError(fmt::format("Integer out of range: '{}'", src.substr(0, len + 3))); + return {}; + } + return {len + 3, value}; + } + + /* Try decimal */ + return ParseIntegerBase(src, 10, log_errors); + } + + T value{}; + assert(base == 10 || base == 16); // we only support these bases when skipping + auto result = std::from_chars(src.data(), src.data() + src.size(), value, base); + auto len = result.ptr - src.data(); + if (result.ec == std::errc::result_out_of_range) { + if (log_errors) LogError(fmt::format("Integer out of range: '{}'+'{}'", src.substr(0, len), src.substr(len, 4))); + return {}; + } + if (result.ec != std::errc{}) { + if (log_errors) LogError(fmt::format("Cannot parse integer: '{}'+'{}'", src.substr(0, len), src.substr(len, 4))); + return {}; + } + return {len, value}; + } + +public: + /** + * Peek and parse an integer in number 'base'. + * If 'base == 0', then a prefix '0x' decides between base 16 or base 10. + * @return Length of string match, and parsed value. + * @note The parser rejects leading whitespace and unary plus. + */ + template + [[nodiscard]] std::pair PeekIntegerBase(int base) const + { + return ParseIntegerBase(this->src.substr(this->position), base, false); + } + /** + * Try to read and parse an integer in number 'base', and then advance the reader. + * If 'base == 0', then a prefix '0x' decides between base 16 or base 10. + * @return Parsed value, if valid. + * @note The parser rejects leading whitespace and unary plus. + */ + template + [[nodiscard]] std::optional TryReadIntegerBase(int base) + { + auto [len, value] = this->PeekIntegerBase(base); + if (len == 0) return std::nullopt; + this->SkipIntegerBase(base); + return value; + } + /** + * Read and parse an integer in number 'base', and advance the reader. + * If 'base == 0', then a prefix '0x' decides between base 16 or base 10. + * @return Parsed value, or 'def' if invalid. + * @note The reader is advanced, even if no valid data was present. + * @note The parser rejects leading whitespace and unary plus. + */ + template + [[nodiscard]] T ReadIntegerBase(int base, T def = 0) + { + auto [len, value] = ParseIntegerBase(this->src.substr(this->position), base, true); + this->SkipIntegerBase(base); // always advance + return len > 0 ? value : def; + } + /** + * Skip an integer in number 'base'. + * If 'base == 0', then a prefix '0x' decides between base 16 or base 10. + * @note The reader is advanced, even if no valid data was present. + * @note The parser rejects leading whitespace and unary plus. + */ + void SkipIntegerBase(int base); +}; + +#endif /* STRING_CONSUMER_HPP */ diff --git a/src/settingsgen/CMakeLists.txt b/src/settingsgen/CMakeLists.txt index c69f755035..220ffb972b 100644 --- a/src/settingsgen/CMakeLists.txt +++ b/src/settingsgen/CMakeLists.txt @@ -11,6 +11,7 @@ if (NOT HOST_BINARY_DIR) ../ini_load.cpp ../string.cpp ../core/string_builder.cpp + ../core/string_consumer.cpp ../core/utf8.cpp ) add_definitions(-DSETTINGSGEN) diff --git a/src/strgen/CMakeLists.txt b/src/strgen/CMakeLists.txt index 425cc1dd1a..40eb11448f 100644 --- a/src/strgen/CMakeLists.txt +++ b/src/strgen/CMakeLists.txt @@ -13,6 +13,7 @@ if (NOT HOST_BINARY_DIR) ../error.cpp ../string.cpp ../core/string_builder.cpp + ../core/string_consumer.cpp ../core/utf8.cpp ) add_definitions(-DSTRGEN) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 7bfc261e4c..29f97ad205 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -8,6 +8,7 @@ add_test_files( mock_spritecache.cpp mock_spritecache.h string_builder.cpp + string_consumer.cpp string_func.cpp test_main.cpp test_network_crypto.cpp diff --git a/src/tests/string_consumer.cpp b/src/tests/string_consumer.cpp new file mode 100644 index 0000000000..1cf470a0cc --- /dev/null +++ b/src/tests/string_consumer.cpp @@ -0,0 +1,487 @@ +/* + * 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 string_consumer.cpp Test functionality from core/string_consumer. */ + +#include "../stdafx.h" + +#include + +#include "../3rdparty/catch2/catch.hpp" + +#include "../core/string_consumer.hpp" + +#include "../safeguards.h" + +using namespace std::literals; + +TEST_CASE("StringConsumer - basic") +{ + StringConsumer consumer("ab"sv); + CHECK(!consumer.AnyBytesRead()); + CHECK(consumer.GetBytesRead() == 0); + CHECK(consumer.AnyBytesLeft()); + CHECK(consumer.GetBytesLeft() == 2); + CHECK(consumer.GetOrigData() == "ab"); + CHECK(consumer.GetReadData() == ""); + CHECK(consumer.GetLeftData() == "ab"); + consumer.Skip(1); + CHECK(consumer.AnyBytesRead()); + CHECK(consumer.GetBytesRead() == 1); + CHECK(consumer.AnyBytesLeft()); + CHECK(consumer.GetBytesLeft() == 1); + CHECK(consumer.GetOrigData() == "ab"); + CHECK(consumer.GetReadData() == "a"); + CHECK(consumer.GetLeftData() == "b"); + consumer.SkipAll(); + CHECK(consumer.AnyBytesRead()); + CHECK(consumer.GetBytesRead() == 2); + CHECK(!consumer.AnyBytesLeft()); + CHECK(consumer.GetBytesLeft() == 0); + CHECK(consumer.GetOrigData() == "ab"); + CHECK(consumer.GetReadData() == "ab"); + CHECK(consumer.GetLeftData() == ""); + consumer.Skip(1); + CHECK(consumer.AnyBytesRead()); + CHECK(consumer.GetBytesRead() == 2); + CHECK(!consumer.AnyBytesLeft()); + CHECK(consumer.GetBytesLeft() == 0); + CHECK(consumer.GetOrigData() == "ab"); + CHECK(consumer.GetReadData() == "ab"); + CHECK(consumer.GetLeftData() == ""); +} + +TEST_CASE("StringConsumer - binary8") +{ + StringConsumer consumer("\xFF\xFE\xFD\0"sv); + CHECK(consumer.PeekUint8() == 0xFF); + CHECK(consumer.PeekSint8() == -1); + CHECK(consumer.PeekChar() == static_cast(-1)); + consumer.SkipUint8(); + CHECK(consumer.PeekUint8() == 0xFE); + CHECK(consumer.PeekSint8() == -2); + CHECK(consumer.PeekChar() == static_cast(-2)); + CHECK(consumer.ReadUint8() == 0xFE); + CHECK(consumer.PeekUint8() == 0xFD); + CHECK(consumer.PeekSint8() == -3); + CHECK(consumer.PeekChar() == static_cast(-3)); + CHECK(consumer.ReadSint8() == -3); + CHECK(consumer.PeekUint8() == 0); + CHECK(consumer.PeekSint8() == 0); + CHECK(consumer.PeekChar() == 0); + CHECK(consumer.ReadChar() == 0); + CHECK(consumer.PeekUint8() == std::nullopt); + CHECK(consumer.PeekSint8() == std::nullopt); + CHECK(consumer.PeekChar() == std::nullopt); + CHECK(consumer.ReadUint8(42) == 42); + consumer.SkipSint8(); + CHECK(consumer.ReadSint8(42) == 42); + CHECK(consumer.ReadChar(42) == 42); +} + +TEST_CASE("StringConsumer - binary16") +{ + StringConsumer consumer("\xFF\xFF\xFE\xFF\xFD\xFF"sv); + CHECK(consumer.PeekUint16LE() == 0xFFFF); + CHECK(consumer.PeekSint16LE() == -1); + consumer.SkipUint16LE(); + CHECK(consumer.PeekUint16LE() == 0xFFFE); + CHECK(consumer.PeekSint16LE() == -2); + CHECK(consumer.ReadUint16LE() == 0xFFFE); + CHECK(consumer.PeekUint16LE() == 0xFFFD); + CHECK(consumer.PeekSint16LE() == -3); + CHECK(consumer.ReadSint16LE() == -3); + CHECK(consumer.PeekUint16LE() == std::nullopt); + CHECK(consumer.PeekSint16LE() == std::nullopt); + CHECK(consumer.ReadUint16LE(42) == 42); + consumer.SkipSint16LE(); + CHECK(consumer.ReadSint16LE(42) == 42); +} + +TEST_CASE("StringConsumer - binary32") +{ + StringConsumer consumer("\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFD\xFF\xFF\xFF"sv); + CHECK(consumer.PeekUint32LE() == 0xFFFFFFFF); + CHECK(consumer.PeekSint32LE() == -1); + consumer.SkipUint32LE(); + CHECK(consumer.PeekUint32LE() == 0xFFFFFFFE); + CHECK(consumer.PeekSint32LE() == -2); + CHECK(consumer.ReadUint32LE() == 0xFFFFFFFE); + CHECK(consumer.PeekUint32LE() == 0xFFFFFFFD); + CHECK(consumer.PeekSint32LE() == -3); + CHECK(consumer.ReadSint32LE() == -3); + CHECK(consumer.PeekUint32LE() == std::nullopt); + CHECK(consumer.PeekSint32LE() == std::nullopt); + CHECK(consumer.ReadUint32LE(42) == 42); + consumer.SkipSint32LE(); + CHECK(consumer.ReadSint32LE(42) == 42); +} + +TEST_CASE("StringConsumer - binary64") +{ + StringConsumer consumer("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFD\xFF\xFF\xFF\xFF\xFF\xFF\xFF"sv); + CHECK(consumer.PeekUint64LE() == 0xFFFFFFFF'FFFFFFFF); + CHECK(consumer.PeekSint64LE() == -1); + consumer.SkipUint64LE(); + CHECK(consumer.PeekUint64LE() == 0xFFFFFFFF'FFFFFFFE); + CHECK(consumer.PeekSint64LE() == -2); + CHECK(consumer.ReadUint64LE() == 0xFFFFFFFF'FFFFFFFE); + CHECK(consumer.PeekUint64LE() == 0xFFFFFFFF'FFFFFFFD); + CHECK(consumer.PeekSint64LE() == -3); + CHECK(consumer.ReadSint64LE() == -3); + CHECK(consumer.PeekUint64LE() == std::nullopt); + CHECK(consumer.PeekSint64LE() == std::nullopt); + CHECK(consumer.ReadUint64LE(42) == 42); + consumer.SkipSint64LE(); + CHECK(consumer.ReadSint64LE(42) == 42); +} + +TEST_CASE("StringConsumer - utf8") +{ + StringConsumer consumer("a\u1234\xFF\xFE""b"sv); + CHECK(consumer.PeekUtf8() == std::pair(1, 'a')); + consumer.SkipUtf8(); + CHECK(consumer.PeekUtf8() == std::pair(3, 0x1234)); + CHECK(consumer.ReadUtf8() == 0x1234); + CHECK(consumer.PeekUint8() == 0xFF); + CHECK(consumer.PeekUtf8() == std::pair(0, 0)); + CHECK(consumer.ReadUtf8() == '?'); + CHECK(consumer.PeekUint8() == 0xFE); + CHECK(consumer.PeekUtf8() == std::pair(0, 0)); + consumer.SkipUtf8(); + CHECK(consumer.PeekUtf8() == std::pair(1, 'b')); + CHECK(consumer.ReadUtf8() == 'b'); + CHECK(!consumer.AnyBytesLeft()); + CHECK(consumer.PeekUtf8() == std::pair(0, 0)); + CHECK(consumer.ReadUtf8() == '?'); +} + +TEST_CASE("StringConsumer - conditions") +{ + StringConsumer consumer("ABCDabcde\u0234@@@gh\0\0\0ij\0\0\0kl"sv); + CHECK(consumer.PeekIf("AB")); + CHECK(consumer.PeekCharIf('A')); + CHECK(consumer.PeekUtf8If('A')); + CHECK(!consumer.PeekIf("CD")); + CHECK(!consumer.ReadIf("CD")); + consumer.SkipIf("CD"); + CHECK(consumer.ReadIf("AB")); + CHECK(consumer.PeekIf("CD")); + consumer.SkipIf("CD"); + CHECK(consumer.Peek(2) == "ab"); + CHECK(consumer.Read(2) == "ab"); + CHECK(consumer.Peek(2) == "cd"); + CHECK(consumer.Find("e\u0234") == 2); + CHECK(consumer.Find("ab") == StringConsumer::npos); + CHECK(consumer.FindChar('e') == 2); + CHECK(consumer.FindChar('a') == StringConsumer::npos); + CHECK(consumer.FindUtf8(0x234) == 3); + CHECK(consumer.FindUtf8(0x1234) == StringConsumer::npos); + consumer.Skip(2); + CHECK(consumer.Peek(3) == "e\u0234"); + CHECK(consumer.PeekUntil("e", StringConsumer::READ_ALL_SEPARATORS) == "e"); + CHECK(consumer.PeekUntil("e", StringConsumer::READ_ONE_SEPARATOR) == "e"); + CHECK(consumer.PeekUntil("e", StringConsumer::KEEP_SEPARATOR) == ""); + CHECK(consumer.PeekUntil("e", StringConsumer::SKIP_ONE_SEPARATOR) == ""); + CHECK(consumer.PeekUntil("e", StringConsumer::SKIP_ALL_SEPARATORS) == ""); + CHECK(consumer.PeekUntil("@", StringConsumer::READ_ALL_SEPARATORS) == "e\u0234@@@"); + CHECK(consumer.PeekUntil("@", StringConsumer::READ_ONE_SEPARATOR) == "e\u0234@"); + CHECK(consumer.PeekUntil("@", StringConsumer::KEEP_SEPARATOR) == "e\u0234"); + CHECK(consumer.PeekUntil("@", StringConsumer::SKIP_ONE_SEPARATOR) == "e\u0234"); + CHECK(consumer.PeekUntil("@", StringConsumer::SKIP_ALL_SEPARATORS) == "e\u0234"); + CHECK(consumer.ReadUntil("@", StringConsumer::KEEP_SEPARATOR) == "e\u0234"); + CHECK(consumer.ReadUntil("@", StringConsumer::READ_ONE_SEPARATOR) == "@"); + CHECK(consumer.ReadUntil("@", StringConsumer::READ_ALL_SEPARATORS) == "@@"); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::READ_ALL_SEPARATORS) == "gh\0\0\0"sv); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::READ_ONE_SEPARATOR) == "gh\0"sv); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::KEEP_SEPARATOR) == "gh"); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::SKIP_ONE_SEPARATOR) == "gh"); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::SKIP_ALL_SEPARATORS) == "gh"); + CHECK(consumer.ReadUntilChar('\0', StringConsumer::READ_ONE_SEPARATOR) == "gh\0"sv); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::READ_ALL_SEPARATORS) == "\0\0"sv); + CHECK(consumer.ReadUntilChar('\0', StringConsumer::SKIP_ONE_SEPARATOR) == ""); + CHECK(consumer.PeekUntilChar('\0', StringConsumer::READ_ALL_SEPARATORS) == "\0"sv); + consumer.SkipUntilUtf8(0, StringConsumer::READ_ALL_SEPARATORS); + CHECK(consumer.PeekUntilUtf8(0, StringConsumer::KEEP_SEPARATOR) == "ij"); + consumer.SkipUntilUtf8(0, StringConsumer::SKIP_ALL_SEPARATORS); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::READ_ALL_SEPARATORS) == "kl"); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::READ_ONE_SEPARATOR) == "kl"); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::KEEP_SEPARATOR) == "kl"); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::SKIP_ONE_SEPARATOR) == "kl"); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::SKIP_ALL_SEPARATORS) == "kl"); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::READ_ALL_SEPARATORS) == "kl"); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::READ_ALL_SEPARATORS) == ""); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::READ_ONE_SEPARATOR) == ""); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::KEEP_SEPARATOR) == ""); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::SKIP_ONE_SEPARATOR) == ""); + CHECK(consumer.PeekUntilUtf8(0x234, StringConsumer::SKIP_ALL_SEPARATORS) == ""); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::READ_ALL_SEPARATORS) == ""); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::READ_ONE_SEPARATOR) == ""); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::KEEP_SEPARATOR) == ""); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::SKIP_ONE_SEPARATOR) == ""); + CHECK(consumer.ReadUntilUtf8(0x234, StringConsumer::SKIP_ALL_SEPARATORS) == ""); + CHECK(consumer.Peek(2) == ""); + CHECK(consumer.Read(2) == ""); +} + +TEST_CASE("StringConsumer - ascii") +{ + StringConsumer consumer("abcdefgh \r\n\tAB \r\n\t"sv); + CHECK(consumer.FindCharIn("dc") == 2); + CHECK(consumer.FindCharIn("xy") == StringConsumer::npos); + CHECK(consumer.FindCharNotIn("ba") == 2); + CHECK(consumer.PeekUntilCharNotIn("ba") == "ab"); + CHECK(consumer.PeekUntilCharNotIn("dc") == ""); + CHECK(consumer.PeekUntilCharIn("ba") == ""); + CHECK(consumer.PeekUntilCharIn("dc") == "ab"); + CHECK(consumer.ReadUntilCharNotIn("dc") == ""); + CHECK(consumer.ReadUntilCharNotIn("ba") == "ab"); + CHECK(consumer.ReadUntilCharIn("dc") == ""); + CHECK(consumer.ReadUntilCharIn("fe") == "cd"); + CHECK(consumer.PeekIf("ef")); + consumer.SkipUntilCharNotIn("ji"); + CHECK(consumer.PeekIf("ef")); + consumer.SkipUntilCharNotIn("fe"); + CHECK(consumer.PeekIf("gh")); + consumer.SkipUntilCharIn("hg"); + CHECK(consumer.PeekIf("gh")); + consumer.SkipUntilCharIn(StringConsumer::WHITESPACE_OR_NEWLINE); + CHECK(consumer.PeekCharIfIn(StringConsumer::WHITESPACE_OR_NEWLINE) == ' '); + CHECK(consumer.ReadCharIfIn(StringConsumer::WHITESPACE_OR_NEWLINE) == ' '); + consumer.SkipCharIfIn(StringConsumer::WHITESPACE_OR_NEWLINE); + CHECK(consumer.PeekUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE) == "\r"); + CHECK(consumer.ReadUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE) == "\r"); + consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE); + CHECK(consumer.PeekCharIfIn(StringConsumer::WHITESPACE_OR_NEWLINE) == '\n'); + CHECK(consumer.ReadCharIfIn(StringConsumer::WHITESPACE_OR_NEWLINE) == '\n'); + CHECK(consumer.PeekUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE) == "\t"); + CHECK(consumer.ReadUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE) == "\t"); + consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE); + CHECK(consumer.PeekUntilCharIn(StringConsumer::WHITESPACE_OR_NEWLINE) == "AB"); + CHECK(consumer.ReadUntilCharIn(StringConsumer::WHITESPACE_OR_NEWLINE) == "AB"); + CHECK(consumer.PeekUntilCharNotIn(StringConsumer::WHITESPACE_OR_NEWLINE) == " \r\n\t"); + consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_OR_NEWLINE); + CHECK(!consumer.AnyBytesLeft()); +} + +TEST_CASE("StringConsumer - parse int") +{ + StringConsumer consumer("1 a -a -2 -2 ffffFFFF ffffFFFF -1aaaAAAA -1aaaAAAA +3 1234567890123 1234567890123 1234567890123 ffffFFFFffffFFFE ffffFFFFffffFFFE ffffFFFFffffFFFE ffffFFFFffffFFFE -0x1aaaAAAAaaaaAAAA -1234567890123 "sv); + CHECK(consumer.PeekIntegerBase(0) == std::pair(1, 1)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(1, 1)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 1)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 1)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 1)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 1)); + CHECK(consumer.TryReadIntegerBase(10) == 1); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0xa)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0xa)); + CHECK(consumer.ReadIntegerBase(16) == 0xa); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(2, -0xa)); + CHECK(consumer.ReadIntegerBase(16) == -0xa); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(2, -2)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(2, -2)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(2, -2)); + CHECK(consumer.TryReadIntegerBase(10) == std::nullopt); + CHECK(consumer.ReadIntegerBase(10) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(2, -2)); + CHECK(consumer.TryReadIntegerBase(10) == std::nullopt); + CHECK(consumer.ReadIntegerBase(10) == -2); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(8, 0xffffffff)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.TryReadIntegerBase(16) == std::nullopt); + CHECK(consumer.ReadIntegerBase(16) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.TryReadIntegerBase(16) == 0xffffffff); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(9, -0x1aaaaaaa)); + CHECK(consumer.TryReadIntegerBase(16) == std::nullopt); + CHECK(consumer.ReadIntegerBase(16) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(9, -0x1aaaaaaa)); + CHECK(consumer.TryReadIntegerBase(16) == std::nullopt); + CHECK(consumer.ReadIntegerBase(16) == -0x1aaaaaaa); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + consumer.SkipIntegerBase(10); + CHECK(consumer.ReadUtf8() == '+'); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 3)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 3)); + consumer.SkipIntegerBase(10); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.TryReadIntegerBase(10) == std::nullopt); + CHECK(consumer.ReadIntegerBase(10) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.TryReadIntegerBase(10) == std::nullopt); + CHECK(consumer.ReadIntegerBase(10) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(13, 1234567890123)); + CHECK(consumer.ReadIntegerBase(10) == 1234567890123); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(16, 0xffffffff'fffffffe)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.ReadIntegerBase(16) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(16, 0xffffffff'fffffffe)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.ReadIntegerBase(16) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(16, 0xffffffff'fffffffe)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.ReadIntegerBase(16) == 0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(16, 0xffffffff'fffffffe)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.ReadIntegerBase(16) == 0xffffffff'fffffffe); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(2, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(2, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(19, -0x1aaaaaaa'aaaaaaaa)); + CHECK(consumer.ReadIntegerBase(0) == -0x1aaaaaaa'aaaaaaaa); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(14, -1234567890123)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(14, -1234567890123)); + CHECK(consumer.ReadIntegerBase(0) == -1234567890123); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + consumer.SkipIntegerBase(10); + consumer.SkipIntegerBase(10); + consumer.SkipIntegerBase(0); + consumer.SkipIntegerBase(0); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + consumer.SkipIntegerBase(10); + consumer.SkipIntegerBase(10); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(10, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); + CHECK(consumer.ReadIntegerBase(0, 42) == 42); +} + +TEST_CASE("StringConsumer - invalid int") +{ + StringConsumer consumer("x 0x - -0x 0y"sv); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + consumer.SkipIntegerBase(0); + consumer.SkipIntegerBase(10); + consumer.SkipIntegerBase(16); + CHECK(consumer.ReadUtf8() == 'x'); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0)); + consumer.SkipIntegerBase(0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + consumer.SkipIntegerBase(0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(2, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(0, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(2, 0)); + consumer.SkipIntegerBase(0); + CHECK(consumer.ReadUtf8() == ' '); + CHECK(consumer.PeekIntegerBase(0) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(0) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(10) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0)); + CHECK(consumer.PeekIntegerBase(16) == std::pair(1, 0)); + consumer.SkipIntegerBase(0); + CHECK(consumer.ReadUtf8() == 'y'); +} From 96eee0e8e4421618b4791dfda629cc6fe5d2e513 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 27 Mar 2025 19:57:01 +0100 Subject: [PATCH 023/572] Codechange: Base ByteReader on StringConsumer. --- src/newgrf.cpp | 11 +++-- src/newgrf/newgrf_bytereader.cpp | 26 ------------ src/newgrf/newgrf_bytereader.h | 69 +++++++++++++++++++------------- src/string_func.h | 14 ------- 4 files changed, 49 insertions(+), 71 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 3dc4fca19f..ee440aa464 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1218,23 +1218,26 @@ struct InvokeGrfActionHandler { * XXX: We consider GRF files trusted. It would be trivial to exploit OTTD by * a crafted invalid GRF file. We should tell that to the user somehow, or * better make this more robust in the future. */ -static void DecodeSpecialSprite(uint8_t *buf, uint num, GrfLoadingStage stage) +static void DecodeSpecialSprite(ReusableBuffer &allocator, uint num, GrfLoadingStage stage) { + uint8_t *buf; auto it = _grf_line_to_action6_sprite_override.find({_cur_gps.grfconfig->ident.grfid, _cur_gps.nfo_line}); if (it == _grf_line_to_action6_sprite_override.end()) { /* No preloaded sprite to work with; read the * pseudo sprite content. */ + buf = allocator.Allocate(num); _cur_gps.file->ReadBlock(buf, num); } else { /* Use the preloaded sprite data. */ buf = it->second.data(); + assert(it->second.size() == num); GrfMsg(7, "DecodeSpecialSprite: Using preloaded pseudo sprite data"); /* Skip the real (original) content of this action. */ _cur_gps.file->SeekTo(num, SEEK_CUR); } - ByteReader br(buf, buf + num); + ByteReader br(buf, num); try { uint8_t action = br.ReadByte(); @@ -1302,7 +1305,7 @@ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, Spr _cur_gps.ClearDataForNextFile(); - ReusableBuffer buf; + ReusableBuffer allocator; while ((num = (grf_container_version >= 2 ? file.ReadDword() : file.ReadWord())) != 0) { uint8_t type = file.ReadByte(); @@ -1317,7 +1320,7 @@ static void LoadNewGRFFileFromFile(GRFConfig &config, GrfLoadingStage stage, Spr break; } - DecodeSpecialSprite(buf.Allocate(num), num, stage); + DecodeSpecialSprite(allocator, num, stage); /* Stop all processing if we are to skip the remaining sprites */ if (_cur_gps.skip_sprites == -1) break; diff --git a/src/newgrf/newgrf_bytereader.cpp b/src/newgrf/newgrf_bytereader.cpp index d09c1dfadc..a1a9585ff2 100644 --- a/src/newgrf/newgrf_bytereader.cpp +++ b/src/newgrf/newgrf_bytereader.cpp @@ -14,17 +14,6 @@ #include "../safeguards.h" -/** - * Read a single DWord (32 bits). - * @note The buffer is NOT advanced. - * @returns Value read from buffer. - */ -uint32_t ByteReader::PeekDWord() -{ - AutoRestoreBackup backup(this->data, this->data); - return this->ReadDWord(); -} - /** * Read a value of the given number of bytes. * @returns Value read from buffer. @@ -40,18 +29,3 @@ uint32_t ByteReader::ReadVarSize(uint8_t size) return 0; } } - -/** - * Read a string. - * @returns Sting read from the buffer. - */ -std::string_view ByteReader::ReadString() -{ - const char *string = reinterpret_cast(this->data); - size_t string_length = ttd_strnlen(string, this->Remaining()); - - /* Skip past the terminating NUL byte if it is present, but not more than remaining. */ - this->Skip(std::min(string_length + 1, this->Remaining())); - - return std::string_view(string, string_length); -} diff --git a/src/newgrf/newgrf_bytereader.h b/src/newgrf/newgrf_bytereader.h index b3ceec7f2b..e298524741 100644 --- a/src/newgrf/newgrf_bytereader.h +++ b/src/newgrf/newgrf_bytereader.h @@ -10,24 +10,21 @@ #ifndef NEWGRF_BYTEREADER_H #define NEWGRF_BYTEREADER_H +#include "../core/string_consumer.hpp" + class OTTDByteReaderSignal { }; /** Class to read from a NewGRF file */ class ByteReader { + StringConsumer consumer; public: - ByteReader(const uint8_t *data, const uint8_t *end) : data(data), end(end) { } + ByteReader(const uint8_t *data, size_t len) : consumer(reinterpret_cast(data), len) { } const uint8_t *ReadBytes(size_t size) { - if (this->data + size >= this->end) { - /* Put data at the end, as would happen if every byte had been individually read. */ - this->data = this->end; - throw OTTDByteReaderSignal(); - } - - const uint8_t *ret = this->data; - this->data += size; - return ret; + auto result = this->consumer.Read(size); + if (result.size() != size) throw OTTDByteReaderSignal(); + return reinterpret_cast(result.data()); } /** @@ -36,8 +33,9 @@ public: */ uint8_t ReadByte() { - if (this->data < this->end) return *this->data++; - throw OTTDByteReaderSignal(); + auto result = this->consumer.TryReadUint8(); + if (!result.has_value()) throw OTTDByteReaderSignal(); + return *result; } /** @@ -46,8 +44,9 @@ public: */ uint16_t ReadWord() { - uint16_t val = this->ReadByte(); - return val | (this->ReadByte() << 8); + auto result = this->consumer.TryReadUint16LE(); + if (!result.has_value()) throw OTTDByteReaderSignal(); + return *result; } /** @@ -66,35 +65,51 @@ public: */ uint32_t ReadDWord() { - uint32_t val = this->ReadWord(); - return val | (this->ReadWord() << 16); + auto result = this->consumer.TryReadUint32LE(); + if (!result.has_value()) throw OTTDByteReaderSignal(); + return *result; + } + + /** + * Read a single DWord (32 bits). + * @note The buffer is NOT advanced. + * @returns Value read from buffer. + */ + uint32_t PeekDWord() + { + auto result = this->consumer.PeekUint32LE(); + if (!result.has_value()) throw OTTDByteReaderSignal(); + return *result; } - uint32_t PeekDWord(); uint32_t ReadVarSize(uint8_t size); - std::string_view ReadString(); + + /** + * Read a NUL-terminated string. + * @returns String read from the buffer. + */ + std::string_view ReadString() + { + /* Terminating NUL may be missing at the end of sprite. */ + return this->consumer.ReadUntilChar('\0', StringConsumer::SKIP_ONE_SEPARATOR); + } size_t Remaining() const { - return this->end - this->data; + return this->consumer.GetBytesLeft(); } bool HasData(size_t count = 1) const { - return this->data + count <= this->end; + return count <= this->consumer.GetBytesLeft(); } void Skip(size_t len) { - this->data += len; - /* It is valid to move the buffer to exactly the end of the data, - * as there may not be any more data read. */ - if (this->data > this->end) throw OTTDByteReaderSignal(); + auto result = this->consumer.Read(len); + if (result.size() != len) throw OTTDByteReaderSignal(); } -private: - const uint8_t *data; ///< Current position within data. - const uint8_t *end; ///< Last position of data. }; #endif /* NEWGRF_BYTEREADER_H */ diff --git a/src/string_func.h b/src/string_func.h index 0952993855..09c8dc18db 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -70,20 +70,6 @@ inline bool StrEmpty(const char *s) return s == nullptr || s[0] == '\0'; } -/** - * Get the length of a string, within a limited buffer. - * - * @param str The pointer to the first element of the buffer - * @param maxlen The maximum size of the buffer - * @return The length of the string - */ -inline size_t ttd_strnlen(const char *str, size_t maxlen) -{ - const char *t; - for (t = str; static_cast(t - str) < maxlen && *t != '\0'; t++) {} - return t - str; -} - bool IsValidChar(char32_t key, CharSetFilter afilter); size_t Utf8Decode(char32_t *c, const char *s); From 3964d053b5a068cd8a1409c3f328a2264dac7f01 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 27 Mar 2025 20:21:42 +0100 Subject: [PATCH 024/572] Codechange: Replace BufState with StringConsumer. --- src/3rdparty/squirrel/squirrel/sqapi.cpp | 37 ++++-------------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/sqapi.cpp b/src/3rdparty/squirrel/squirrel/sqapi.cpp index 189fe67329..e530cd23ce 100644 --- a/src/3rdparty/squirrel/squirrel/sqapi.cpp +++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp @@ -18,6 +18,7 @@ #include "sqfuncstate.h" #include "sqclass.h" +#include "../../../core/string_consumer.hpp" #include "../../../string_func.h" #include "../../../safeguards.h" @@ -1253,44 +1254,16 @@ SQRESULT sq_next(HSQUIRRELVM v,SQInteger idx) return SQ_ERROR; } -struct BufState{ - const SQChar *buf; - SQInteger ptr; - SQInteger size; -}; - char32_t buf_lexfeed(SQUserPointer file) { /* Convert an UTF-8 character into a char32_t */ - BufState *buf = (BufState *)file; - const char *p = &buf->buf[buf->ptr]; - - if (buf->size < buf->ptr + 1) return 0; - - /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */ - uint len = Utf8EncodedCharLen(*p); - if (len == 0) { - buf->ptr++; - return -1; - } - - /* Read the remaining bits. */ - if (buf->size < buf->ptr + len) return 0; - buf->ptr += len; - - /* Convert the character, and when definitely invalid, bail out as well. */ - char32_t c; - if (Utf8Decode(&c, p) != len) return -1; - - return c; + StringConsumer &consumer = *reinterpret_cast(file); + return consumer.AnyBytesLeft() ? consumer.ReadUtf8(-1) : 0; } SQRESULT sq_compilebuffer(HSQUIRRELVM v,const SQChar *s,SQInteger size,const SQChar *sourcename,SQBool raiseerror) { - BufState buf; - buf.buf = s; - buf.size = size; - buf.ptr = 0; - return sq_compile(v, buf_lexfeed, &buf, sourcename, raiseerror); + StringConsumer consumer(s, size); + return sq_compile(v, buf_lexfeed, &consumer, sourcename, raiseerror); } void sq_move(HSQUIRRELVM dest,HSQUIRRELVM src,SQInteger idx) From 9bcd3feb1720ce4787411e06d94b5e92871b863d Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 27 Mar 2025 22:10:47 +0100 Subject: [PATCH 025/572] Codechange: Make SQFile a buffered reader, based on StringConsumer. --- src/script/squirrel.cpp | 79 ++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index af65a993f5..05967deecc 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -18,6 +18,8 @@ #include #include <../squirrel/sqpcheader.h> #include <../squirrel/sqvm.h> +#include "../core/math_func.hpp" +#include "../core/string_consumer.hpp" #include "../safeguards.h" @@ -544,52 +546,73 @@ private: FileHandle file; size_t size; size_t pos; + std::string buffer; + StringConsumer consumer; + + size_t ReadInternal(std::span buf) + { + size_t count = buf.size(); + if (this->pos + count > this->size) { + count = this->size - this->pos; + } + if (count > 0) count = fread(buf.data(), 1, count, this->file); + this->pos += count; + return count; + } public: - SQFile(FileHandle file, size_t size) : file(std::move(file)), size(size), pos(0) {} + SQFile(FileHandle file, size_t size) : file(std::move(file)), size(size), pos(0), consumer(buffer) {} - size_t Read(void *buf, size_t elemsize, size_t count) + StringConsumer &GetConsumer(size_t min_size = 64) { - assert(elemsize != 0); - if (this->pos + (elemsize * count) > this->size) { - count = (this->size - this->pos) / elemsize; + if (this->consumer.GetBytesLeft() < min_size && this->pos < this->size) { + this->buffer.erase(0, this->consumer.GetBytesRead()); + + size_t buffer_size = this->buffer.size(); + size_t read_size = Align(min_size - buffer_size, 4096); // read pages of 4096 bytes + // TODO C++23: use std::string::resize_and_overwrite() + this->buffer.resize(buffer_size + read_size); + auto dest = std::span(this->buffer.data(), this->buffer.size()).subspan(buffer_size); + buffer_size += this->ReadInternal(dest); + this->buffer.resize(buffer_size); + + this->consumer = StringConsumer(this->buffer); } - if (count == 0) return 0; - size_t ret = fread(buf, elemsize, count, this->file); - this->pos += ret * elemsize; - return ret; + return this->consumer; + } + + size_t Read(void *buf, size_t max_size) + { + std::span dest(reinterpret_cast(buf), max_size); + + auto view = this->consumer.Read(max_size); + std::copy(view.data(), view.data() + view.size(), dest.data()); + size_t result_size = view.size(); + + if (result_size < max_size) { + assert(!this->consumer.AnyBytesLeft()); + result_size += this->ReadInternal(dest.subspan(result_size)); + } + + return result_size; } }; static char32_t _io_file_lexfeed_ASCII(SQUserPointer file) { - unsigned char c; - if (((SQFile *)file)->Read(&c, sizeof(c), 1) > 0) return c; - return 0; + StringConsumer &consumer = reinterpret_cast(file)->GetConsumer(); + return consumer.TryReadUint8().value_or(0); // read as unsigned, otherwise integer promotion breaks it } static char32_t _io_file_lexfeed_UTF8(SQUserPointer file) { - char buffer[5]; - - /* Read the first character, and get the length based on UTF-8 specs. If invalid, bail out. */ - if (((SQFile *)file)->Read(buffer, sizeof(buffer[0]), 1) != 1) return 0; - uint len = Utf8EncodedCharLen(buffer[0]); - if (len == 0) return -1; - - /* Read the remaining bits. */ - if (len > 1 && ((SQFile *)file)->Read(buffer + 1, sizeof(buffer[0]), len - 1) != len - 1) return 0; - - /* Convert the character, and when definitely invalid, bail out as well. */ - char32_t c; - if (Utf8Decode(&c, buffer) != len) return -1; - - return c; + StringConsumer &consumer = reinterpret_cast(file)->GetConsumer(); + return consumer.AnyBytesLeft() ? consumer.ReadUtf8(-1) : 0; } static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger size) { - SQInteger ret = ((SQFile *)file)->Read(buf, 1, size); + SQInteger ret = reinterpret_cast(file)->Read(buf, size); if (ret == 0) return -1; return ret; } From 131b7c71229aa96aaf7a53105cc4bfc4b6600a3c Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 28 Mar 2025 19:15:18 +0100 Subject: [PATCH 026/572] Codechange: Replace Utf8Decode usages with StringConsumer. --- src/osk_gui.cpp | 12 +++--------- src/saveload/saveload.cpp | 14 +++++++------ src/strings.cpp | 41 +++++++++++++++------------------------ 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index 4763321ba9..585c267f9f 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -16,6 +16,7 @@ #include "querystring_gui.h" #include "video/video_driver.hpp" #include "zoom_func.h" +#include "core/string_consumer.hpp" #include "widgets/osk_widget.h" @@ -358,17 +359,10 @@ void GetKeyboardLayout() keyboard[1] = _keyboard_opt[1].empty() ? GetString(STR_OSK_KEYBOARD_LAYOUT_CAPS) : _keyboard_opt[1]; for (uint j = 0; j < 2; j++) { - auto kbd = keyboard[j].begin(); - bool ended = false; + StringConsumer consumer(keyboard[j]); for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) { - _keyboard[j][i] = Utf8Consume(kbd); - /* Be lenient when the last characters are missing (is quite normal) */ - if (_keyboard[j][i] == '\0' || ended) { - ended = true; - _keyboard[j][i] = ' '; - continue; - } + _keyboard[j][i] = consumer.AnyBytesLeft() ? consumer.ReadUtf8() : ' '; if (IsPrintable(_keyboard[j][i])) { errormark[j] += ' '; diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 5b743ba20d..9c7bcc32c6 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -30,6 +30,7 @@ #include "../strings_func.h" #include "../core/endian_func.hpp" #include "../core/string_builder.hpp" +#include "../core/string_consumer.hpp" #include "../vehicle_base.h" #include "../company_func.h" #include "../timer/timer_game_economy.h" @@ -935,13 +936,14 @@ void FixSCCEncoded(std::string &str, bool fix_code) bool in_string = false; // Set if we in a string, between double-quotes. bool need_type = true; // Set if a parameter type needs to be emitted. - for (auto it = std::begin(str); it != std::end(str); /* nothing */) { - size_t len = Utf8EncodedCharLen(*it); - if (len == 0 || it + len > std::end(str)) break; - + StringConsumer consumer(str); + while (consumer.AnyBytesLeft()) { char32_t c; - Utf8Decode(&c, &*it); - it += len; + if (auto r = consumer.TryReadUtf8(); r.has_value()) { + c = *r; + } else { + break; + } if (c == SCC_ENCODED || (fix_code && (c == 0xE028 || c == 0xE02A))) { builder.PutUtf8(SCC_ENCODED); need_type = false; diff --git a/src/strings.cpp b/src/strings.cpp index 68a59c0c9b..438af68e8a 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -39,8 +39,8 @@ #include "core/backup_type.hpp" #include "gfx_layout.h" #include "core/utf8.hpp" +#include "core/string_consumer.hpp" #include -#include #include "table/strings.h" #include "table/control_codes.h" @@ -153,48 +153,39 @@ EncodedString EncodedString::ReplaceParam(size_t param, StringParameter &&data) if (this->empty()) return {}; std::vector params; + StringConsumer consumer(this->string); - /* We need char * for std::from_chars. Iterate the underlying data, as string's own iterators may interfere. */ - const char *p = this->string.data(); - const char *e = this->string.data() + this->string.length(); - - char32_t c = Utf8Consume(p); - if (c != SCC_ENCODED_INTERNAL) return {}; + if (!consumer.ReadUtf8If(SCC_ENCODED_INTERNAL)) return {}; StringID str; - auto result = std::from_chars(p, e, str, 16); - if (result.ec != std::errc()) return {}; - if (result.ptr != e && *result.ptr != SCC_RECORD_SEPARATOR) return {}; - p = result.ptr; + if (auto r = consumer.TryReadIntegerBase(16); r.has_value()) { + str = *r; + } else { + return {}; + } + if (consumer.AnyBytesLeft() && !consumer.ReadUtf8If(SCC_RECORD_SEPARATOR)) return {}; - while (p != e) { - auto s = ++p; + while (consumer.AnyBytesLeft()) { + StringConsumer record(consumer.ReadUntilUtf8(SCC_RECORD_SEPARATOR, StringConsumer::SKIP_ONE_SEPARATOR)); - /* Find end of the parameter. */ - for (; p != e && *p != SCC_RECORD_SEPARATOR; ++p) {} - - if (s == p) { + if (!record.AnyBytesLeft()) { /* This is an empty parameter. */ params.emplace_back(std::monostate{}); continue; } /* Get the parameter type. */ - char32_t parameter_type; - size_t len = Utf8Decode(¶meter_type, s); - s += len; - + char32_t parameter_type = record.ReadUtf8(); switch (parameter_type) { case SCC_ENCODED_NUMERIC: { - uint64_t value; - result = std::from_chars(s, p, value, 16); - if (result.ec != std::errc() || result.ptr != p) return {}; + uint64_t value = record.ReadIntegerBase(16); + assert(!record.AnyBytesLeft()); params.emplace_back(value); break; } case SCC_ENCODED_STRING: { - params.emplace_back(std::string(s, p)); + params.emplace_back(std::string(record.Read(StringConsumer::npos))); break; } From d48bc18721cb889174d9cc5faf80d91c5af20606 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 13 Apr 2025 21:06:09 +0100 Subject: [PATCH 027/572] Codechange: Rename badge_class to class_index and badge_classes to gui_classes internally. (#13995) These names are already used in some places, so this brings a bit of consistency. --- src/newgrf_badge.cpp | 46 ++++++++++++++++++++++---------------------- src/newgrf_badge.h | 8 ++++---- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/newgrf_badge.cpp b/src/newgrf_badge.cpp index b1269a02fe..0ed9cced62 100644 --- a/src/newgrf_badge.cpp +++ b/src/newgrf_badge.cpp @@ -285,7 +285,7 @@ static PalSpriteID GetBadgeSprite(const Badge &badge, GrfSpecFeature feature, st /** * Get the largest badge size (within limits) for a badge class. - * @param badge_class Badge class. + * @param class_index Badge class. * @param feature Feature being used. * @returns Largest base size of the badge class for the feature. */ @@ -439,11 +439,11 @@ int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature) { if (badges.empty()) return r.top; - std::set classes; - for (const BadgeID &index : badges) classes.insert(GetBadge(index)->class_index); + std::set class_indexes; + for (const BadgeID &index : badges) class_indexes.insert(GetBadge(index)->class_index); std::string_view list_separator = GetListSeparator(); - for (const BadgeClassID &class_index : classes) { + for (const BadgeClassID &class_index : class_indexes) { const Badge *class_badge = GetClassBadge(class_index); if (class_badge == nullptr || class_badge->name == STR_NULL) continue; @@ -473,23 +473,23 @@ int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature) * Draw a badge column group. * @param r rect to draw within. * @param column_group column to draw. - * @param badge_classes badge classes. + * @param gui_classes gui badge classes. * @param badges badges to draw. * @param feature feature being used. * @param introduction_date introduction date of item. * @param remap palette remap to for company-coloured badges. */ -void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &badge_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) +void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap) { bool rtl = _current_text_dir == TD_RTL; - for (const auto &badge_class : badge_classes.GetClasses()) { - if (badge_class.column_group != column_group) continue; - if (!badge_class.visible) continue; + for (const auto &gc : gui_classes.GetClasses()) { + if (gc.column_group != column_group) continue; + if (!gc.visible) continue; - int width = ScaleGUITrad(badge_class.size.width); + int width = ScaleGUITrad(gc.size.width); for (const BadgeID &index : badges) { const Badge &badge = *GetBadge(index); - if (badge.class_index != badge_class.badge_class) continue; + if (badge.class_index != gc.class_index) continue; PalSpriteID ps = GetBadgeSprite(badge, feature, introduction_date, remap); if (ps.sprite == 0) continue; @@ -507,13 +507,13 @@ template class DropDownBadges : public TBase { public: template - explicit DropDownBadges(const std::shared_ptr &badge_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, Args&&... args) - : TBase(std::forward(args)...), badge_classes(badge_classes), badges(badges), feature(feature), introduction_date(introduction_date) + explicit DropDownBadges(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, Args&&... args) + : TBase(std::forward(args)...), gui_classes(gui_classes), badges(badges), feature(feature), introduction_date(introduction_date) { - for (const auto &badge_class : badge_classes->GetClasses()) { - if (badge_class.column_group != 0) continue; - dim.width += badge_class.size.width + WidgetDimensions::scaled.hsep_normal; - dim.height = std::max(dim.height, badge_class.size.height); + for (const auto &gc : gui_classes->GetClasses()) { + if (gc.column_group != 0) continue; + dim.width += gc.size.width + WidgetDimensions::scaled.hsep_normal; + dim.height = std::max(dim.height, gc.size.height); } } @@ -524,13 +524,13 @@ public: { bool rtl = TEnd ^ (_current_text_dir == TD_RTL); - DrawBadgeColumn(r.WithWidth(this->dim.width, rtl), 0, *this->badge_classes, this->badges, this->feature, this->introduction_date, PAL_NONE); + DrawBadgeColumn(r.WithWidth(this->dim.width, rtl), 0, *this->gui_classes, this->badges, this->feature, this->introduction_date, PAL_NONE); this->TBase::Draw(full, r.Indent(this->dim.width + WidgetDimensions::scaled.hsep_wide, rtl), sel, bg_colour); } private: - std::shared_ptr badge_classes; + std::shared_ptr gui_classes; const std::span badges; const GrfSpecFeature feature; @@ -543,12 +543,12 @@ private: using DropDownListBadgeItem = DropDownBadges; using DropDownListBadgeIconItem = DropDownBadges; -std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &badge_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked, bool shaded) +std::unique_ptr MakeDropDownListBadgeItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, std::string &&str, int value, bool masked, bool shaded) { - return std::make_unique(badge_classes, badges, feature, introduction_date, std::move(str), value, masked, shaded); + return std::make_unique(gui_classes, badges, feature, introduction_date, std::move(str), value, masked, shaded); } -std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &badge_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked, bool shaded) +std::unique_ptr MakeDropDownListBadgeIconItem(const std::shared_ptr &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, const Dimension &dim, SpriteID sprite, PaletteID palette, std::string &&str, int value, bool masked, bool shaded) { - return std::make_unique(badge_classes, badges, feature, introduction_date, dim, sprite, palette, std::move(str), value, masked, shaded); + return std::make_unique(gui_classes, badges, feature, introduction_date, dim, sprite, palette, std::move(str), value, masked, shaded); } diff --git a/src/newgrf_badge.h b/src/newgrf_badge.h index e76baa71d5..b296aa98bc 100644 --- a/src/newgrf_badge.h +++ b/src/newgrf_badge.h @@ -44,15 +44,15 @@ Badge *GetClassBadge(BadgeClassID class_index); class GUIBadgeClasses { public: struct Element { - BadgeClassID badge_class; ///< Badge class index. + BadgeClassID class_index; ///< Badge class index. uint8_t column_group; ///< Column group in UI. 0 = left, 1 = centre, 2 = right. bool visible; ///< Whether this element is visible. uint sort_order; ///< Order of element. Dimension size; ///< Maximal size of this element. std::string_view label; ///< Class label (string owned by the class badge) - constexpr Element(BadgeClassID badge_class, uint8_t column_group, bool visible, uint sort_order, Dimension size, std::string_view label) : - badge_class(badge_class), column_group(column_group), visible(visible), sort_order(sort_order), size(size), label(label) {} + constexpr Element(BadgeClassID class_index, uint8_t column_group, bool visible, uint sort_order, Dimension size, std::string_view label) : + class_index(class_index), column_group(column_group), visible(visible), sort_order(sort_order), size(size), label(label) {} }; GUIBadgeClasses() = default; @@ -70,7 +70,7 @@ private: }; int DrawBadgeNameList(Rect r, std::span badges, GrfSpecFeature feature); -void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &badge_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap); +void DrawBadgeColumn(Rect r, int column_group, const GUIBadgeClasses &gui_classes, std::span badges, GrfSpecFeature feature, std::optional introduction_date, PaletteID remap); uint32_t GetBadgeVariableResult(const struct GRFFile &grffile, std::span badges, uint32_t parameter); From 3dacf46870a711591d3251517adcfe09fba8b3fe Mon Sep 17 00:00:00 2001 From: translators Date: Mon, 14 Apr 2025 04:44:46 +0000 Subject: [PATCH 028/572] Update: Translations from eints vietnamese: 7 changes by KhoiCanDev --- src/lang/vietnamese.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index f3525df674..8154410b2d 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -1210,7 +1210,7 @@ STR_CITY_APPROVAL_TOLERANT :Vừa phải STR_CITY_APPROVAL_HOSTILE :Khó khăn STR_CITY_APPROVAL_PERMISSIVE :Dễ dãi (không có tác dụng với hoạt động xây dựng của công ty) -STR_WARNING_NO_SUITABLE_AI :{WHITE}Không có AI nào phù hợp...{}Bạn có thể tải các AI từ mục 'Online Content' +STR_WARNING_NO_SUITABLE_AI :{WHITE}Không có AI nào phù hợp...{}{}Bạn có thể tải các AI từ mục 'Nội dung trực tuyến' # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Thiết lập @@ -2854,6 +2854,8 @@ STR_HOUSE_PICKER_CLASS_ZONE3 :Phía ngoài ng STR_HOUSE_PICKER_CLASS_ZONE4 :Phía trong ngoại ô STR_HOUSE_PICKER_CLASS_ZONE5 :Nội thành +STR_HOUSE_PICKER_PROTECT_OFF :Tắt +STR_HOUSE_PICKER_PROTECT_ON :Bật STR_STATION_CLASS_DFLT :Mặc định STR_STATION_CLASS_DFLT_STATION :Trạm mặc định @@ -4016,6 +4018,10 @@ STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Sản l STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Cần cung cấp: +STR_INDUSTRY_VIEW_ACCEPT_CARGO_SUFFIX :{YELLOW}{0:STRING}{BLACK}{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_SUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} đang chờ{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_NOSUFFIX :{YELLOW}{0:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_NOSUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} đang chờ STR_CONFIG_GAME_PRODUCTION :{WHITE}Thay đổi sản lượng (bội số của 8, max 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Thay đổi mức sản lượng (theo phần trăm, cao nhất 800%) From 069edc1a4bbcd5a284a6d1e450de77f2f4216ce4 Mon Sep 17 00:00:00 2001 From: John Taylor Date: Mon, 14 Apr 2025 16:57:07 +0200 Subject: [PATCH 029/572] Fix #13954: Plotting graphs with limited data to the right. (#13956) --- src/graph_gui.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index e3b89744b4..7cb36d9dbe 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -442,10 +442,14 @@ protected: y += y_sep; } + x = rtl ? r.right : r.left; + y = r.bottom + ScaleGUITrad(2); + + /* if there are not enough datapoints to fill the graph, align to the right */ + x += (this->num_vert_lines - this->num_on_x_axis) * x_sep; + /* Draw x-axis labels and markings for graphs based on financial quarters and years. */ if (this->draw_dates) { - x = rtl ? r.right : r.left; - y = r.bottom + ScaleGUITrad(2); TimerGameEconomy::Month month = this->month; TimerGameEconomy::Year year = this->year; for (int i = 0; i < this->num_on_x_axis; i++) { @@ -471,9 +475,6 @@ protected: } } else { /* Draw x-axis labels for graphs not based on quarterly performance (cargo payment rates, and all graphs when using wallclock units). */ - x = rtl ? r.right : r.left; - y = r.bottom + ScaleGUITrad(2); - int16_t iterator; uint16_t label; if (this->x_values_reversed) { @@ -512,6 +513,9 @@ protected: x = r.left + (x_sep / 2); } + /* if there are not enough datapoints to fill the graph, align to the right */ + x += (this->num_vert_lines - this->num_on_x_axis) * x_sep; + uint prev_x = INVALID_DATAPOINT_POS; uint prev_y = INVALID_DATAPOINT_POS; From 98efd3c96e4564ad40d680022edb43b25b3272d0 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 28 Mar 2025 16:18:24 +0100 Subject: [PATCH 030/572] Codefix #13872: Use StringConsumer in TranslateTTDPatchCodes. --- src/newgrf_text.cpp | 58 ++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 3deb92a221..fdb09ace1c 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -28,6 +28,7 @@ #include "debug.h" #include "core/alloc_type.hpp" #include "core/string_builder.hpp" +#include "core/string_consumer.hpp" #include "language.h" #include "table/strings.h" @@ -238,17 +239,10 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all /* Empty input string? Nothing to do here. */ if (str.empty()) return {}; - std::string_view::const_iterator src = str.cbegin(); + StringConsumer consumer(str); /* Is this an unicode string? */ - bool unicode = false; - char32_t marker; - size_t len = Utf8Decode(&marker, &*src); - - if (marker == NFO_UTF8_IDENTIFIER) { - unicode = true; - src += len; - } + bool unicode = consumer.ReadUtf8If(NFO_UTF8_IDENTIFIER); /* Helper variable for a possible (string) mapping of plural/gender and cases. */ std::optional mapping_pg, mapping_c; @@ -256,29 +250,27 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all std::string dest; StringBuilder builder(dest); - while (src != str.cend()) { + while (consumer.AnyBytesLeft()) { char32_t c; - - if (unicode && Utf8EncodedCharLen(*src) != 0) { - c = Utf8Consume(src); + if (auto u = unicode ? consumer.TryReadUtf8() : std::nullopt; u.has_value()) { + c = *u; /* 'Magic' range of control codes. */ - if (GB(c, 8, 8) == 0xE0) { - c = GB(c, 0, 8); + if (0xE000 <= c && c <= 0xE0FF) { + c -= 0xE000; } else if (c >= 0x20) { if (!IsValidChar(c, CS_ALPHANUMERAL)) c = '?'; builder.PutUtf8(c); continue; } } else { - c = static_cast(*src++); + c = consumer.ReadUint8(); // read as unsigned, otherwise integer promotion breaks it } - + assert(c <= 0xFF); if (c == '\0') break; switch (c) { case 0x01: - if (*src == '\0') goto string_end; - src++; + consumer.SkipUint8(); builder.PutChar(' '); break; case 0x0A: break; @@ -292,8 +284,8 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x0E: builder.PutUtf8(SCC_TINYFONT); break; case 0x0F: builder.PutUtf8(SCC_BIGFONT); break; case 0x1F: - if (src[0] == '\0' || src[1] == '\0') goto string_end; - src += 2; + consumer.SkipUint8(); + consumer.SkipUint8(); builder.PutChar(' '); break; case 0x7B: @@ -304,10 +296,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x80: builder.PutUtf8(byte80); break; case 0x81: { - if (src[0] == '\0' || src[1] == '\0') goto string_end; - uint16_t string; - string = static_cast(*src++); - string |= static_cast(*src++) << 8; + uint16_t string = consumer.ReadUint16LE(); builder.PutUtf8(SCC_NEWGRF_STRINL); builder.PutUtf8(MapGRFStringID(grfid, GRFStringID{string})); break; @@ -337,7 +326,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x98: builder.PutUtf8(SCC_BLACK); break; case 0x9A: { - int code = *src++; + uint8_t code = consumer.ReadUint8(); switch (code) { case 0x00: goto string_end; case 0x01: builder.PutUtf8(SCC_NEWGRF_PRINT_QWORD_CURRENCY); break; @@ -350,9 +339,7 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all * support this. As such it is not implemented in OpenTTD. */ case 0x03: { - if (src[0] == '\0' || src[1] == '\0') goto string_end; - uint16_t tmp = static_cast(*src++); - tmp |= static_cast(*src++) << 8; + uint16_t tmp = consumer.ReadUint16LE(); builder.PutUtf8(SCC_NEWGRF_PUSH_WORD); builder.PutUtf8(tmp); break; @@ -367,9 +354,8 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x0E: case 0x0F: { - if (str[0] == '\0') goto string_end; const LanguageMap *lm = LanguageMap::GetLanguageMap(grfid, language_id); - int index = *src++; + int index = consumer.ReadUint8(); int mapped = lm != nullptr ? lm->GetMapping(index, code == 0x0E) : -1; if (mapped >= 0) { builder.PutUtf8(code == 0x0E ? SCC_GENDER_INDEX : SCC_SET_CASE); @@ -380,14 +366,13 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x10: case 0x11: - if (str[0] == '\0') goto string_end; if (!mapping_pg.has_value() && !mapping_c.has_value()) { - if (code == 0x10) src++; // Skip the index + if (code == 0x10) consumer.SkipUint8(); // Skip the index GrfMsg(1, "choice list {} marker found when not expected", code == 0x10 ? "next" : "default"); break; } else { auto &mapping = mapping_pg ? mapping_pg : mapping_c; - int index = (code == 0x10 ? *src++ : 0); + int index = (code == 0x10 ? consumer.ReadUint8() : 0); if (mapping->strings.find(index) != mapping->strings.end()) { GrfMsg(1, "duplicate choice list string, ignoring"); } else { @@ -416,14 +401,13 @@ std::string TranslateTTDPatchCodes(uint32_t grfid, uint8_t language_id, bool all case 0x14: case 0x15: { auto &mapping = code == 0x14 ? mapping_c : mapping_pg; - if (src[0] == '\0') goto string_end; /* Case mapping can have nested plural/gender mapping. Otherwise nesting is invalid. */ if (mapping.has_value() || mapping_pg.has_value()) { GrfMsg(1, "choice lists can't be stacked, it's going to get messy now..."); - if (code != 0x14) src++; + if (code != 0x14) consumer.SkipUint8(); } else { static const StringControlCode mp[] = { SCC_GENDER_LIST, SCC_SWITCH_CASE, SCC_PLURAL_LIST }; - mapping.emplace(mp[code - 0x13], code == 0x14 ? 0 : *src++); + mapping.emplace(mp[code - 0x13], code == 0x14 ? 0 : consumer.ReadUint8()); } break; } From 15a17d832fff6acec1a2a736054490ecc060c853 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 28 Mar 2025 16:31:16 +0100 Subject: [PATCH 031/572] Codechange: Use StringConsumer in HandleNewGRFStringControlCodes. --- src/newgrf_text.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index fdb09ace1c..a23d94a988 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -746,11 +746,11 @@ static void HandleNewGRFStringControlCodes(std::string_view str, TextRefStack &s /** * Process NewGRF string control code instructions. * @param scc The string control code that has been read. - * @param str The string that we are reading from. + * @param consumer The string that we are reading from. * @param stack The TextRefStack. * @param[out] params Output parameters */ -static void ProcessNewGRFStringControlCode(char32_t scc, const char *&str, TextRefStack &stack, std::vector ¶ms) +static void ProcessNewGRFStringControlCode(char32_t scc, StringConsumer &consumer, TextRefStack &stack, std::vector ¶ms) { /* There is data on the NewGRF text stack, and we want to move them to OpenTTD's string stack. * After this call, a new call is made with `modify_parameters` set to false when the string is finally formatted. */ @@ -758,33 +758,35 @@ static void ProcessNewGRFStringControlCode(char32_t scc, const char *&str, TextR default: return; case SCC_PLURAL_LIST: - ++str; // plural form + consumer.SkipUint8(); // plural form [[fallthrough]]; case SCC_GENDER_LIST: { - ++str; // offset + consumer.SkipUint8(); // offset /* plural and gender choices cannot contain any string commands, so just skip the whole thing */ - uint num = static_cast(*str++); + uint num = consumer.ReadUint8(); uint total_len = 0; for (uint i = 0; i != num; i++) { - total_len += static_cast(*str++); + total_len += consumer.ReadUint8(); } - str += total_len; + consumer.Skip(total_len); break; } case SCC_SWITCH_CASE: { /* skip all cases and continue with default case */ - uint num = static_cast(*str++); + uint num = consumer.ReadUint8(); for (uint i = 0; i != num; i++) { - str += 3 + static_cast(str[1]) + (static_cast(str[2]) << 8); + consumer.SkipUint8(); + auto len = consumer.ReadUint16LE(); + consumer.Skip(len); } - str += 2; // length of default + consumer.SkipUint16LE(); // length of default break; } case SCC_GENDER_INDEX: case SCC_SET_CASE: - ++str; + consumer.SkipUint8(); break; case SCC_ARG_INDEX: @@ -824,7 +826,7 @@ static void ProcessNewGRFStringControlCode(char32_t scc, const char *&str, TextR case SCC_NEWGRF_DISCARD_WORD: stack.PopUnsignedWord(); break; case SCC_NEWGRF_ROTATE_TOP_4_WORDS: stack.RotateTop4Words(); break; - case SCC_NEWGRF_PUSH_WORD: stack.PushWord(Utf8Consume(&str)); break; + case SCC_NEWGRF_PUSH_WORD: stack.PushWord(consumer.ReadUtf8(0)); break; case SCC_NEWGRF_PRINT_WORD_CARGO_LONG: case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT: @@ -834,7 +836,7 @@ static void ProcessNewGRFStringControlCode(char32_t scc, const char *&str, TextR break; case SCC_NEWGRF_STRINL: { - StringID stringid = Utf8Consume(str); + StringID stringid = consumer.ReadUtf8(STR_NULL); /* We also need to handle the substring's stack usage. */ HandleNewGRFStringControlCodes(GetStringPtr(stringid), stack, params); break; @@ -947,10 +949,10 @@ char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str) */ static void HandleNewGRFStringControlCodes(std::string_view str, TextRefStack &stack, std::vector ¶ms) { - for (const char *p = str.data(), *end = str.data() + str.size(); p < end; /* nothing */) { - char32_t scc; - p += Utf8Decode(&scc, p); - ProcessNewGRFStringControlCode(scc, p, stack, params); + StringConsumer consumer(str); + while (consumer.AnyBytesLeft()) { + char32_t scc = consumer.ReadUtf8(); + ProcessNewGRFStringControlCode(scc, consumer, stack, params); } } From f5ffd4789bca560dc7910b94a287c9dfd3513eb7 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 28 Mar 2025 17:38:11 +0100 Subject: [PATCH 032/572] Codechange: Use StringConsumer in FormatString. --- src/newgrf_text.cpp | 6 +- src/strings.cpp | 146 +++++++++++++++++++---------------------- src/strings_internal.h | 3 +- 3 files changed, 73 insertions(+), 82 deletions(-) diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index a23d94a988..7d17af6b13 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -861,10 +861,10 @@ static void ProcessNewGRFStringControlCode(char32_t scc, StringConsumer &consume /** * Emit OpenTTD's internal string code for the different NewGRF string codes. * @param scc NewGRF string code. - * @param[in,out] str String iterator, moved forward if SCC_NEWGRF_PUSH_WORD is found. + * @param consumer String consumer, moved forward if SCC_NEWGRF_PUSH_WORD is found. * @returns String code to use. */ -char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str) +char32_t RemapNewGRFStringControlCode(char32_t scc, StringConsumer &consumer) { switch (scc) { default: @@ -932,7 +932,7 @@ char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str) /* These NewGRF string codes modify the NewGRF stack or otherwise do not map to OpenTTD string codes. */ case SCC_NEWGRF_PUSH_WORD: - Utf8Consume(str); + consumer.SkipUtf8(); return 0; case SCC_NEWGRF_DISCARD_WORD: diff --git a/src/strings.cpp b/src/strings.cpp index 438af68e8a..d0d65f9d40 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -644,7 +644,7 @@ static void FormatGenericCurrency(StringBuilder &builder, const CurrencySpec *sp * @param plural_form The plural form we want an index for. * @return The plural index for the given form. */ -static int DeterminePluralForm(int64_t count, int plural_form) +static int DeterminePluralForm(int64_t count, uint plural_form) { /* The absolute value determines plurality */ uint64_t n = abs(count); @@ -765,22 +765,25 @@ static int DeterminePluralForm(int64_t count, int plural_form) } } -static const char *ParseStringChoice(const char *b, uint form, StringBuilder &builder) +static void ParseStringChoice(StringConsumer &consumer, uint form, StringBuilder &builder) { /* {Length of each string} {each string} */ - uint n = (uint8_t)*b++; - size_t form_offset = 0, form_len = 0, total_len = 0; + uint n = consumer.ReadUint8(); + size_t form_pre = 0, form_len = 0, form_post = 0; for (uint i = 0; i != n; i++) { - uint len = (uint8_t)*b++; - if (i == form) { - form_offset = total_len; + uint len = consumer.ReadUint8(); + if (i < form) { + form_pre += len; + } else if (i > form) { + form_post += len; + } else { form_len = len; } - total_len += len; } - builder += std::string_view(b + form_offset, form_len); - return b + total_len; + consumer.Skip(form_pre); + builder += consumer.Read(form_len); + consumer.Skip(form_post); } /** Helper for unit conversion. */ @@ -982,67 +985,59 @@ uint ConvertDisplaySpeedToKmhishSpeed(uint speed, VehicleType type) /** * Decodes an encoded string during FormatString. - * @param str The buffer of the encoded string. + * @param consumer The encoded string. * @param game_script Set if decoding a GameScript-encoded string. This affects how string IDs are handled. * @param builder The string builder to write the string to. - * @returns Updated position position in input buffer. */ -static const char *DecodeEncodedString(const char *str, bool game_script, StringBuilder &builder) +static void DecodeEncodedString(StringConsumer &consumer, bool game_script, StringBuilder &builder) { std::vector sub_args; - char *p; - StringIndexInTab id(std::strtoul(str, &p, 16)); - if (*p != SCC_RECORD_SEPARATOR && *p != '\0') { - while (*p != '\0') p++; + StringIndexInTab id(consumer.ReadIntegerBase(16)); + if (consumer.AnyBytesLeft() && !consumer.ReadUtf8If(SCC_RECORD_SEPARATOR)) { + consumer.SkipAll(); builder += "(invalid SCC_ENCODED)"; - return p; + return; } if (game_script && id >= TAB_SIZE_GAMESCRIPT) { - while (*p != '\0') p++; + consumer.SkipAll(); builder += "(invalid StringID)"; - return p; + return; } - while (*p != '\0') { - /* The start of parameter. */ - const char *s = ++p; + while (consumer.AnyBytesLeft()) { + StringConsumer record(consumer.ReadUntilUtf8(SCC_RECORD_SEPARATOR, StringConsumer::SKIP_ONE_SEPARATOR)); - /* Find end of the parameter. */ - for (; *p != '\0' && *p != SCC_RECORD_SEPARATOR; ++p) {} - - if (s == p) { + if (!record.AnyBytesLeft()) { /* This is an empty parameter. */ sub_args.emplace_back(std::monostate{}); continue; } /* Get the parameter type. */ - char32_t parameter_type; - size_t len = Utf8Decode(¶meter_type, s); - s += len; - + char32_t parameter_type = record.ReadUtf8(); switch (parameter_type) { case SCC_ENCODED: { - uint64_t param = std::strtoull(s, &p, 16); + uint64_t param = record.ReadIntegerBase(16); if (param >= TAB_SIZE_GAMESCRIPT) { - while (*p != '\0') p++; builder += "(invalid sub-StringID)"; - return p; + return; } + assert(!record.AnyBytesLeft()); param = MakeStringID(TEXT_TAB_GAMESCRIPT_START, StringIndexInTab(param)); sub_args.emplace_back(param); break; } case SCC_ENCODED_NUMERIC: { - uint64_t param = std::strtoull(s, &p, 16); + uint64_t param = record.ReadIntegerBase(16); + assert(!record.AnyBytesLeft()); sub_args.emplace_back(param); break; } case SCC_ENCODED_STRING: { - sub_args.emplace_back(std::string(s, p - s)); + sub_args.emplace_back(std::string(record.Read(StringConsumer::npos))); break; } @@ -1055,8 +1050,6 @@ static const char *DecodeEncodedString(const char *str, bool game_script, String StringID stringid = game_script ? MakeStringID(TEXT_TAB_GAMESCRIPT_START, id) : StringID{id.base()}; GetStringWithArgs(builder, stringid, sub_args, true); - - return p; } /** @@ -1087,13 +1080,12 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin } uint next_substr_case_index = 0; struct StrStackItem { - const char *str; - const char *end; + StringConsumer consumer; size_t first_param_offset; uint case_index; StrStackItem(std::string_view view, size_t first_param_offset, uint case_index) - : str(view.data()), end(view.data() + view.size()), first_param_offset(first_param_offset), case_index(case_index) + : consumer(view), first_param_offset(first_param_offset), case_index(case_index) {} }; std::stack> str_stack; @@ -1101,19 +1093,19 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin for (;;) { try { - while (!str_stack.empty() && str_stack.top().str >= str_stack.top().end) { + while (!str_stack.empty() && !str_stack.top().consumer.AnyBytesLeft()) { str_stack.pop(); } if (str_stack.empty()) break; - const char *&str = str_stack.top().str; + StringConsumer &consumer = str_stack.top().consumer; const size_t ref_param_offset = str_stack.top().first_param_offset; const uint case_index = str_stack.top().case_index; - char32_t b = Utf8Consume(&str); + char32_t b = consumer.ReadUtf8(); assert(b != 0); if (SCC_NEWGRF_FIRST <= b && b <= SCC_NEWGRF_LAST) { /* We need to pass some stuff as it might be modified. */ - b = RemapNewGRFStringControlCode(b, &str); + b = RemapNewGRFStringControlCode(b, consumer); if (b == 0) continue; } @@ -1126,13 +1118,13 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin switch (b) { case SCC_ENCODED: case SCC_ENCODED_INTERNAL: - str = DecodeEncodedString(str, b == SCC_ENCODED, builder); + DecodeEncodedString(consumer, b == SCC_ENCODED, builder); break; case SCC_NEWGRF_STRINL: { - StringID substr = Utf8Consume(&str); + StringID substr = consumer.ReadUtf8(STR_NULL); std::string_view ptr = GetStringPtr(substr); - str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str" + str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "consumer" next_substr_case_index = 0; break; } @@ -1140,15 +1132,15 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin case SCC_NEWGRF_PRINT_WORD_STRING_ID: { StringID substr = args.GetNextParameter(); std::string_view ptr = GetStringPtr(substr); - str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "str" + str_stack.emplace(ptr, args.GetOffset(), next_substr_case_index); // this may invalidate "consumer" next_substr_case_index = 0; break; } case SCC_GENDER_LIST: { // {G 0 Der Die Das} /* First read the meta data from the language file. */ - size_t offset = ref_param_offset + (uint8_t)*str++; - int gender = 0; + size_t offset = ref_param_offset + consumer.ReadUint8(); + uint8_t gender = 0; if (offset >= args.GetNumParameters()) { /* The offset may come from an external NewGRF, and be invalid. */ builder += "(invalid GENDER parameter)"; @@ -1170,37 +1162,38 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin FormatString(tmp_builder, input, tmp_params); } - /* The gender is stored at the start of the formatted string. */ - const char *s = buffer.c_str(); - char32_t c = Utf8Consume(&s); - /* Does this string have a gender, if so, set it */ - if (c == SCC_GENDER_INDEX) gender = (uint8_t)s[0]; + /* The gender is stored at the start of the formatted string. + * Does this string have a gender, if so, set it. */ + StringConsumer gender_consumer(buffer); + if (gender_consumer.ReadUtf8If(SCC_GENDER_INDEX)) { + gender = gender_consumer.ReadUint8(); + } } - str = ParseStringChoice(str, gender, builder); + ParseStringChoice(consumer, gender, builder); break; } /* This sets up the gender for the string. * We just ignore this one. It's used in {G 0 Der Die Das} to determine the case. */ - case SCC_GENDER_INDEX: // {GENDER 0} + case SCC_GENDER_INDEX: { // {GENDER 0} + uint8_t gender = consumer.ReadUint8(); if (_scan_for_gender_data) { builder.PutUtf8(SCC_GENDER_INDEX); - builder.PutUint8(*str++); - } else { - str++; + builder.PutUint8(gender); } break; + } case SCC_PLURAL_LIST: { // {P} - int plural_form = *str++; // contains the plural form for this string - size_t offset = ref_param_offset + (uint8_t)*str++; + uint8_t plural_form = consumer.ReadUint8(); // contains the plural form for this string + size_t offset = ref_param_offset + consumer.ReadUint8(); const uint64_t *v = nullptr; /* The offset may come from an external NewGRF, and be invalid. */ if (offset < args.GetNumParameters()) { v = std::get_if(&args.GetParam(offset)); // contains the number that determines plural } if (v != nullptr) { - str = ParseStringChoice(str, DeterminePluralForm(static_cast(*v), plural_form), builder); + ParseStringChoice(consumer, DeterminePluralForm(static_cast(*v), plural_form), builder); } else { builder += "(invalid PLURAL parameter)"; } @@ -1208,38 +1201,35 @@ static void FormatString(StringBuilder &builder, std::string_view str_arg, Strin } case SCC_ARG_INDEX: { // Move argument pointer - args.SetOffset(ref_param_offset + (uint8_t)*str++); + args.SetOffset(ref_param_offset + consumer.ReadUint8()); break; } case SCC_SET_CASE: { // {SET_CASE} /* This is a pseudo command, it's outputted when someone does {STRING.ack} * The modifier is added to all subsequent GetStringWithArgs that accept the modifier. */ - next_substr_case_index = (uint8_t)*str++; + next_substr_case_index = consumer.ReadUint8(); break; } case SCC_SWITCH_CASE: { // {Used to implement case switching} /* <0x9E> * Each LEN is printed using 2 bytes in little endian order. */ - uint num = (uint8_t)*str++; + uint num = consumer.ReadUint8(); std::optional found; for (; num > 0; --num) { - uint8_t index = static_cast(str[0]); - uint16_t len = static_cast(str[1]) + (static_cast(str[2]) << 8); - str += 3; + uint8_t index = consumer.ReadUint8(); + uint16_t len = consumer.ReadUint16LE(); + auto case_str = consumer.Read(len); if (index == case_index) { /* Found the case */ - found.emplace(str, len); + found = case_str; } - str += len; } - uint16_t default_len = static_cast(str[0]) + (static_cast(str[1]) << 8); - str += 2; - if (!found.has_value()) found.emplace(str, default_len); - str += default_len; - assert(str <= str_stack.top().end); - str_stack.emplace(*found, ref_param_offset, case_index); // this may invalidate "str" + uint16_t default_len = consumer.ReadUint16LE(); + auto default_str = consumer.Read(default_len); + if (!found.has_value()) found = default_str; + str_stack.emplace(*found, ref_param_offset, case_index); // this may invalidate "consumer" break; } diff --git a/src/strings_internal.h b/src/strings_internal.h index 47e4329bad..c15a09a0c3 100644 --- a/src/strings_internal.h +++ b/src/strings_internal.h @@ -13,6 +13,7 @@ #include "strings_func.h" #include "string_func.h" #include "core/string_builder.hpp" +#include "core/string_consumer.hpp" class StringParameters { protected: @@ -214,6 +215,6 @@ void GenerateTownNameString(StringBuilder &builder, size_t lang, uint32_t seed); void GetTownName(StringBuilder &builder, const struct Town *t); void GRFTownNameGenerate(StringBuilder &builder, uint32_t grfid, uint16_t gen, uint32_t seed); -char32_t RemapNewGRFStringControlCode(char32_t scc, const char **str); +char32_t RemapNewGRFStringControlCode(char32_t scc, StringConsumer &consumer); #endif /* STRINGS_INTERNAL_H */ From dc21fae18e06b5f8f70553bdc942f30194152fe9 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 3 Apr 2025 20:50:51 +0200 Subject: [PATCH 033/572] Codechange: Add InPlaceReplacement to couple StringConsumer and Builder on the same buffer. --- src/core/CMakeLists.txt | 2 + src/core/string_inplace.cpp | 63 ++++++++++++++++++++ src/core/string_inplace.hpp | 105 +++++++++++++++++++++++++++++++++ src/settingsgen/CMakeLists.txt | 1 + src/strgen/CMakeLists.txt | 1 + src/tests/CMakeLists.txt | 1 + src/tests/string_inplace.cpp | 57 ++++++++++++++++++ 7 files changed, 230 insertions(+) create mode 100644 src/core/string_inplace.cpp create mode 100644 src/core/string_inplace.hpp create mode 100644 src/tests/string_inplace.cpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index d21ea8da92..448090585d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -27,6 +27,8 @@ add_files( string_builder.hpp string_consumer.cpp string_consumer.hpp + string_inplace.cpp + string_inplace.hpp strong_typedef_type.hpp utf8.cpp utf8.hpp diff --git a/src/core/string_inplace.cpp b/src/core/string_inplace.cpp new file mode 100644 index 0000000000..248fe8d130 --- /dev/null +++ b/src/core/string_inplace.cpp @@ -0,0 +1,63 @@ +/* + * 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 string_inplace.cpp Inplace-replacement of textual and binary data. + */ + +#include "../stdafx.h" +#include "string_inplace.hpp" +#include "../safeguards.h" + +/** + * Check whether any unused bytes are left between the Builder and Consumer position. + */ +[[nodiscard]] bool InPlaceBuilder::AnyBytesUnused() const noexcept +{ + return this->consumer.GetBytesRead() > this->position; +} + +/** + * Get number of unused bytes left between the Builder and Consumer position. + */ +[[nodiscard]] InPlaceBuilder::size_type InPlaceBuilder::GetBytesUnused() const noexcept +{ + return this->consumer.GetBytesRead() - this->position; +} + +/** + * Append buffer. + */ +void InPlaceBuilder::PutBuffer(const char *str, size_type len) +{ + auto unused = this->GetBytesUnused(); + if (len > unused) NOT_REACHED(); + std::copy(str, str + len, this->dest.data() + this->position); + this->position += len; +} + +/** + * Create coupled Consumer+Builder pair. + * @param buffer Data to consume and replace. + * @note The lifetime of the buffer must exceed the lifetime of both the Consumer and the Builder. + */ +InPlaceReplacement::InPlaceReplacement(std::span buffer) + : consumer(buffer), builder(buffer, consumer) +{ +} + +InPlaceReplacement::InPlaceReplacement(const InPlaceReplacement &src) + : consumer(src.consumer), builder(src.builder, consumer) +{ +} + +InPlaceReplacement& InPlaceReplacement::operator=(const InPlaceReplacement &src) +{ + this->consumer = src.consumer; + this->builder.AssignBuffer(src.builder); + return *this; +} diff --git a/src/core/string_inplace.hpp b/src/core/string_inplace.hpp new file mode 100644 index 0000000000..855ae55896 --- /dev/null +++ b/src/core/string_inplace.hpp @@ -0,0 +1,105 @@ +/* + * 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 string_inplace.hpp Inplace-replacement of textual and binary data. + */ + +#ifndef STRING_INPLACE_HPP +#define STRING_INPLACE_HPP + +#include "string_builder.hpp" +#include "string_consumer.hpp" + +/** + * Builder implementation for InPlaceReplacement. + */ +class InPlaceBuilder final : public BaseStringBuilder +{ + std::span dest; + size_type position = 0; + const StringConsumer &consumer; + + friend class InPlaceReplacement; + explicit InPlaceBuilder(std::span dest, const StringConsumer &consumer) : dest(dest), consumer(consumer) {} + InPlaceBuilder(const InPlaceBuilder &src, const StringConsumer &consumer) : dest(src.dest), position(src.position), consumer(consumer) {} + void AssignBuffer(const InPlaceBuilder &src) { this->dest = src.dest; this->position = src.position; } +public: + InPlaceBuilder(const InPlaceBuilder &) = delete; + InPlaceBuilder& operator=(const InPlaceBuilder &) = delete; + + /** + * Check whether any bytes have been written. + */ + [[nodiscard]] bool AnyBytesWritten() const noexcept { return this->position != 0; } + /** + * Get number of already written bytes. + */ + [[nodiscard]] size_type GetBytesWritten() const noexcept { return this->position; } + /** + * Get already written data. + */ + [[nodiscard]] std::string_view GetWrittenData() const noexcept { return {this->dest.data(), this->position}; } + + [[nodiscard]] bool AnyBytesUnused() const noexcept; + [[nodiscard]] size_type GetBytesUnused() const noexcept; + + using BaseStringBuilder::PutBuffer; + void PutBuffer(const char *str, size_type len) override; + + /** + * Implementation of std::back_insert_iterator for non-growing destination buffer. + */ + class back_insert_iterator { + InPlaceBuilder *parent = nullptr; + public: + using value_type = void; + using difference_type = void; + using iterator_category = std::output_iterator_tag; + using pointer = void; + using reference = void; + + back_insert_iterator(InPlaceBuilder &parent) : parent(&parent) {} + + back_insert_iterator &operator++() { return *this; } + back_insert_iterator operator++(int) { return *this; } + back_insert_iterator &operator*() { return *this; } + + back_insert_iterator &operator=(char value) + { + this->parent->PutChar(value); + return *this; + } + }; + /** + * Create a back-insert-iterator. + */ + back_insert_iterator back_inserter() + { + return back_insert_iterator(*this); + } +}; + +/** + * Compose data into a fixed size buffer, which is consumed at the same time. + * - The Consumer reads data from a buffer. + * - The Builder writes data to the buffer, replacing already consumed data. + * - The Builder asserts, if it overtakes the consumer. + */ +class InPlaceReplacement +{ +public: + StringConsumer consumer; ///< Consumer from shared buffer + InPlaceBuilder builder; ///< Builder into shared buffer + +public: + InPlaceReplacement(std::span buffer); + InPlaceReplacement(const InPlaceReplacement &src); + InPlaceReplacement& operator=(const InPlaceReplacement &src); +}; + +#endif /* STRING_INPLACE_HPP */ diff --git a/src/settingsgen/CMakeLists.txt b/src/settingsgen/CMakeLists.txt index 220ffb972b..7f7c1854b1 100644 --- a/src/settingsgen/CMakeLists.txt +++ b/src/settingsgen/CMakeLists.txt @@ -12,6 +12,7 @@ if (NOT HOST_BINARY_DIR) ../string.cpp ../core/string_builder.cpp ../core/string_consumer.cpp + ../core/string_inplace.cpp ../core/utf8.cpp ) add_definitions(-DSETTINGSGEN) diff --git a/src/strgen/CMakeLists.txt b/src/strgen/CMakeLists.txt index 40eb11448f..64d1905089 100644 --- a/src/strgen/CMakeLists.txt +++ b/src/strgen/CMakeLists.txt @@ -14,6 +14,7 @@ if (NOT HOST_BINARY_DIR) ../string.cpp ../core/string_builder.cpp ../core/string_consumer.cpp + ../core/string_inplace.cpp ../core/utf8.cpp ) add_definitions(-DSTRGEN) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 29f97ad205..94579147fa 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -9,6 +9,7 @@ add_test_files( mock_spritecache.h string_builder.cpp string_consumer.cpp + string_inplace.cpp string_func.cpp test_main.cpp test_network_crypto.cpp diff --git a/src/tests/string_inplace.cpp b/src/tests/string_inplace.cpp new file mode 100644 index 0000000000..275c2c1fd3 --- /dev/null +++ b/src/tests/string_inplace.cpp @@ -0,0 +1,57 @@ +/* + * 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 string_inplace.cpp Test functionality from core/string_inplace. */ + +#include "../stdafx.h" +#include "../3rdparty/catch2/catch.hpp" +#include "../core/string_inplace.hpp" +#include "../safeguards.h" + +using namespace std::literals; + +TEST_CASE("InPlaceReplacement") +{ + std::array buffer{1, 2, 3, 4}; + InPlaceReplacement inplace(buffer); + + CHECK(!inplace.builder.AnyBytesWritten()); + CHECK(inplace.builder.GetBytesWritten() == 0); + CHECK(inplace.builder.GetWrittenData() == ""sv); + CHECK(!inplace.builder.AnyBytesUnused()); + CHECK(inplace.builder.GetBytesUnused() == 0); + CHECK(!inplace.consumer.AnyBytesRead()); + CHECK(inplace.consumer.GetBytesRead() == 0); + CHECK(inplace.consumer.AnyBytesLeft()); + CHECK(inplace.consumer.GetBytesLeft() == 4); + + CHECK(inplace.consumer.ReadUint16LE() == 0x201); + + CHECK(inplace.builder.GetBytesWritten() == 0); + CHECK(inplace.builder.GetBytesUnused() == 2); + CHECK(inplace.consumer.GetBytesRead() == 2); + CHECK(inplace.consumer.GetBytesLeft() == 2); + + inplace.builder.PutUint8(11); + + CHECK(inplace.builder.GetBytesWritten() == 1); + CHECK(inplace.builder.GetBytesUnused() == 1); + CHECK(inplace.consumer.GetBytesRead() == 2); + CHECK(inplace.consumer.GetBytesLeft() == 2); + + inplace.builder.PutUint8(12); + + CHECK(inplace.builder.GetBytesWritten() == 2); + CHECK(inplace.builder.GetBytesUnused() == 0); + CHECK(inplace.consumer.GetBytesRead() == 2); + CHECK(inplace.consumer.GetBytesLeft() == 2); + + CHECK(buffer[0] == 11); + CHECK(buffer[1] == 12); + CHECK(buffer[2] == 3); + CHECK(buffer[3] == 4); +} From b81a35ea89f02248b187268e00449e1f668bbd9b Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 1 Apr 2025 19:14:30 +0200 Subject: [PATCH 034/572] Codechange: Use StringConsumer and Builder in StrMakeValid and StrValid. --- src/string.cpp | 137 ++++++++++++++++--------------------------------- 1 file changed, 43 insertions(+), 94 deletions(-) diff --git a/src/string.cpp b/src/string.cpp index 2fadbb2e30..4032a7f34f 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -14,6 +14,7 @@ #include "string_func.h" #include "string_base.h" #include "core/utf8.hpp" +#include "core/string_inplace.hpp" #include "table/control_codes.h" @@ -108,76 +109,40 @@ static bool IsSccEncodedCode(char32_t c) } /** - * Copies the valid (UTF-8) characters from \c str up to \c last to the \c dst. + * Copies the valid (UTF-8) characters from \c consumer to the \c builder. * Depending on the \c settings invalid characters can be replaced with a * question mark, as well as determining what characters are deemed invalid. * - * It is allowed for \c dst to be the same as \c src, in which case the string - * is make valid in place. - * @param dst The destination to write to. - * @param str The string to validate. - * @param last The last valid character of str. + * @param builder The destination to write to. + * @param consumer The string to validate. * @param settings The settings for the string validation. */ -template -static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings) +template +static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ - - while (str <= last && *str != '\0') { - size_t len = Utf8EncodedCharLen(*str); - char32_t c; - /* If the first byte does not look like the first byte of an encoded - * character, i.e. encoded length is 0, then this byte is definitely bad - * and it should be skipped. - * When the first byte looks like the first byte of an encoded character, - * then the remaining bytes in the string are checked whether the whole - * encoded character can be there. If that is not the case, this byte is - * skipped. - * Finally we attempt to decode the encoded character, which does certain - * extra validations to see whether the correct number of bytes were used - * to encode the character. If that is not the case, the byte is probably - * invalid and it is skipped. We could emit a question mark, but then the - * logic below cannot just copy bytes, it would need to re-encode the - * decoded characters as the length in bytes may have changed. - * - * The goals here is to get as much valid Utf8 encoded characters from the - * source string to the destination string. - * - * Note: a multi-byte encoded termination ('\0') will trigger the encoded - * char length and the decoded length to differ, so it will be ignored as - * invalid character data. If it were to reach the termination, then we - * would also reach the "last" byte of the string and a normal '\0' - * termination will be placed after it. - */ - if (len == 0 || str + len > last + 1 || len != Utf8Decode(&c, str)) { + while (consumer.AnyBytesLeft()) { + auto c = consumer.TryReadUtf8(); + if (!c.has_value()) { /* Maybe the next byte is still a valid character? */ - str++; + consumer.Skip(1); continue; } + if (*c == 0) break; - if ((IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) || (settings.Test(StringValidationSetting::AllowControlCode) && IsSccEncodedCode(c))) { - /* Copy the character back. Even if dst is current the same as str - * (i.e. no characters have been changed) this is quicker than - * moving the pointers ahead by len */ - do { - *dst++ = *str++; - } while (--len != 0); - } else if (settings.Test(StringValidationSetting::AllowNewline) && c == '\n') { - *dst++ = *str++; - } else { - if (settings.Test(StringValidationSetting::AllowNewline) && c == '\r' && str[1] == '\n') { - str += len; - continue; - } - str += len; - if (settings.Test(StringValidationSetting::ReplaceTabCrNlWithSpace) && (c == '\r' || c == '\n' || c == '\t')) { - /* Replace the tab, carriage return or newline with a space. */ - *dst++ = ' '; - } else if (settings.Test(StringValidationSetting::ReplaceWithQuestionMark)) { - /* Replace the undesirable character with a question mark */ - *dst++ = '?'; - } + if ((IsPrintable(*c) && (*c < SCC_SPRITE_START || *c > SCC_SPRITE_END)) || + (settings.Test(StringValidationSetting::AllowControlCode) && IsSccEncodedCode(*c)) || + (settings.Test(StringValidationSetting::AllowNewline) && *c == '\n')) { + builder.PutUtf8(*c); + } else if (settings.Test(StringValidationSetting::AllowNewline) && *c == '\r' && consumer.PeekCharIf('\n')) { + /* Skip \r, if followed by \n */ + /* continue */ + } else if (settings.Test(StringValidationSetting::ReplaceTabCrNlWithSpace) && (*c == '\r' || *c == '\n' || *c == '\t')) { + /* Replace the tab, carriage return or newline with a space. */ + builder.PutChar(' '); + } else if (settings.Test(StringValidationSetting::ReplaceWithQuestionMark)) { + /* Replace the undesirable character with a question mark */ + builder.PutChar('?'); } } @@ -193,9 +158,10 @@ static void StrMakeValid(T &dst, const char *str, const char *last, StringValida */ void StrMakeValidInPlace(char *str, StringValidationSettings settings) { - char *dst = str; - StrMakeValid(dst, str, str + strlen(str), settings); - *dst = '\0'; + InPlaceReplacement inplace(std::span(str, strlen(str))); + StrMakeValid(inplace.builder, inplace.consumer, settings); + /* Add NUL terminator, if we ended up with less bytes than before */ + if (inplace.builder.AnyBytesUnused()) inplace.builder.PutChar('\0'); } /** @@ -209,11 +175,9 @@ void StrMakeValidInPlace(std::string &str, StringValidationSettings settings) { if (str.empty()) return; - char *buf = str.data(); - char *last = buf + str.size() - 1; - char *dst = buf; - StrMakeValid(dst, buf, last, settings); - str.erase(dst - buf, std::string::npos); + InPlaceReplacement inplace(std::span(str.data(), str.size())); + StrMakeValid(inplace.builder, inplace.consumer, settings); + str.erase(inplace.builder.GetBytesWritten(), std::string::npos); } /** @@ -225,16 +189,11 @@ void StrMakeValidInPlace(std::string &str, StringValidationSettings settings) */ std::string StrMakeValid(std::string_view str, StringValidationSettings settings) { - if (str.empty()) return {}; - - auto buf = str.data(); - auto last = buf + str.size() - 1; - - std::ostringstream dst; - std::ostreambuf_iterator dst_iter(dst); - StrMakeValid(dst_iter, buf, last, settings); - - return dst.str(); + std::string result; + StringBuilder builder(result); + StringConsumer consumer(str); + StrMakeValid(builder, consumer, settings); + return result; } /** @@ -248,27 +207,17 @@ std::string StrMakeValid(std::string_view str, StringValidationSettings settings bool StrValid(std::span str) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ - auto it = std::begin(str); - auto last = std::prev(std::end(str)); - - while (it <= last && *it != '\0') { - size_t len = Utf8EncodedCharLen(*it); - /* Encoded length is 0 if the character isn't known. - * The length check is needed to prevent Utf8Decode to read - * over the terminating '\0' if that happens to be placed - * within the encoding of an UTF8 character. */ - if (len == 0 || it + len > last) return false; - - char32_t c; - len = Utf8Decode(&c, &*it); - if (!IsPrintable(c) || (c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) { + StringConsumer consumer(str); + while (consumer.AnyBytesLeft()) { + auto c = consumer.TryReadUtf8(); + if (!c.has_value()) return false; // invalid codepoint + if (*c == 0) return true; // NUL termination + if (!IsPrintable(*c) || (*c >= SCC_SPRITE_START && *c <= SCC_SPRITE_END)) { return false; } - - it += len; } - return *it == '\0'; + return false; // missing NUL termination } /** From b27fd83ff1aea2c1586ed6310cdcfd3e513ebd24 Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 31 Mar 2025 17:30:54 +0200 Subject: [PATCH 035/572] Codechange: Parse translation strings using StringConsumer. --- src/game/game_text.cpp | 2 +- src/strgen/strgen.cpp | 8 +- src/strgen/strgen.h | 5 +- src/strgen/strgen_base.cpp | 174 ++++++++++++++----------------------- src/table/strgen_tables.h | 8 +- 5 files changed, 75 insertions(+), 122 deletions(-) diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 5a7aa0365c..07182ad712 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -267,7 +267,7 @@ static void ExtractStringParams(const StringData &data, StringParamsList ¶ms if (ls != nullptr) { StringParams ¶m = params.emplace_back(); - ParsedCommandStruct pcs = ExtractCommandString(ls->english.c_str(), false); + ParsedCommandStruct pcs = ExtractCommandString(ls->english, false); for (auto it = pcs.consuming_commands.begin(); it != pcs.consuming_commands.end(); it++) { if (*it == nullptr) { diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index c86c0c1029..b54da8a7b9 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -146,10 +146,10 @@ void FileStringReader::HandlePragma(char *str, LanguagePackHeader &lang) lang.newgrflangid = static_cast(langid); } else if (!memcmp(str, "gender ", 7)) { if (this->master) FatalError("Genders are not allowed in the base translation."); - const char *buf = str + 7; + StringConsumer consumer(std::string_view(str + 7)); for (;;) { - auto s = ParseWord(&buf); + auto s = ParseWord(consumer); if (!s.has_value()) break; if (lang.num_genders >= MAX_NUM_GENDERS) FatalError("Too many genders, max {}", MAX_NUM_GENDERS); @@ -158,10 +158,10 @@ void FileStringReader::HandlePragma(char *str, LanguagePackHeader &lang) } } else if (!memcmp(str, "case ", 5)) { if (this->master) FatalError("Cases are not allowed in the base translation."); - const char *buf = str + 5; + StringConsumer consumer(std::string_view(str + 5)); for (;;) { - auto s = ParseWord(&buf); + auto s = ParseWord(consumer); if (!s.has_value()) break; if (lang.num_cases >= MAX_NUM_CASES) FatalError("Too many cases, max {}", MAX_NUM_CASES); diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index 78a6c8def7..18e007f71e 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -10,6 +10,7 @@ #ifndef STRGEN_H #define STRGEN_H +#include "../core/string_consumer.hpp" #include "../language.h" #include "../3rdparty/fmt/format.h" @@ -144,7 +145,7 @@ struct ParsedCommandStruct { }; const CmdStruct *TranslateCmdForCompare(const CmdStruct *a); -ParsedCommandStruct ExtractCommandString(const char *s, bool warnings); +ParsedCommandStruct ExtractCommandString(std::string_view s, bool warnings); void StrgenWarningI(const std::string &msg); void StrgenErrorI(const std::string &msg); @@ -152,7 +153,7 @@ void StrgenErrorI(const std::string &msg); #define StrgenWarning(format_string, ...) StrgenWarningI(fmt::format(FMT_STRING(format_string) __VA_OPT__(,) __VA_ARGS__)) #define StrgenError(format_string, ...) StrgenErrorI(fmt::format(FMT_STRING(format_string) __VA_OPT__(,) __VA_ARGS__)) #define StrgenFatal(format_string, ...) StrgenFatalI(fmt::format(FMT_STRING(format_string) __VA_OPT__(,) __VA_ARGS__)) -std::optional ParseWord(const char **buf); +std::optional ParseWord(StringConsumer &consumer); /** Global state shared between strgen.cpp, game_text.cpp and strgen_base.cpp */ struct StrgenState { diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index 534003ec16..aa831c1945 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -33,7 +33,7 @@ struct ParsedCommandString { std::optional argno; std::optional casei; }; -static ParsedCommandString ParseCommandString(const char **str); +static ParsedCommandString ParseCommandString(StringConsumer &consumer); static size_t TranslateArgumentIdx(size_t arg, size_t offset = 0); /** @@ -139,9 +139,9 @@ uint32_t StringData::Version() const hash = (hash & 1 ? hash >> 1 ^ 0xDEADBEEF : hash >> 1); hash = VersionHashStr(hash, ls->name); - const char *s = ls->english.c_str(); + StringConsumer consumer(ls->english); ParsedCommandString cs; - while ((cs = ParseCommandString(&s)).cmd != nullptr) { + while ((cs = ParseCommandString(consumer)).cmd != nullptr) { if (cs.cmd->flags.Test(CmdFlag::DontCount)) continue; hash ^= (cs.cmd - _cmd_structs) * 0x1234567; @@ -188,62 +188,41 @@ static size_t Utf8Validate(const char *s) return 0; } -void EmitSingleChar(StringBuilder &builder, const char *buf, char32_t value) +void EmitSingleChar(StringBuilder &builder, std::string_view param, char32_t value) { - if (*buf != '\0') StrgenWarning("Ignoring trailing letters in command"); + if (!param.empty()) StrgenWarning("Ignoring trailing letters in command"); builder.PutUtf8(value); } /* The plural specifier looks like * {NUM} {PLURAL passenger passengers} then it picks either passenger/passengers depending on the count in NUM */ -static std::pair, std::optional> ParseRelNum(const char **buf) +static std::pair, std::optional> ParseRelNum(StringConsumer &consumer) { - const char *s = *buf; - char *end; - - while (*s == ' ' || *s == '\t') s++; - size_t v = std::strtoul(s, &end, 0); - if (end == s) return {}; + consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE); + std::optional v = consumer.TryReadIntegerBase(10); std::optional offset; - if (*end == ':') { + if (v.has_value() && consumer.ReadCharIf(':')) { /* Take the Nth within */ - s = end + 1; - offset = std::strtoul(s, &end, 0); - if (end == s) return {}; + offset = consumer.TryReadIntegerBase(10); + if (!offset.has_value()) StrgenFatal("Expected number for substring parameter"); } - *buf = end; return {v, offset}; } /* Parse out the next word, or nullptr */ -std::optional ParseWord(const char **buf) +std::optional ParseWord(StringConsumer &consumer) { - const char *s = *buf; + consumer.SkipUntilCharNotIn(StringConsumer::WHITESPACE_NO_NEWLINE); + if (!consumer.AnyBytesLeft()) return {}; - while (*s == ' ' || *s == '\t') s++; - if (*s == '\0') return {}; - - if (*s == '"') { - const char *begin = ++s; + if (consumer.ReadCharIf('"')) { /* parse until next " or NUL */ - for (;;) { - if (*s == '\0') StrgenFatal("Unterminated quotes"); - if (*s == '"') { - *buf = s + 1; - return std::string_view(begin, s - begin); - } - s++; - } + auto result = consumer.ReadUntilChar('"', StringConsumer::KEEP_SEPARATOR); + if (!consumer.ReadCharIf('"')) StrgenFatal("Unterminated quotes"); + return result; } else { /* proceed until whitespace or NUL */ - const char *begin = s; - for (;;) { - if (*s == '\0' || *s == ' ' || *s == '\t') { - *buf = s; - return std::string_view(begin, s - begin); - } - s++; - } + return consumer.ReadUntilCharIn(StringConsumer::WHITESPACE_NO_NEWLINE); } } @@ -262,10 +241,12 @@ static void EmitWordList(StringBuilder &builder, const std::vector } } -void EmitPlural(StringBuilder &builder, const char *buf, char32_t) +void EmitPlural(StringBuilder &builder, std::string_view param, char32_t) { + StringConsumer consumer(param); + /* Parse out the number, if one exists. Otherwise default to prev arg. */ - auto [argidx, offset] = ParseRelNum(&buf); + auto [argidx, offset] = ParseRelNum(consumer); if (!argidx.has_value()) { if (_cur_argidx == 0) StrgenFatal("Plural choice needs positional reference"); argidx = _cur_argidx - 1; @@ -283,7 +264,7 @@ void EmitPlural(StringBuilder &builder, const char *buf, char32_t) /* Parse each string */ std::vector words; for (;;) { - auto word = ParseWord(&buf); + auto word = ParseWord(consumer); if (!word.has_value()) break; words.emplace_back(*word); } @@ -315,14 +296,14 @@ void EmitPlural(StringBuilder &builder, const char *buf, char32_t) EmitWordList(builder, words); } -void EmitGender(StringBuilder &builder, const char *buf, char32_t) +void EmitGender(StringBuilder &builder, std::string_view param, char32_t) { - if (buf[0] == '=') { - buf++; - + StringConsumer consumer(param); + if (consumer.ReadCharIf('=')) { /* This is a {G=DER} command */ - auto nw = _strgen.lang.GetGenderIndex(buf); - if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", buf); + auto gender = consumer.Read(StringConsumer::npos); + auto nw = _strgen.lang.GetGenderIndex(gender); + if (nw >= MAX_NUM_GENDERS) StrgenFatal("G argument '{}' invalid", gender); /* now nw contains the gender index */ builder.PutUtf8(SCC_GENDER_INDEX); @@ -330,7 +311,7 @@ void EmitGender(StringBuilder &builder, const char *buf, char32_t) } else { /* This is a {G 0 foo bar two} command. * If no relative number exists, default to +0 */ - auto [argidx, offset] = ParseRelNum(&buf); + auto [argidx, offset] = ParseRelNum(consumer); if (!argidx.has_value()) argidx = _cur_argidx; if (!offset.has_value()) offset = 0; @@ -341,7 +322,7 @@ void EmitGender(StringBuilder &builder, const char *buf, char32_t) std::vector words; for (;;) { - auto word = ParseWord(&buf); + auto word = ParseWord(consumer); if (!word.has_value()) break; words.emplace_back(*word); } @@ -370,74 +351,45 @@ static uint8_t ResolveCaseName(std::string_view str) } /* returns cmd == nullptr on eof */ -static ParsedCommandString ParseCommandString(const char **str) +static ParsedCommandString ParseCommandString(StringConsumer &consumer) { ParsedCommandString result; - const char *s = *str; /* Scan to the next command, exit if there's no next command. */ - for (; *s != '{'; s++) { - if (*s == '\0') return {}; - } - s++; // Skip past the { + consumer.SkipUntilChar('{', StringConsumer::KEEP_SEPARATOR); + if (!consumer.ReadCharIf('{')) return {}; - if (*s >= '0' && *s <= '9') { - char *end; - - result.argno = std::strtoul(s, &end, 0); - if (*end != ':') StrgenFatal("missing arg #"); - s = end + 1; + if (auto argno = consumer.TryReadIntegerBase(10); argno.has_value()) { + result.argno = argno; + if (!consumer.ReadCharIf(':')) StrgenFatal("missing arg #"); } /* parse command name */ - const char *start = s; - char c; - do { - c = *s++; - } while (c != '}' && c != ' ' && c != '=' && c != '.' && c != 0); - - std::string_view command(start, s - start - 1); + auto command = consumer.ReadUntilCharIn("} =."); result.cmd = FindCmd(command); if (result.cmd == nullptr) { StrgenError("Undefined command '{}'", command); return {}; } - if (c == '.') { - const char *casep = s; - + /* parse case */ + if (consumer.ReadCharIf('.')) { if (!result.cmd->flags.Test(CmdFlag::Case)) { StrgenFatal("Command '{}' can't have a case", result.cmd->cmd); } - do { - c = *s++; - } while (c != '}' && c != ' ' && c != '\0'); - result.casei = ResolveCaseName(std::string_view(casep, s - casep - 1)); + auto casep = consumer.ReadUntilCharIn("} "); + result.casei = ResolveCaseName(casep); } - if (c == '\0') { - StrgenError("Missing }} from command '{}'", start); + /* parse params */ + result.param = consumer.ReadUntilChar('}', StringConsumer::KEEP_SEPARATOR); + + if (!consumer.ReadCharIf('}')) { + StrgenError("Missing }} from command '{}'", result.cmd->cmd); return {}; } - if (c != '}') { - if (c == '=') s--; - /* copy params */ - start = s; - for (;;) { - c = *s++; - if (c == '}') break; - if (c == '\0') { - StrgenError("Missing }} from command '{}'", start); - return {}; - } - result.param += c; - } - } - - *str = s; - return result; } @@ -453,14 +405,15 @@ StringReader::StringReader(StringData &data, const std::string &file, bool maste { } -ParsedCommandStruct ExtractCommandString(const char *s, bool) +ParsedCommandStruct ExtractCommandString(std::string_view s, bool) { ParsedCommandStruct p; + StringConsumer consumer(s); size_t argidx = 0; for (;;) { /* read until next command from a. */ - auto cs = ParseCommandString(&s); + auto cs = ParseCommandString(consumer); if (cs.cmd == nullptr) break; @@ -499,7 +452,7 @@ const CmdStruct *TranslateCmdForCompare(const CmdStruct *a) return a; } -static bool CheckCommandsMatch(const char *a, const char *b, const char *name) +static bool CheckCommandsMatch(std::string_view a, std::string_view b, std::string_view name) { /* If we're not translating, i.e. we're compiling the base language, * it is pointless to do all these checks as it'll always be correct. @@ -629,7 +582,7 @@ void StringReader::HandleString(char *str) } /* make sure that the commands match */ - if (!CheckCommandsMatch(s, ent->english.c_str(), str)) return; + if (!CheckCommandsMatch(s, ent->english, str)) return; if (casep != nullptr) { ent->translated_cases.emplace_back(ResolveCaseName(casep), s); @@ -735,20 +688,19 @@ static void PutArgidxCommand(StringBuilder &builder) builder.PutUint8(static_cast(TranslateArgumentIdx(_cur_argidx))); } -static std::string PutCommandString(const char *str) +static std::string PutCommandString(std::string_view str) { std::string result; StringBuilder builder(result); + StringConsumer consumer(str); _cur_argidx = 0; - while (*str != '\0') { + for (;;) { /* Process characters as they are until we encounter a { */ - if (*str != '{') { - builder.PutChar(*str++); - continue; - } + builder.Put(consumer.ReadUntilChar('{', StringConsumer::KEEP_SEPARATOR)); + if (!consumer.AnyBytesLeft()) break; - auto cs = ParseCommandString(&str); + auto cs = ParseCommandString(consumer); auto *cmd = cs.cmd; if (cmd == nullptr) break; @@ -772,7 +724,7 @@ static std::string PutCommandString(const char *str) } } - cmd->proc(builder, cs.param.c_str(), cmd->value); + cmd->proc(builder, cs.param, cmd->value); } return result; } @@ -848,7 +800,7 @@ void LanguageWriter::WriteLang(const StringData &data) } /* Extract the strings and stuff from the english command string */ - _cur_pcs = ExtractCommandString(ls->english.c_str(), false); + _cur_pcs = ExtractCommandString(ls->english, false); _translated = !ls->translated_cases.empty() || !ls->translated.empty(); const std::string &cmdp = _translated ? ls->translated : ls->english; @@ -863,7 +815,7 @@ void LanguageWriter::WriteLang(const StringData &data) /* Write each case */ for (const Case &c : ls->translated_cases) { - auto case_str = PutCommandString(c.string.c_str()); + auto case_str = PutCommandString(c.string); builder.PutUint8(c.caseidx); builder.PutUint16LE(static_cast(case_str.size())); builder.Put(case_str); @@ -871,7 +823,7 @@ void LanguageWriter::WriteLang(const StringData &data) } std::string def_str; - if (!cmdp.empty()) def_str = PutCommandString(cmdp.c_str()); + if (!cmdp.empty()) def_str = PutCommandString(cmdp); if (!ls->translated_cases.empty()) { builder.PutUint16LE(static_cast(def_str.size())); } diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index bd57fa795d..2791e1982a 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -17,7 +17,7 @@ enum class CmdFlag : uint8_t { using CmdFlags = EnumBitSet; class StringBuilder; -typedef void (*ParseCmdProc)(StringBuilder &builder, const char *buf, char32_t value); +typedef void (*ParseCmdProc)(StringBuilder &builder, std::string_view param, char32_t value); struct CmdStruct { std::string_view cmd; @@ -28,9 +28,9 @@ struct CmdStruct { CmdFlags flags; }; -extern void EmitSingleChar(StringBuilder &builder, const char *buf, char32_t value); -extern void EmitPlural(StringBuilder &builder, const char *buf, char32_t value); -extern void EmitGender(StringBuilder &builder, const char *buf, char32_t value); +extern void EmitSingleChar(StringBuilder &builder, std::string_view param, char32_t value); +extern void EmitPlural(StringBuilder &builder, std::string_view param, char32_t value); +extern void EmitGender(StringBuilder &builder, std::string_view param, char32_t value); static const CmdStruct _cmd_structs[] = { /* Font size */ From bf8a241f691658257c435df5f40cfb8e282850ba Mon Sep 17 00:00:00 2001 From: frosch Date: Mon, 31 Mar 2025 17:32:05 +0200 Subject: [PATCH 036/572] Codechange: Parse translation files using StringConsumer. --- src/strgen/strgen.cpp | 71 +++++++++--------- src/strgen/strgen.h | 8 +-- src/strgen/strgen_base.cpp | 143 +++++++++++++++---------------------- 3 files changed, 96 insertions(+), 126 deletions(-) diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index b54da8a7b9..a926f0d1f9 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -91,7 +91,7 @@ struct FileStringReader : StringReader { return result; } - void HandlePragma(char *str, LanguagePackHeader &lang) override; + void HandlePragma(std::string_view str, LanguagePackHeader &lang) override; void ParseFile() override { @@ -103,51 +103,50 @@ struct FileStringReader : StringReader { } }; -void FileStringReader::HandlePragma(char *str, LanguagePackHeader &lang) +void FileStringReader::HandlePragma(std::string_view str, LanguagePackHeader &lang) { - if (!memcmp(str, "id ", 3)) { - this->data.next_string_id = std::strtoul(str + 3, nullptr, 0); - } else if (!memcmp(str, "name ", 5)) { - strecpy(lang.name, str + 5); - } else if (!memcmp(str, "ownname ", 8)) { - strecpy(lang.own_name, str + 8); - } else if (!memcmp(str, "isocode ", 8)) { - strecpy(lang.isocode, str + 8); - } else if (!memcmp(str, "textdir ", 8)) { - if (!memcmp(str + 8, "ltr", 3)) { + StringConsumer consumer(str); + auto name = consumer.ReadUntilChar(' ', StringConsumer::SKIP_ALL_SEPARATORS); + if (name == "id") { + this->data.next_string_id = consumer.ReadIntegerBase(0); + } else if (name == "name") { + strecpy(lang.name, consumer.Read(StringConsumer::npos)); + } else if (name == "ownname") { + strecpy(lang.own_name, consumer.Read(StringConsumer::npos)); + } else if (name == "isocode") { + strecpy(lang.isocode, consumer.Read(StringConsumer::npos)); + } else if (name == "textdir") { + auto dir = consumer.Read(StringConsumer::npos); + if (dir == "ltr") { lang.text_dir = TD_LTR; - } else if (!memcmp(str + 8, "rtl", 3)) { + } else if (dir == "rtl") { lang.text_dir = TD_RTL; } else { - FatalError("Invalid textdir {}", str + 8); + FatalError("Invalid textdir {}", dir); } - } else if (!memcmp(str, "digitsep ", 9)) { - str += 9; - strecpy(lang.digit_group_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); - } else if (!memcmp(str, "digitsepcur ", 12)) { - str += 12; - strecpy(lang.digit_group_separator_currency, strcmp(str, "{NBSP}") == 0 ? NBSP : str); - } else if (!memcmp(str, "decimalsep ", 11)) { - str += 11; - strecpy(lang.digit_decimal_separator, strcmp(str, "{NBSP}") == 0 ? NBSP : str); - } else if (!memcmp(str, "winlangid ", 10)) { - const char *buf = str + 10; - long langid = std::strtol(buf, nullptr, 16); + } else if (name == "digitsep") { + auto sep = consumer.Read(StringConsumer::npos); + strecpy(lang.digit_group_separator, sep == "{NBSP}" ? NBSP : sep); + } else if (name == "digitsepcur") { + auto sep = consumer.Read(StringConsumer::npos); + strecpy(lang.digit_group_separator_currency, sep == "{NBSP}" ? NBSP : sep); + } else if (name == "decimalsep") { + auto sep = consumer.Read(StringConsumer::npos); + strecpy(lang.digit_decimal_separator, sep == "{NBSP}" ? NBSP : sep); + } else if (name == "winlangid") { + auto langid = consumer.ReadIntegerBase(0); if (langid > UINT16_MAX || langid < 0) { - FatalError("Invalid winlangid {}", buf); + FatalError("Invalid winlangid {}", langid); } lang.winlangid = static_cast(langid); - } else if (!memcmp(str, "grflangid ", 10)) { - const char *buf = str + 10; - long langid = std::strtol(buf, nullptr, 16); + } else if (name == "grflangid") { + auto langid = consumer.ReadIntegerBase(0); if (langid >= 0x7F || langid < 0) { - FatalError("Invalid grflangid {}", buf); + FatalError("Invalid grflangid {}", langid); } lang.newgrflangid = static_cast(langid); - } else if (!memcmp(str, "gender ", 7)) { + } else if (name == "gender") { if (this->master) FatalError("Genders are not allowed in the base translation."); - StringConsumer consumer(std::string_view(str + 7)); - for (;;) { auto s = ParseWord(consumer); @@ -156,10 +155,8 @@ void FileStringReader::HandlePragma(char *str, LanguagePackHeader &lang) s->copy(lang.genders[lang.num_genders], CASE_GENDER_LEN - 1); lang.num_genders++; } - } else if (!memcmp(str, "case ", 5)) { + } else if (name == "case") { if (this->master) FatalError("Cases are not allowed in the base translation."); - StringConsumer consumer(std::string_view(str + 5)); - for (;;) { auto s = ParseWord(consumer); diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index 18e007f71e..c57b803d28 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -22,7 +22,7 @@ struct Case { uint8_t caseidx; ///< The index of the case. std::string string; ///< The translation of the case. - Case(uint8_t caseidx, const std::string &string); + Case(uint8_t caseidx, std::string_view string); }; /** Information about a single string. */ @@ -34,7 +34,7 @@ struct LangString { size_t line; ///< Line of string in source-file. std::vector translated_cases; ///< Cases of the translation. - LangString(const std::string &name, const std::string &english, size_t index, size_t line); + LangString(std::string_view name, std::string_view english, size_t index, size_t line); void FreeTranslation(); }; @@ -63,7 +63,7 @@ struct StringReader { StringReader(StringData &data, const std::string &file, bool master, bool translation); virtual ~StringReader() = default; - void HandleString(char *str); + void HandleString(std::string_view str); /** * Read a single line from the source of strings. @@ -75,7 +75,7 @@ struct StringReader { * Handle the pragma of the file. * @param str The pragma string to parse. */ - virtual void HandlePragma(char *str, LanguagePackHeader &lang); + virtual void HandlePragma(std::string_view str, LanguagePackHeader &lang); /** * Start parsing the file. diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index aa831c1945..4a08dcafae 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -41,7 +41,7 @@ static size_t TranslateArgumentIdx(size_t arg, size_t offset = 0); * @param caseidx The index of the case. * @param string The translation of the case. */ -Case::Case(uint8_t caseidx, const std::string &string) : +Case::Case(uint8_t caseidx, std::string_view string) : caseidx(caseidx), string(string) { } @@ -53,7 +53,7 @@ Case::Case(uint8_t caseidx, const std::string &string) : * @param index The index in the string table. * @param line The line this string was found on. */ -LangString::LangString(const std::string &name, const std::string &english, size_t index, size_t line) : +LangString::LangString(std::string_view name, std::string_view english, size_t index, size_t line) : name(name), english(english), index(index), line(line) { } @@ -164,30 +164,6 @@ size_t StringData::CountInUse(size_t tab) const return count; } -static size_t Utf8Validate(const char *s) -{ - char32_t c; - - if (!HasBit(s[0], 7)) { - /* 1 byte */ - return 1; - } else if (GB(s[0], 5, 3) == 6 && IsUtf8Part(s[1])) { - /* 2 bytes */ - c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6); - if (c >= 0x80) return 2; - } else if (GB(s[0], 4, 4) == 14 && IsUtf8Part(s[1]) && IsUtf8Part(s[2])) { - /* 3 bytes */ - c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6); - if (c >= 0x800) return 3; - } else if (GB(s[0], 3, 5) == 30 && IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) { - /* 4 bytes */ - c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6); - if (c >= 0x10000 && c <= 0x10FFFF) return 4; - } - - return 0; -} - void EmitSingleChar(StringBuilder &builder, std::string_view param, char32_t value) { if (!param.empty()) StrgenWarning("Ignoring trailing letters in command"); @@ -503,91 +479,92 @@ static bool CheckCommandsMatch(std::string_view a, std::string_view b, std::stri return result; } -void StringReader::HandleString(char *str) +[[nodiscard]] static std::string_view StripTrailingWhitespace(std::string_view str) { - if (*str == '#') { - if (str[1] == '#' && str[2] != '#') this->HandlePragma(str + 2, _strgen.lang); - return; + auto len = str.find_last_not_of("\r\n "); + if (len == std::string_view::npos) return {}; + return str.substr(0, len + 1); +} + +void StringReader::HandleString(std::string_view src) +{ + /* Ignore blank lines */ + if (src.empty()) return; + + StringConsumer consumer(src); + if (consumer.ReadCharIf('#')) { + if (consumer.ReadCharIf('#') && !consumer.ReadCharIf('#')) this->HandlePragma(consumer.Read(StringConsumer::npos), _strgen.lang); + return; // ignore comments } - /* Ignore comments & blank lines */ - if (*str == ';' || *str == ' ' || *str == '\0') return; - - char *s = strchr(str, ':'); - if (s == nullptr) { + /* Read string name */ + std::string_view str_name = StripTrailingWhitespace(consumer.ReadUntilChar(':', StringConsumer::KEEP_SEPARATOR)); + if (!consumer.ReadCharIf(':')) { StrgenError("Line has no ':' delimiter"); return; } - char *t; - /* Trim spaces. - * After this str points to the command name, and s points to the command contents */ - for (t = s; t > str && (t[-1] == ' ' || t[-1] == '\t'); t--) {} - *t = 0; - s++; - - /* Check string is valid UTF-8 */ - const char *tmp; - for (tmp = s; *tmp != '\0';) { - size_t len = Utf8Validate(tmp); - if (len == 0) StrgenFatal("Invalid UTF-8 sequence in '{}'", s); - - char32_t c; - Utf8Decode(&c, tmp); - if (c <= 0x001F || // ASCII control character range - c == 0x200B || // Zero width space - (c >= 0xE000 && c <= 0xF8FF) || // Private range - (c >= 0xFFF0 && c <= 0xFFFF)) { // Specials range - StrgenFatal("Unwanted UTF-8 character U+{:04X} in sequence '{}'", static_cast(c), s); - } - - tmp += len; + /* Read string case */ + std::optional casep; + if (auto index = str_name.find("."); index != std::string_view::npos) { + casep = str_name.substr(index + 1); + str_name = str_name.substr(0, index); } - /* Check if the string has a case.. - * The syntax for cases is IDENTNAME.case */ - char *casep = strchr(str, '.'); - if (casep != nullptr) *casep++ = '\0'; + /* Read string data */ + std::string_view value = consumer.Read(StringConsumer::npos); + + /* Check string is valid UTF-8 */ + for (StringConsumer validation_consumer(value); validation_consumer.AnyBytesLeft(); ) { + auto c = validation_consumer.TryReadUtf8(); + if (!c.has_value()) StrgenFatal("Invalid UTF-8 sequence in '{}'", value); + if (*c <= 0x001F || // ASCII control character range + *c == 0x200B || // Zero width space + (*c >= 0xE000 && *c <= 0xF8FF) || // Private range + (*c >= 0xFFF0 && *c <= 0xFFFF)) { // Specials range + StrgenFatal("Unwanted UTF-8 character U+{:04X} in sequence '{}'", static_cast(*c), value); + } + } /* Check if this string already exists.. */ - LangString *ent = this->data.Find(str); + LangString *ent = this->data.Find(std::string(str_name)); if (this->master) { - if (casep != nullptr) { + if (casep.has_value()) { StrgenError("Cases in the base translation are not supported."); return; } if (ent != nullptr) { - StrgenError("String name '{}' is used multiple times", str); + StrgenError("String name '{}' is used multiple times", str_name); return; } if (this->data.strings[this->data.next_string_id] != nullptr) { - StrgenError("String ID 0x{:X} for '{}' already in use by '{}'", this->data.next_string_id, str, this->data.strings[this->data.next_string_id]->name); + StrgenError("String ID 0x{:X} for '{}' already in use by '{}'", this->data.next_string_id, str_name, this->data.strings[this->data.next_string_id]->name); return; } /* Allocate a new LangString */ - this->data.Add(std::make_unique(str, s, this->data.next_string_id++, _strgen.cur_line)); + this->data.Add(std::make_unique(str_name, value, this->data.next_string_id++, _strgen.cur_line)); } else { if (ent == nullptr) { - StrgenWarning("String name '{}' does not exist in master file", str); + StrgenWarning("String name '{}' does not exist in master file", str_name); return; } - if (!ent->translated.empty() && casep == nullptr) { - StrgenError("String name '{}' is used multiple times", str); + if (!ent->translated.empty() && !casep.has_value()) { + StrgenError("String name '{}' is used multiple times", str_name); return; } /* make sure that the commands match */ - if (!CheckCommandsMatch(s, ent->english, str)) return; + if (!CheckCommandsMatch(value, ent->english, str_name)) return; - if (casep != nullptr) { - ent->translated_cases.emplace_back(ResolveCaseName(casep), s); + if (casep.has_value()) { + ent->translated_cases.emplace_back(ResolveCaseName(*casep), value); } else { - ent->translated = s; + ent->translated = value; /* If the string was translated, use the line from the * translated language so errors in the translated file * are properly referenced to. */ @@ -596,23 +573,20 @@ void StringReader::HandleString(char *str) } } -void StringReader::HandlePragma(char *str, LanguagePackHeader &lang) +void StringReader::HandlePragma(std::string_view str, LanguagePackHeader &lang) { - if (!memcmp(str, "plural ", 7)) { - lang.plural_form = atoi(str + 7); + StringConsumer consumer(str); + auto name = consumer.ReadUntilChar(' ', StringConsumer::SKIP_ALL_SEPARATORS); + if (name == "plural") { + lang.plural_form = consumer.ReadIntegerBase(10); if (lang.plural_form >= lengthof(_plural_forms)) { StrgenFatal("Invalid pluralform {}", lang.plural_form); } } else { - StrgenFatal("unknown pragma '{}'", str); + StrgenFatal("unknown pragma '{}'", name); } } -static void StripTrailingWhitespace(std::string &str) -{ - str.erase(str.find_last_not_of("\r\n ") + 1); -} - void StringReader::ParseFile() { _strgen.warnings = _strgen.errors = 0; @@ -631,8 +605,7 @@ void StringReader::ParseFile() std::optional line = this->ReadLine(); if (!line.has_value()) return; - StripTrailingWhitespace(line.value()); - this->HandleString(line.value().data()); + this->HandleString(StripTrailingWhitespace(line.value())); _strgen.cur_line++; } From 588fedb5db2ba0c160d27fe2a3cc851d2e40e2b5 Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 1 Apr 2025 18:21:34 +0200 Subject: [PATCH 037/572] Codechange: Remove unused Utf8Consume, Utf8Decode, Utf8EncodedCharLen. --- src/string.cpp | 42 ------------------------------------------ src/string_func.h | 38 -------------------------------------- 2 files changed, 80 deletions(-) diff --git a/src/string.cpp b/src/string.cpp index 4032a7f34f..a9d72efab9 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -377,48 +377,6 @@ bool IsValidChar(char32_t key, CharSetFilter afilter) } } - -/* UTF-8 handling routines */ - - -/** - * Decode and consume the next UTF-8 encoded character. - * @param c Buffer to place decoded character. - * @param s Character stream to retrieve character from. - * @return Number of characters in the sequence. - */ -size_t Utf8Decode(char32_t *c, const char *s) -{ - assert(c != nullptr); - - if (!HasBit(s[0], 7)) { - /* Single byte character: 0xxxxxxx */ - *c = s[0]; - return 1; - } else if (GB(s[0], 5, 3) == 6) { - if (IsUtf8Part(s[1])) { - /* Double byte character: 110xxxxx 10xxxxxx */ - *c = GB(s[0], 0, 5) << 6 | GB(s[1], 0, 6); - if (*c >= 0x80) return 2; - } - } else if (GB(s[0], 4, 4) == 14) { - if (IsUtf8Part(s[1]) && IsUtf8Part(s[2])) { - /* Triple byte character: 1110xxxx 10xxxxxx 10xxxxxx */ - *c = GB(s[0], 0, 4) << 12 | GB(s[1], 0, 6) << 6 | GB(s[2], 0, 6); - if (*c >= 0x800) return 3; - } - } else if (GB(s[0], 3, 5) == 30) { - if (IsUtf8Part(s[1]) && IsUtf8Part(s[2]) && IsUtf8Part(s[3])) { - /* 4 byte character: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - *c = GB(s[0], 0, 3) << 18 | GB(s[1], 0, 6) << 12 | GB(s[2], 0, 6) << 6 | GB(s[3], 0, 6); - if (*c >= 0x10000 && *c <= 0x10FFFF) return 4; - } - } - - *c = '?'; - return 1; -} - /** * Test if a unicode character is considered garbage to be skipped. * @param c Character to test. diff --git a/src/string_func.h b/src/string_func.h index 09c8dc18db..c7e8910542 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -72,44 +72,6 @@ inline bool StrEmpty(const char *s) bool IsValidChar(char32_t key, CharSetFilter afilter); -size_t Utf8Decode(char32_t *c, const char *s); -/* std::string_view::iterator might be char *, in which case we do not want this templated variant to be taken. */ -template requires (!std::is_same_v && (std::is_same_v || std::is_same_v)) -inline size_t Utf8Decode(char32_t *c, T &s) { return Utf8Decode(c, &*s); } - -inline char32_t Utf8Consume(const char **s) -{ - char32_t c; - *s += Utf8Decode(&c, *s); - return c; -} - -template -inline char32_t Utf8Consume(Titr &s) -{ - char32_t c; - s += Utf8Decode(&c, &*s); - return c; -} - -/** - * Return the length of an UTF-8 encoded value based on a single char. This - * char should be the first byte of the UTF-8 encoding. If not, or encoding - * is invalid, return value is 0 - * @param c char to query length of - * @return requested size - */ -inline int8_t Utf8EncodedCharLen(char c) -{ - if (GB(c, 3, 5) == 0x1E) return 4; - if (GB(c, 4, 4) == 0x0E) return 3; - if (GB(c, 5, 3) == 0x06) return 2; - if (GB(c, 7, 1) == 0x00) return 1; - - /* Invalid UTF8 start encoding */ - return 0; -} - /* Check if the given character is part of a UTF8 sequence */ inline bool IsUtf8Part(char c) From d2c9828b4c4259709a7138ad10286ccb8fdacc32 Mon Sep 17 00:00:00 2001 From: frosch Date: Wed, 2 Apr 2025 10:04:46 +0200 Subject: [PATCH 038/572] Codechange: Move IsUtf8Part to only file using it. --- src/core/utf8.hpp | 8 +++++++- src/string_func.h | 7 ------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/utf8.hpp b/src/core/utf8.hpp index db1354ef24..26e6305ba9 100644 --- a/src/core/utf8.hpp +++ b/src/core/utf8.hpp @@ -13,11 +13,17 @@ #define UTF8_HPP #include -#include "../string_func.h" +#include "bitmath_func.hpp" [[nodiscard]] std::pair EncodeUtf8(char32_t c); [[nodiscard]] std::pair DecodeUtf8(std::string_view buf); +/* Check if the given character is part of a UTF8 sequence */ +inline bool IsUtf8Part(char c) +{ + return GB(c, 6, 2) == 2; +} + /** * Constant span of UTF-8 encoded data. */ diff --git a/src/string_func.h b/src/string_func.h index c7e8910542..9fa5636204 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -72,13 +72,6 @@ inline bool StrEmpty(const char *s) bool IsValidChar(char32_t key, CharSetFilter afilter); - -/* Check if the given character is part of a UTF8 sequence */ -inline bool IsUtf8Part(char c) -{ - return GB(c, 6, 2) == 2; -} - size_t Utf8StringLength(std::string_view str); /** From fc20ce301a39f4a2d4a1e62b50cd2c8b8728be49 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Mon, 14 Apr 2025 20:50:02 +0200 Subject: [PATCH 039/572] Doc: Missing changelog entry for 15.0-beta2. (#14001) --- changelog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.md b/changelog.md index e70a8b5069..5dbd8bf0a4 100644 --- a/changelog.md +++ b/changelog.md @@ -20,6 +20,7 @@ - Add: Ukrainian Hryvnia currency (#12877) - Add: Convert 32bpp-only sprites to 8bpp when needed (#11602) - Change: [Script] Start GS (but don't run it) when generating world in scenario editor (#13961) +- Change: [Script] Add vehicle owner to crash event (#13878) - Change: Make tree placement at world generation look more organic (#13515) - Change: [MacOS] Put the icon in a rounded rectangle (#13446) - Change: [Script] GetWaypointID to return the StationID of any waypoint (#13407) From 5008568dfc56571f2badc4b677aa30f4f8e255dc Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 14 Apr 2025 23:55:40 +0100 Subject: [PATCH 040/572] Codechange: Rename CenterBounds to CentreBounds and move to geometry header. (#14002) --- src/aircraft_gui.cpp | 2 +- src/airport_gui.cpp | 2 +- src/build_vehicle_gui.cpp | 2 +- src/company_gui.cpp | 6 +++--- src/core/geometry_type.hpp | 11 +++++++++++ src/dropdown_common_type.h | 4 ++-- src/genworld_gui.cpp | 2 +- src/gfx.cpp | 4 ++-- src/gfx_func.h | 12 ------------ src/graph_gui.cpp | 10 +++++----- src/industry_gui.cpp | 2 +- src/linkgraph/linkgraph_gui.cpp | 6 +++--- src/misc_gui.cpp | 6 +++--- src/network/network_content_gui.cpp | 2 +- src/network/network_gui.cpp | 8 ++++---- src/newgrf_debug_gui.cpp | 2 +- src/newgrf_gui.cpp | 4 ++-- src/news_gui.cpp | 2 +- src/rail_gui.cpp | 2 +- src/roadveh_gui.cpp | 2 +- src/script/script_gui.cpp | 2 +- src/ship_gui.cpp | 2 +- src/smallmap_gui.cpp | 4 ++-- src/statusbar_gui.cpp | 4 ++-- src/subsidy_gui.cpp | 2 +- src/train_gui.cpp | 2 +- src/tree_gui.cpp | 2 +- src/vehicle_gui.cpp | 8 ++++---- src/widget.cpp | 10 +++++----- 29 files changed, 63 insertions(+), 64 deletions(-) diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index 1ba0a311d5..5b7d67582b 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -82,7 +82,7 @@ void DrawAircraftImage(const Vehicle *v, const Rect &r, VehicleID selection, Eng int x_offs = UnScaleGUI(rect.left); int x = rtl ? r.right - width - x_offs : r.left - x_offs; /* This magic -1 offset is related to the sprite_y_offsets in build_vehicle_gui.cpp */ - int y = ScaleSpriteTrad(-1) + CenterBounds(r.top, r.bottom, 0); + int y = ScaleSpriteTrad(-1) + CentreBounds(r.top, r.bottom, 0); bool helicopter = v->subtype == AIR_HELICOPTER; int heli_offs = 0; diff --git a/src/airport_gui.cpp b/src/airport_gui.cpp index 6954317887..5b2464e975 100644 --- a/src/airport_gui.cpp +++ b/src/airport_gui.cpp @@ -401,7 +401,7 @@ public: case WID_AP_AIRPORT_SPRITE: if (this->preview_sprite != 0) { Dimension d = GetSpriteSize(this->preview_sprite); - DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), CenterBounds(r.left, r.right, d.width), CenterBounds(r.top, r.bottom, d.height)); + DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), CentreBounds(r.left, r.right, d.width), CentreBounds(r.top, r.bottom, d.height)); } break; diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index ad0f55141e..e2a5c7cdf0 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -995,7 +995,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li if (lvl < item.indent) tx += level_width; } /* Draw our node in the tree. */ - int ycentre = CenterBounds(textr.top, textr.bottom, WidgetDimensions::scaled.fullbevel.top); + int ycentre = CentreBounds(textr.top, textr.bottom, WidgetDimensions::scaled.fullbevel.top); if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ir.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top); GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top); } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 0c171330e2..01544dc527 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -1127,8 +1127,8 @@ void DrawCompanyManagerFace(CompanyManagerFace cmf, Colours colour, const Rect & /* Determine offset from centre of drawing rect. */ Dimension d = GetSpriteSize(SPR_GRADIENT); - int x = CenterBounds(r.left, r.right, d.width); - int y = CenterBounds(r.top, r.bottom, d.height); + int x = CentreBounds(r.left, r.right, d.width); + int y = CentreBounds(r.top, r.bottom, d.height); bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0; bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0; @@ -2373,7 +2373,7 @@ struct CompanyWindow : Window Point offset; Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset); d.height -= offset.y; - DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, CenterBounds(r.top, r.bottom, d.height) - offset.y); + DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, CentreBounds(r.top, r.bottom, d.height) - offset.y); break; } diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp index 9149ab2c3c..ddb3398ade 100644 --- a/src/core/geometry_type.hpp +++ b/src/core/geometry_type.hpp @@ -16,6 +16,17 @@ # define Point OTTD_Point #endif /* __APPLE__ */ +/** + * Determine where to position a centred object. + * @param min The top or left coordinate. + * @param max The bottom or right coordinate. + * @param size The height or width of the object to draw. + * @return Offset of where to position the object. + */ +inline int CentreBounds(int min, int max, int size) +{ + return (min + max - size + 1) / 2; +} /** Coordinates of a point in 2D */ struct Point { diff --git a/src/dropdown_common_type.h b/src/dropdown_common_type.h index 5193348464..04cb7665f6 100644 --- a/src/dropdown_common_type.h +++ b/src/dropdown_common_type.h @@ -36,7 +36,7 @@ public: uint8_t c1 = GetColourGradient(bg_colour, SHADE_DARK); uint8_t c2 = GetColourGradient(bg_colour, SHADE_LIGHTEST); - int mid = CenterBounds(full.top, full.bottom, 0); + int mid = CentreBounds(full.top, full.bottom, 0); GfxFillRect(full.left, mid - WidgetDimensions::scaled.bevel.bottom, full.right, mid - 1, c1); GfxFillRect(full.left, mid, full.right, mid + WidgetDimensions::scaled.bevel.top - 1, c2); } @@ -126,7 +126,7 @@ public: { bool rtl = TEnd ^ (_current_text_dir == TD_RTL); Rect ir = r.WithWidth(this->dbounds.width, rtl); - DrawSprite(this->sprite, this->palette, CenterBounds(ir.left, ir.right, this->dsprite.width), CenterBounds(r.top, r.bottom, this->dsprite.height)); + DrawSprite(this->sprite, this->palette, CentreBounds(ir.left, ir.right, this->dsprite.width), CentreBounds(r.top, r.bottom, this->dsprite.height)); this->TBase::Draw(full, r.Indent(this->dbounds.width + WidgetDimensions::scaled.hsep_normal, rtl), sel, bg_colour); } }; diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 52218c2380..a646638cff 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -1393,7 +1393,7 @@ struct GenerateProgressWindow : public Window { DrawFrameRect(r, COLOUR_GREY, {FrameFlag::BorderOnly, FrameFlag::Lowered}); Rect br = r.Shrink(WidgetDimensions::scaled.bevel); DrawFrameRect(br.WithWidth(br.Width() * GenWorldStatus::percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {}); - DrawString(br.left, br.right, CenterBounds(br.top, br.bottom, GetCharacterHeight(FS_NORMAL)), + DrawString(br.left, br.right, CentreBounds(br.top, br.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_GENERATION_PROGRESS, GenWorldStatus::percent), TC_FROMSTRING, SA_HOR_CENTER); break; } diff --git a/src/gfx.cpp b/src/gfx.cpp index f116343b00..13d9776d12 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -907,8 +907,8 @@ void DrawCharCentered(char32_t c, const Rect &r, TextColour colour) { SetColourRemap(colour); GfxMainBlitter(GetGlyph(FS_NORMAL, c), - CenterBounds(r.left, r.right, GetCharacterWidth(FS_NORMAL, c)), - CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), + CentreBounds(r.left, r.right, GetCharacterWidth(FS_NORMAL, c)), + CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), BlitterMode::ColourRemap); } diff --git a/src/gfx_func.h b/src/gfx_func.h index d7febfdc74..72654a7b8c 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -156,18 +156,6 @@ inline bool FillDrawPixelInfo(DrawPixelInfo *n, const Rect &r) return FillDrawPixelInfo(n, r.left, r.top, r.Width(), r.Height()); } -/** - * Determine where to draw a centred object inside a widget. - * @param min The top or left coordinate. - * @param max The bottom or right coordinate. - * @param size The height or width of the object to draw. - * @return Offset of where to start drawing the object. - */ -inline int CenterBounds(int min, int max, int size) -{ - return (min + max - size + 1) / 2; -} - /* window.cpp */ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom); diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 7cb36d9dbe..011e1d41c2 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -73,10 +73,10 @@ struct GraphLegendWindow : Window { const Rect ir = r.Shrink(WidgetDimensions::scaled.framerect); Dimension d = GetSpriteSize(SPR_COMPANY_ICON); - DrawCompanyIcon(cid, rtl ? ir.right - d.width : ir.left, CenterBounds(ir.top, ir.bottom, d.height)); + DrawCompanyIcon(cid, rtl ? ir.right - d.width : ir.left, CentreBounds(ir.top, ir.bottom, d.height)); const Rect tr = ir.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl); - DrawString(tr.left, tr.right, CenterBounds(tr.top, tr.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_COMPANY_NAME_COMPANY_NUM, cid, cid), _legend_excluded_companies.Test(cid) ? TC_BLACK : TC_WHITE); + DrawString(tr.left, tr.right, CentreBounds(tr.top, tr.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_COMPANY_NAME_COMPANY_NUM, cid, cid), _legend_excluded_companies.Test(cid) ? TC_BLACK : TC_WHITE); } void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override @@ -1385,7 +1385,7 @@ struct PerformanceRatingDetailWindow : Window { if (this->IsWidgetDisabled(widget)) return; CompanyID cid = (CompanyID)(widget - WID_PRD_COMPANY_FIRST); Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); - DrawCompanyIcon(cid, CenterBounds(r.left, r.right, sprite_size.width), CenterBounds(r.top, r.bottom, sprite_size.height)); + DrawCompanyIcon(cid, CentreBounds(r.left, r.right, sprite_size.width), CentreBounds(r.top, r.bottom, sprite_size.height)); return; } @@ -1408,8 +1408,8 @@ struct PerformanceRatingDetailWindow : Window { needed = SCORE_MAX; } - uint bar_top = CenterBounds(r.top, r.bottom, this->bar_height); - uint text_top = CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)); + uint bar_top = CentreBounds(r.top, r.bottom, this->bar_height); + uint text_top = CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)); DrawString(this->score_info_left, this->score_info_right, text_top, STR_PERFORMANCE_DETAIL_VEHICLES + score_type); diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index bbe73b9327..6beb9bdaf9 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -864,7 +864,7 @@ public: SpriteID icon = CargoSpec::Get(cargo_type)->GetCargoIcon(); Dimension d = GetSpriteSize(icon); Rect ir = r.WithWidth(this->cargo_icon_size.width, rtl).WithHeight(GetCharacterHeight(FS_NORMAL)); - DrawSprite(icon, PAL_NONE, CenterBounds(ir.left, ir.right, d.width), CenterBounds(ir.top, ir.bottom, this->cargo_icon_size.height)); + DrawSprite(icon, PAL_NONE, CentreBounds(ir.left, ir.right, d.width), CentreBounds(ir.top, ir.bottom, this->cargo_icon_size.height)); } std::string GetAcceptedCargoString(const Industry::AcceptedCargo &ac, const CargoSuffix &suffix) const diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index 61c25550c0..57ab1dfaf0 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -604,7 +604,7 @@ void LinkGraphLegendWindow::DrawWidget(const Rect &r, WidgetID widget) const if (this->IsWidgetDisabled(widget)) return; CompanyID cid = (CompanyID)(widget - WID_LGL_COMPANY_FIRST); Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); - DrawCompanyIcon(cid, CenterBounds(br.left, br.right, sprite_size.width), CenterBounds(br.top, br.bottom, sprite_size.height)); + DrawCompanyIcon(cid, CentreBounds(br.left, br.right, sprite_size.width), CentreBounds(br.top, br.bottom, sprite_size.height)); } if (IsInsideMM(widget, WID_LGL_SATURATION_FIRST, WID_LGL_SATURATION_LAST + 1)) { uint8_t colour = LinkGraphOverlay::LINK_COLOURS[_settings_client.gui.linkgraph_colours][widget - WID_LGL_SATURATION_FIRST]; @@ -618,13 +618,13 @@ void LinkGraphLegendWindow::DrawWidget(const Rect &r, WidgetID widget) const str = STR_LINKGRAPH_LEGEND_SATURATED; } if (str != STR_NULL) { - DrawString(br.left, br.right, CenterBounds(br.top, br.bottom, GetCharacterHeight(FS_SMALL)), str, GetContrastColour(colour) | TC_FORCED, SA_HOR_CENTER, false, FS_SMALL); + DrawString(br.left, br.right, CentreBounds(br.top, br.bottom, GetCharacterHeight(FS_SMALL)), str, GetContrastColour(colour) | TC_FORCED, SA_HOR_CENTER, false, FS_SMALL); } } if (IsInsideMM(widget, WID_LGL_CARGO_FIRST, WID_LGL_CARGO_LAST + 1)) { const CargoSpec *cargo = _sorted_cargo_specs[widget - WID_LGL_CARGO_FIRST]; GfxFillRect(br, cargo->legend_colour); - DrawString(br.left, br.right, CenterBounds(br.top, br.bottom, GetCharacterHeight(FS_SMALL)), cargo->abbrev, GetContrastColour(cargo->legend_colour, 73), SA_HOR_CENTER, false, FS_SMALL); + DrawString(br.left, br.right, CentreBounds(br.top, br.bottom, GetCharacterHeight(FS_SMALL)), cargo->abbrev, GetContrastColour(cargo->legend_colour, 73), SA_HOR_CENTER, false, FS_SMALL); } } diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index bae49d57f3..eefdf37a29 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -767,14 +767,14 @@ void QueryString::DrawEditBox(const Window *w, WidgetID wid) const /* If we have a marked area, draw a background highlight. */ if (tb->marklength != 0) GfxFillRect(fr.left + tb->markxoffs, fr.top, fr.left + tb->markxoffs + tb->marklength - 1, fr.bottom, PC_GREY); - DrawString(fr.left, fr.right, CenterBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), tb->GetText(), TC_YELLOW); + DrawString(fr.left, fr.right, CentreBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), tb->GetText(), TC_YELLOW); bool focussed = w->IsWidgetGloballyFocused(wid) || IsOSKOpenedFor(w, wid); if (focussed && tb->caret) { int caret_width = GetCaretWidth(); if (rtl) { - DrawString(fr.right - tb->pixels + tb->caretxoffs - caret_width, fr.right - tb->pixels + tb->caretxoffs, CenterBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), "_", TC_WHITE); + DrawString(fr.right - tb->pixels + tb->caretxoffs - caret_width, fr.right - tb->pixels + tb->caretxoffs, CentreBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), "_", TC_WHITE); } else { - DrawString(fr.left + tb->caretxoffs, fr.left + tb->caretxoffs + caret_width, CenterBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), "_", TC_WHITE); + DrawString(fr.left + tb->caretxoffs, fr.left + tb->caretxoffs + caret_width, CentreBounds(fr.top, fr.bottom, GetCharacterHeight(FS_NORMAL)), "_", TC_WHITE); } } } diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index de77cc6dd7..5974f0f1bb 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -145,7 +145,7 @@ void BaseNetworkContentDownloadStatusWindow::DrawWidget(const Rect &r, WidgetID DrawFrameRect(r, COLOUR_GREY, {FrameFlag::BorderOnly, FrameFlag::Lowered}); Rect ir = r.Shrink(WidgetDimensions::scaled.bevel); DrawFrameRect(ir.WithWidth((uint64_t)ir.Width() * this->downloaded_bytes / this->total_bytes, _current_text_dir == TD_RTL), COLOUR_MAUVE, {}); - DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), + DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_CONTENT_DOWNLOAD_PROGRESS_SIZE, this->downloaded_bytes, this->total_bytes, this->downloaded_bytes * 100LL / this->total_bytes), TC_FROMSTRING, SA_HOR_CENTER); break; diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index cb5c5cb4a2..a5da3540d1 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1900,10 +1900,10 @@ public: void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const { bool rtl = _current_text_dir == TD_RTL; - int text_y_offset = CenterBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL)); + int text_y_offset = CentreBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL)); Dimension d = GetSpriteSize(SPR_COMPANY_ICON); - int offset = CenterBounds(0, this->line_height, d.height); + int offset = CentreBounds(0, this->line_height, d.height); uint line_start = this->vscroll->GetPosition(); uint line_end = line_start + this->vscroll->GetCapacity(); @@ -1961,7 +1961,7 @@ public: if (player_icon != 0) { Dimension d2 = GetSpriteSize(player_icon); - int offset_y = CenterBounds(0, this->line_height, d2.height); + int offset_y = CentreBounds(0, this->line_height, d2.height); DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? tr.right - d2.width : tr.left, y + offset_y); tr = tr.Indent(d2.width + WidgetDimensions::scaled.hsep_normal, rtl); } @@ -2075,7 +2075,7 @@ struct NetworkJoinStatusWindow : Window { break; } DrawFrameRect(ir.WithWidth(ir.Width() * progress / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {}); - DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), STR_NETWORK_CONNECTING_1 + _network_join_status, TC_FROMSTRING, SA_HOR_CENTER); break; } diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index 40fabd2e0c..1f83160969 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -412,7 +412,7 @@ struct NewGRFInspectWindow : Window { GrfSpecFeature f = GetFeatureNum(this->window_number); int h = GetVehicleImageCellSize((VehicleType)(VEH_TRAIN + (f - GSF_TRAINS)), EIT_IN_DEPOT).height; - int y = CenterBounds(br.top, br.bottom, h); + int y = CentreBounds(br.top, br.bottom, h); DrawVehicleImage(v->First(), br, VehicleID::Invalid(), EIT_IN_DETAILS, skip); /* Highlight the articulated part (this is different to the whole-vehicle highlighting of DrawVehicleImage */ diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 2b145522d3..6c206a93fe 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -908,7 +908,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { case WID_NS_NEWGRF_INFO_TITLE: { /* Create the nice grayish rectangle at the details top. */ GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), PC_DARK_BLUE); - DrawString(r.left, r.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER); + DrawString(r.left, r.right, CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER); break; } @@ -2194,7 +2194,7 @@ struct ScanProgressWindow : public Window { Rect ir = r.Shrink(WidgetDimensions::scaled.bevel); uint percent = scanned * 100 / std::max(1U, _settings_client.gui.last_newgrf_count); DrawFrameRect(ir.WithWidth(ir.Width() * percent / 100, _current_text_dir == TD_RTL), COLOUR_MAUVE, {}); - DrawString(ir.left, ir.right, CenterBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_GENERATION_PROGRESS, percent), TC_FROMSTRING, SA_HOR_CENTER); + DrawString(ir.left, ir.right, CentreBounds(ir.top, ir.bottom, GetCharacterHeight(FS_NORMAL)), GetString(STR_GENERATION_PROGRESS, percent), TC_FROMSTRING, SA_HOR_CENTER); break; } diff --git a/src/news_gui.cpp b/src/news_gui.cpp index f9ca7a3601..8445579b74 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -550,7 +550,7 @@ struct NewsWindow : Window { case WID_N_VEH_SPR: { assert(std::holds_alternative(ni->ref1)); EngineID engine = std::get(this->ni->ref1); - DrawVehicleEngine(r.left, r.right, CenterBounds(r.left, r.right, 0), CenterBounds(r.top, r.bottom, 0), engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW); + DrawVehicleEngine(r.left, r.right, CentreBounds(r.left, r.right, 0), CentreBounds(r.top, r.bottom, 0), engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW); GfxFillRect(r, PALETTE_NEWSPAPER, FILLRECT_RECOLOUR); break; } diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 09c551a344..08d8b38d7f 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1465,7 +1465,7 @@ private: Point offset; Dimension sprite_size = GetSpriteSize(image, &offset); Rect ir = r.Shrink(WidgetDimensions::scaled.imgbtn); - int x = CenterBounds(ir.left, ir.right, sprite_size.width - offset.x) - offset.x; // centered + int x = CentreBounds(ir.left, ir.right, sprite_size.width - offset.x) - offset.x; // centered int y = ir.top - sig_sprite_bottom_offset + (ir.Height() + sig_sprite_size.height) / 2; // aligned to bottom diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index 4a98d58dfa..b7fedf2495 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -152,6 +152,6 @@ void DrawRoadVehImage(const Vehicle *v, const Rect &r, VehicleID selection, Engi if (v->index == selection) { int height = ScaleSpriteTrad(12); Rect hr = {(rtl ? px : 0), 0, (rtl ? max_width : px) - 1, height - 1}; - DrawFrameRect(hr.Translate(r.left, CenterBounds(r.top, r.bottom, height)).Expand(WidgetDimensions::scaled.bevel), COLOUR_WHITE, FrameFlag::BorderOnly); + DrawFrameRect(hr.Translate(r.left, CentreBounds(r.top, r.bottom, height)).Expand(WidgetDimensions::scaled.bevel), COLOUR_WHITE, FrameFlag::BorderOnly); } } diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp index 28c9f2f379..d5353dfa82 100644 --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -857,7 +857,7 @@ struct ScriptDebugWindow : public Window { if (this->IsWidgetDisabled(widget)) return; CompanyID cid = (CompanyID)(widget - start); Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); - DrawCompanyIcon(cid, CenterBounds(r.left, r.right, sprite_size.width), CenterBounds(r.top, r.bottom, sprite_size.height)); + DrawCompanyIcon(cid, CentreBounds(r.left, r.right, sprite_size.width), CentreBounds(r.top, r.bottom, sprite_size.height)); } /** diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index 7edccb0be6..7bdedb82dc 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -41,7 +41,7 @@ void DrawShipImage(const Vehicle *v, const Rect &r, VehicleID selection, EngineI int x_offs = UnScaleGUI(rect.left); int x = rtl ? r.right - width - x_offs : r.left - x_offs; /* This magic -1 offset is related to the sprite_y_offsets in build_vehicle_gui.cpp */ - int y = ScaleSpriteTrad(-1) + CenterBounds(r.top, r.bottom, 0); + int y = ScaleSpriteTrad(-1) + CentreBounds(r.top, r.bottom, 0); seq.Draw(x, y, GetVehiclePalette(v), false); if (v->cargo_cap > 0) DrawCargoIconOverlay(x, y, v->cargo_type); diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index e73183481e..eb4521be95 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1495,8 +1495,8 @@ public: */ Point GetStationMiddle(const Station *st) const { - int x = CenterBounds(st->rect.left, st->rect.right, 0); - int y = CenterBounds(st->rect.top, st->rect.bottom, 0); + int x = CentreBounds(st->rect.left, st->rect.right, 0); + int y = CentreBounds(st->rect.top, st->rect.bottom, 0); Point ret = this->RemapTile(x, y); /* Same magic 3 as in DrawVehicles; that's where I got it from. diff --git a/src/statusbar_gui.cpp b/src/statusbar_gui.cpp index 7944176499..7dbde04b44 100644 --- a/src/statusbar_gui.cpp +++ b/src/statusbar_gui.cpp @@ -106,7 +106,7 @@ struct StatusBarWindow : Window { void DrawWidget(const Rect &r, WidgetID widget) const override { Rect tr = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero); - tr.top = CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)); + tr.top = CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)); switch (widget) { case WID_S_LEFT: /* Draw the date */ @@ -155,7 +155,7 @@ struct StatusBarWindow : Window { if (!this->reminder_timeout.HasFired()) { Dimension icon_size = GetSpriteSize(SPR_UNREAD_NEWS); - DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, tr.right - icon_size.width, CenterBounds(r.top, r.bottom, icon_size.height)); + DrawSprite(SPR_UNREAD_NEWS, PAL_NONE, tr.right - icon_size.width, CentreBounds(r.top, r.bottom, icon_size.height)); } break; } diff --git a/src/subsidy_gui.cpp b/src/subsidy_gui.cpp index 520063d198..5f065166ef 100644 --- a/src/subsidy_gui.cpp +++ b/src/subsidy_gui.cpp @@ -150,7 +150,7 @@ struct SubsidyListWindow : Window { SpriteID icon = CargoSpec::Get(cargo_type)->GetCargoIcon(); Dimension d = GetSpriteSize(icon); Rect ir = r.WithWidth(this->cargo_icon_size.width, rtl).WithHeight(GetCharacterHeight(FS_NORMAL)); - DrawSprite(icon, PAL_NONE, CenterBounds(ir.left, ir.right, d.width), CenterBounds(ir.top, ir.bottom, this->cargo_icon_size.height) + y_offset); + DrawSprite(icon, PAL_NONE, CentreBounds(ir.left, ir.right, d.width), CentreBounds(ir.top, ir.bottom, this->cargo_icon_size.height) + y_offset); } void DrawWidget(const Rect &r, WidgetID widget) const override diff --git a/src/train_gui.cpp b/src/train_gui.cpp index a0c5804e56..4a96056f58 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -167,7 +167,7 @@ void DrawTrainImage(const Train *v, const Rect &r, VehicleID selection, EngineIm * the next engine after the highlight could overlap it. */ int height = ScaleSpriteTrad(12); Rect hr = {highlight_l, 0, highlight_r, height - 1}; - DrawFrameRect(hr.Translate(r.left, CenterBounds(r.top, r.bottom, height)).Expand(WidgetDimensions::scaled.bevel), COLOUR_WHITE, FrameFlag::BorderOnly); + DrawFrameRect(hr.Translate(r.left, CentreBounds(r.top, r.bottom, height)).Expand(WidgetDimensions::scaled.bevel), COLOUR_WHITE, FrameFlag::BorderOnly); } } diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp index e177146cd9..109fd08e18 100644 --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -167,7 +167,7 @@ public: if (widget >= WID_BT_TYPE_BUTTON_FIRST) { const int index = widget - WID_BT_TYPE_BUTTON_FIRST; /* Trees "grow" in the centre on the bottom line of the buttons */ - DrawSprite(tree_sprites[index].sprite, tree_sprites[index].pal, CenterBounds(r.left, r.right, 0), r.bottom - ScaleGUITrad(BUTTON_BOTTOM_OFFSET)); + DrawSprite(tree_sprites[index].sprite, tree_sprites[index].pal, CentreBounds(r.left, r.right, 0), r.bottom - ScaleGUITrad(BUTTON_BOTTOM_OFFSET)); } } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 83553cad0f..d78ba5723b 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1058,7 +1058,7 @@ struct RefitWindow : public Window { /* Determine top & bottom position of the highlight.*/ const int height = ScaleSpriteTrad(12); - const int highlight_top = CenterBounds(r.top, r.bottom, height); + const int highlight_top = CentreBounds(r.top, r.bottom, height); const int highlight_bottom = highlight_top + height - 1; for (Train *u = Train::From(v); u != nullptr; u = u->Next()) { @@ -2667,14 +2667,14 @@ struct VehicleDetailsWindow : Window { /* We're using wallclock units. Show minutes since last serviced. */ if (TimerGameEconomy::UsingWallclockUnits()) { int minutes_since_serviced = (TimerGameEconomy::date - v->date_of_last_service).base() / EconomyTime::DAYS_IN_ECONOMY_MONTH; - DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), + DrawString(tr.left, tr.right, CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), GetString(v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_MINUTES, v->GetServiceInterval(), STR_VEHICLE_DETAILS_LAST_SERVICE_MINUTES_AGO, minutes_since_serviced)); break; } /* We're using calendar dates. Show the date of last service. */ - DrawString(tr.left, tr.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), + DrawString(tr.left, tr.right, CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), GetString(v->ServiceIntervalIsPercent() ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS, v->GetServiceInterval(), STR_VEHICLE_DETAILS_LAST_SERVICE_DATE, v->date_of_last_service)); break; @@ -3212,7 +3212,7 @@ public: TextColour text_colour = TC_FROMSTRING; std::string str = GetVehicleStatusString(v, text_colour); - DrawString(tr.left, tr.right, CenterBounds(tr.top, tr.bottom, GetCharacterHeight(FS_NORMAL)), str, text_colour, SA_HOR_CENTER); + DrawString(tr.left, tr.right, CentreBounds(tr.top, tr.bottom, GetCharacterHeight(FS_NORMAL)), str, text_colour, SA_HOR_CENTER); } void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override diff --git a/src/widget.cpp b/src/widget.cpp index 2609362796..cde3eba7bf 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -123,13 +123,13 @@ static inline Point GetAlignedPosition(const Rect &r, const Dimension &d, String if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT; switch (align & SA_HOR_MASK) { case SA_LEFT: p.x = r.left; break; - case SA_HOR_CENTER: p.x = CenterBounds(r.left, r.right, d.width); break; + case SA_HOR_CENTER: p.x = CentreBounds(r.left, r.right, d.width); break; case SA_RIGHT: p.x = r.right + 1 - d.width; break; default: NOT_REACHED(); } switch (align & SA_VERT_MASK) { case SA_TOP: p.y = r.top; break; - case SA_VERT_CENTER: p.y = CenterBounds(r.top, r.bottom, d.height); break; + case SA_VERT_CENTER: p.y = CentreBounds(r.top, r.bottom, d.height); break; case SA_BOTTOM: p.y = r.bottom + 1 - d.height; break; default: NOT_REACHED(); } @@ -676,7 +676,7 @@ static inline void DrawCloseBox(const Rect &r, Colours colour) d.width -= offset.x; d.height -= offset.y; int s = ScaleSpriteTrad(1); /* Offset to account for shadow of SPR_CLOSEBOX */ - DrawSprite(SPR_CLOSEBOX, (colour != COLOUR_WHITE ? TC_BLACK : TC_SILVER) | (1U << PALETTE_TEXT_RECOLOUR), CenterBounds(r.left, r.right, d.width - s) - offset.x, CenterBounds(r.top, r.bottom, d.height - s) - offset.y); + DrawSprite(SPR_CLOSEBOX, (colour != COLOUR_WHITE ? TC_BLACK : TC_SILVER) | (1U << PALETTE_TEXT_RECOLOUR), CentreBounds(r.left, r.right, d.width - s) - offset.x, CentreBounds(r.top, r.bottom, d.height - s) - offset.y); } /** @@ -727,13 +727,13 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FrameFlag::Lowered : FrameFlags{}); DrawImageButtons(r.WithWidth(dd_width, true), WWT_DROPDOWN, colour, clicked_dropdown, SPR_ARROW_DOWN, SA_CENTER); if (!str.empty()) { - DrawString(r.left + WidgetDimensions::scaled.dropdowntext.left, r.right - dd_width - WidgetDimensions::scaled.dropdowntext.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), str, TC_BLACK, align); + DrawString(r.left + WidgetDimensions::scaled.dropdowntext.left, r.right - dd_width - WidgetDimensions::scaled.dropdowntext.right, CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), str, TC_BLACK, align); } } else { DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FrameFlag::Lowered : FrameFlags{}); DrawImageButtons(r.WithWidth(dd_width, false), WWT_DROPDOWN, colour, clicked_dropdown, SPR_ARROW_DOWN, SA_CENTER); if (!str.empty()) { - DrawString(r.left + dd_width + WidgetDimensions::scaled.dropdowntext.left, r.right - WidgetDimensions::scaled.dropdowntext.right, CenterBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), str, TC_BLACK, align); + DrawString(r.left + dd_width + WidgetDimensions::scaled.dropdowntext.left, r.right - WidgetDimensions::scaled.dropdowntext.right, CentreBounds(r.top, r.bottom, GetCharacterHeight(FS_NORMAL)), str, TC_BLACK, align); } } } From 5fad6897827199854fb5e11fd3f58ef4c353ba90 Mon Sep 17 00:00:00 2001 From: translators Date: Tue, 15 Apr 2025 04:44:48 +0000 Subject: [PATCH 041/572] Update: Translations from eints norwegian (bokmal): 1 change by eriksorngard --- src/lang/norwegian_bokmal.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index cc728cb0fa..3a0d7e0e86 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -2022,7 +2022,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Største antall STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Antall ikke-klebrige åpne vinduer før gamle vinduer automatisk blir lukket for å gi plass til nye vinduer STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :deaktivert +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Deaktivert STR_CONFIG_SETTING_ZOOM_MIN :Største zoom-inn nivå: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Største forstørrelsesnivå for synsfelt. Vær oppmerksom på at aktivering av høyere forstørrelsesnivå øker minnekravet From 301b209b87246417dc556ecbec33bb7a8e563c16 Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 15 Apr 2025 14:53:29 +0200 Subject: [PATCH 042/572] Fix: [NewGRF] Roadstop animation/randomisation was not triggered on vehicle arrival. (#14003) --- src/roadveh_cmd.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 069c4fbbb7..b56e8b772d 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -37,6 +37,7 @@ #include "framerate_type.h" #include "roadveh_cmd.h" #include "road_cmd.h" +#include "newgrf_roadstop.h" #include "table/strings.h" @@ -1453,6 +1454,8 @@ again: v->last_station_visited = st->index; RoadVehArrivesAt(v, st); v->BeginLoading(); + TriggerRoadStopRandomisation(st, v->tile, RSRT_VEH_ARRIVES); + TriggerRoadStopAnimation(st, v->tile, SAT_TRAIN_ARRIVES); } return false; } @@ -1515,6 +1518,8 @@ again: if (IsDriveThroughStopTile(v->tile) || (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == st->index)) { RoadVehArrivesAt(v, st); v->BeginLoading(); + TriggerRoadStopRandomisation(st, v->tile, RSRT_VEH_ARRIVES); + TriggerRoadStopAnimation(st, v->tile, SAT_TRAIN_ARRIVES); return false; } } else { From 47f0f4dd9efbd26486b1b813ae0f54b91e82c67b Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 15 Apr 2025 17:13:10 +0200 Subject: [PATCH 043/572] Fix: [NewGRF] Animation speed properties of houses and stations had wrong default. --- src/newgrf_station.h | 2 +- src/table/town_land.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/newgrf_station.h b/src/newgrf_station.h index bc66263700..1c3f5d8609 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -119,7 +119,7 @@ struct StationSpec : NewGRFSpecBase { disallowed_platforms(0), disallowed_lengths(0), cargo_threshold(0), cargo_triggers(0), callback_mask(0), flags(0), - animation({0, 0, 0, 0}) {} + animation({0, 0, 2, 0}) {} /** * Properties related the the grf file. * NUM_CARGO real cargo plus three pseudo cargo sprite groups. diff --git a/src/table/town_land.h b/src/table/town_land.h index 7b2f8c4b8e..ab682e8f51 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -1814,7 +1814,7 @@ static_assert(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); {ca1, ca2, ca3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ {INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \ bf, ba, true, GRFFileProps(INVALID_HOUSE_ID), HouseCallbackMasks{}, {COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN}, \ - 16, HouseExtraFlags{}, HOUSE_NO_CLASS, {0, 2, 0, 0}, 0, 0, 0, {}, {cg1, cg2, cg3}, } + 16, HouseExtraFlags{}, HOUSE_NO_CLASS, {0, 0, 2, 0}, 0, 0, 0, {}, {cg1, cg2, cg3}, } /** House specifications from original data */ extern const HouseSpec _original_house_specs[] = { /** From 03ed59a004fd43d0851de297f00d59bb0283aced Mon Sep 17 00:00:00 2001 From: frosch Date: Tue, 15 Apr 2025 17:11:17 +0200 Subject: [PATCH 044/572] Codechange: Turn AnimationStatus into an enum class. --- src/industry_cmd.cpp | 4 ++-- src/newgrf/newgrf_act0_airports.cpp | 4 ++-- src/newgrf/newgrf_act0_houses.cpp | 9 +++++---- src/newgrf/newgrf_act0_industries.cpp | 2 +- src/newgrf/newgrf_act0_objects.cpp | 2 +- src/newgrf/newgrf_act0_roadstops.cpp | 2 +- src/newgrf/newgrf_act0_stations.cpp | 2 +- src/newgrf_animation_base.h | 2 +- src/newgrf_animation_type.h | 16 +++++++++------- src/newgrf_object.h | 3 ++- src/newgrf_station.h | 4 ++-- src/station_cmd.cpp | 2 +- src/table/airporttiles.h | 4 ++-- src/table/build_industry.h | 2 +- src/table/object_land.h | 2 +- src/table/town_land.h | 2 +- 16 files changed, 33 insertions(+), 29 deletions(-) diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 1c2d79476d..42b8a6fd7f 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -696,7 +696,7 @@ static void AnimateTile_Industry(TileIndex tile) { IndustryGfx gfx = GetIndustryGfx(tile); - if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) { + if (GetIndustryTileSpec(gfx)->animation.status != AnimationStatus::NoAnimation) { AnimateNewIndustryTile(tile); return; } @@ -1955,7 +1955,7 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type, /* it->gfx is stored in the map. But the translated ID cur_gfx is the interesting one */ IndustryGfx cur_gfx = GetTranslatedIndustryTileID(it.gfx); const IndustryTileSpec *its = GetIndustryTileSpec(cur_gfx); - if (its->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(cur_tile); + if (its->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(cur_tile); } } diff --git a/src/newgrf/newgrf_act0_airports.cpp b/src/newgrf/newgrf_act0_airports.cpp index 0063a78361..407b980a06 100644 --- a/src/newgrf/newgrf_act0_airports.cpp +++ b/src/newgrf/newgrf_act0_airports.cpp @@ -210,7 +210,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, tsp->enabled = true; - tsp->animation.status = ANIM_STATUS_NO_ANIMATION; + tsp->animation = AnimationInfo{}; tsp->grf_prop.local_id = id; tsp->grf_prop.subst_id = subs_id; @@ -239,7 +239,7 @@ static ChangeInfoResult AirportTilesChangeInfo(uint first, uint last, int prop, case 0x0F: // Animation information tsp->animation.frames = buf.ReadByte(); - tsp->animation.status = buf.ReadByte(); + tsp->animation.status = static_cast(buf.ReadByte()); break; case 0x10: // Animation speed diff --git a/src/newgrf/newgrf_act0_houses.cpp b/src/newgrf/newgrf_act0_houses.cpp index 86b5c83910..d512666fdf 100644 --- a/src/newgrf/newgrf_act0_houses.cpp +++ b/src/newgrf/newgrf_act0_houses.cpp @@ -253,11 +253,12 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt housespec->extra_flags = static_cast(buf.ReadByte()); break; - case 0x1A: // Animation frames - housespec->animation.frames = buf.ReadByte(); - housespec->animation.status = GB(housespec->animation.frames, 7, 1); - SB(housespec->animation.frames, 7, 1, 0); + case 0x1A: { // Animation frames + uint8_t info = buf.ReadByte(); + housespec->animation.frames = GB(info, 0, 7); + housespec->animation.status = HasBit(info, 7) ? AnimationStatus::Looping : AnimationStatus::NonLooping; break; + } case 0x1B: // Animation speed housespec->animation.speed = Clamp(buf.ReadByte(), 2, 16); diff --git a/src/newgrf/newgrf_act0_industries.cpp b/src/newgrf/newgrf_act0_industries.cpp index 5f46bc3d2f..bb20156748 100644 --- a/src/newgrf/newgrf_act0_industries.cpp +++ b/src/newgrf/newgrf_act0_industries.cpp @@ -152,7 +152,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint first, uint last, int prop, case 0x0F: // Animation information tsp->animation.frames = buf.ReadByte(); - tsp->animation.status = buf.ReadByte(); + tsp->animation.status = static_cast(buf.ReadByte()); break; case 0x10: // Animation speed diff --git a/src/newgrf/newgrf_act0_objects.cpp b/src/newgrf/newgrf_act0_objects.cpp index fad95d7911..4b76d3620a 100644 --- a/src/newgrf/newgrf_act0_objects.cpp +++ b/src/newgrf/newgrf_act0_objects.cpp @@ -151,7 +151,7 @@ static ChangeInfoResult ObjectChangeInfo(uint first, uint last, int prop, ByteRe case 0x11: // Animation info spec->animation.frames = buf.ReadByte(); - spec->animation.status = buf.ReadByte(); + spec->animation.status = static_cast(buf.ReadByte()); break; case 0x12: // Animation speed diff --git a/src/newgrf/newgrf_act0_roadstops.cpp b/src/newgrf/newgrf_act0_roadstops.cpp index 3da28acf04..0a64a273a2 100644 --- a/src/newgrf/newgrf_act0_roadstops.cpp +++ b/src/newgrf/newgrf_act0_roadstops.cpp @@ -115,7 +115,7 @@ static ChangeInfoResult RoadStopChangeInfo(uint first, uint last, int prop, Byte case 0x0E: // Animation info rs->animation.frames = buf.ReadByte(); - rs->animation.status = buf.ReadByte(); + rs->animation.status = static_cast(buf.ReadByte()); break; case 0x0F: // Animation speed diff --git a/src/newgrf/newgrf_act0_stations.cpp b/src/newgrf/newgrf_act0_stations.cpp index 3041060040..38da11b566 100644 --- a/src/newgrf/newgrf_act0_stations.cpp +++ b/src/newgrf/newgrf_act0_stations.cpp @@ -235,7 +235,7 @@ static ChangeInfoResult StationChangeInfo(uint first, uint last, int prop, ByteR case 0x16: // Animation info statspec->animation.frames = buf.ReadByte(); - statspec->animation.status = buf.ReadByte(); + statspec->animation.status = static_cast(buf.ReadByte()); break; case 0x17: // Animation speed diff --git a/src/newgrf_animation_base.h b/src/newgrf_animation_base.h index c1c266f93d..c601179a70 100644 --- a/src/newgrf_animation_base.h +++ b/src/newgrf_animation_base.h @@ -103,7 +103,7 @@ struct AnimationBase { if (!frame_set_by_callback) { if (frame < num_frames) { frame++; - } else if (frame == num_frames && spec->animation.status == ANIM_STATUS_LOOPING) { + } else if (frame == num_frames && spec->animation.status == AnimationStatus::Looping) { /* This animation loops, so start again from the beginning */ frame = 0; } else { diff --git a/src/newgrf_animation_type.h b/src/newgrf_animation_type.h index 6835111bfb..ec1354b3fb 100644 --- a/src/newgrf_animation_type.h +++ b/src/newgrf_animation_type.h @@ -10,16 +10,18 @@ #ifndef NEWGRF_ANIMATION_TYPE_H #define NEWGRF_ANIMATION_TYPE_H -static const uint8_t ANIM_STATUS_NON_LOOPING = 0x00; ///< Animation is not looping. -static const uint8_t ANIM_STATUS_LOOPING = 0x01; ///< Animation is looping. -static const uint8_t ANIM_STATUS_NO_ANIMATION = 0xFF; ///< There is no animation. +enum class AnimationStatus : uint8_t { + NonLooping = 0x00, ///< Animation is not looping. + Looping = 0x01, ///< Animation is looping. + NoAnimation = 0xFF, ///< There is no animation. +}; /** Information about animation. */ struct AnimationInfo { - uint8_t frames; ///< The number of frames. - uint8_t status; ///< Status; 0: no looping, 1: looping, 0xFF: no animation. - uint8_t speed; ///< The speed, i.e. the amount of time between frames. - uint16_t triggers; ///< The triggers that trigger animation. + uint8_t frames = 0; ///< The number of frames. + AnimationStatus status = AnimationStatus::NoAnimation; ///< Status. + uint8_t speed = 2; ///< The speed: time between frames = 2^speed ticks. + uint16_t triggers = 0; ///< The triggers that trigger animation. }; /** Animation triggers for station. */ diff --git a/src/newgrf_object.h b/src/newgrf_object.h index 74cf12e629..c965de8aed 100644 --- a/src/newgrf_object.h +++ b/src/newgrf_object.h @@ -60,7 +60,8 @@ DECLARE_INCREMENT_DECREMENT_OPERATORS(ObjectClassID) struct ObjectSpec : NewGRFSpecBase { /* 2 because of the "normal" and "buy" sprite stacks. */ FixedGRFFileProps<2> grf_prop; ///< Properties related the the grf file - AnimationInfo animation; ///< Information about the animation. + /* Animation speed default differs from other features */ + AnimationInfo animation{0, AnimationStatus::NoAnimation, 0, 0}; ///< Information about the animation. StringID name; ///< The name for this object. LandscapeTypes climate; ///< In which climates is this object available? diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 1c3f5d8609..36d1b9125b 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -118,8 +118,8 @@ struct StationSpec : NewGRFSpecBase { StationSpec() : name(0), disallowed_platforms(0), disallowed_lengths(0), cargo_threshold(0), cargo_triggers(0), - callback_mask(0), flags(0), - animation({0, 0, 2, 0}) {} + callback_mask(0), flags(0) + {} /** * Properties related the the grf file. * NUM_CARGO real cargo plus three pseudo cargo sprite groups. diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index ad5e88dd96..070f2ceb55 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2617,7 +2617,7 @@ CommandCost CmdBuildAirport(DoCommandFlags flags, TileIndex tile, uint8_t airpor SetStationTileRandomBits(t, GB(Random(), 0, 4)); st->airport.Add(iter); - if (AirportTileSpec::Get(GetTranslatedAirportTileID(iter.GetStationGfx()))->animation.status != ANIM_STATUS_NO_ANIMATION) AddAnimatedTile(t); + if (AirportTileSpec::Get(GetTranslatedAirportTileID(iter.GetStationGfx()))->animation.status != AnimationStatus::NoAnimation) AddAnimatedTile(t); } /* Only call the animation trigger after all tiles have been built */ diff --git a/src/table/airporttiles.h b/src/table/airporttiles.h index 1776ea0505..0003b91065 100644 --- a/src/table/airporttiles.h +++ b/src/table/airporttiles.h @@ -11,9 +11,9 @@ #define AIRPORTTILES_H /** Writes all airport tile properties in the AirportTile struct */ -#define AT(num_frames, anim_speed) {{num_frames, ANIM_STATUS_LOOPING, anim_speed, 0}, STR_NULL, AirportTileCallbackMasks{}, 0, true, GRFFileProps(INVALID_AIRPORTTILE), {}} +#define AT(num_frames, anim_speed) {{num_frames, AnimationStatus::Looping, anim_speed, 0}, STR_NULL, AirportTileCallbackMasks{}, 0, true, GRFFileProps(INVALID_AIRPORTTILE), {}} /** Writes an airport tile without animation in the AirportTile struct */ -#define AT_NOANIM {{0, ANIM_STATUS_NO_ANIMATION, 2, 0}, STR_NULL, AirportTileCallbackMasks{}, 0, true, GRFFileProps(INVALID_AIRPORTTILE), {}} +#define AT_NOANIM {AnimationInfo{}, STR_NULL, AirportTileCallbackMasks{}, 0, true, GRFFileProps(INVALID_AIRPORTTILE), {}} /** * All default airport tiles. diff --git a/src/table/build_industry.h b/src/table/build_industry.h index 258c368170..1f2608d10e 100644 --- a/src/table/build_industry.h +++ b/src/table/build_industry.h @@ -1533,7 +1533,7 @@ static const IndustrySpec _origin_industry_specs[NEW_INDUSTRYOFFSET] = { */ #define MT(ca1, c1, ca2, c2, ca3, c3, sl, a1, a2, a3) { \ {INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \ - {ca1, ca2, ca3}, sl, a1, a2, a3, IndustryTileCallbackMasks{}, {0, ANIM_STATUS_NO_ANIMATION, 2, 0}, IndustryTileSpecialFlags{}, true, GRFFileProps(INVALID_INDUSTRYTILE), {}, {c1, c2, c3} \ + {ca1, ca2, ca3}, sl, a1, a2, a3, IndustryTileCallbackMasks{}, AnimationInfo{}, IndustryTileSpecialFlags{}, true, GRFFileProps(INVALID_INDUSTRYTILE), {}, {c1, c2, c3} \ } static const IndustryTileSpec _origin_industry_tile_specs[NEW_INDUSTRYTILEOFFSET] = { /* Coal Mine */ diff --git a/src/table/object_land.h b/src/table/object_land.h index 39574a82c6..0ea2ab8eae 100644 --- a/src/table/object_land.h +++ b/src/table/object_land.h @@ -104,7 +104,7 @@ static const DrawTileSpriteSpan _object_hq[] = { #undef TILE_SPRITE_LINE #undef TILE_SPRITE_LINE_NOTHING -#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) {{INVALID_OBJECT_CLASS, 0}, FixedGRFFileProps<2>{}, {0, 0, 0, 0}, name, climate, size, build_cost_multiplier, clear_cost_multiplier, TimerGameCalendar::Date{}, CalendarTime::MAX_DATE + 1, flags, ObjectCallbackMasks{}, height, 1, gen_amount, {}} +#define M(name, size, build_cost_multiplier, clear_cost_multiplier, height, climate, gen_amount, flags) {{INVALID_OBJECT_CLASS, 0}, FixedGRFFileProps<2>{}, AnimationInfo{}, name, climate, size, build_cost_multiplier, clear_cost_multiplier, TimerGameCalendar::Date{}, CalendarTime::MAX_DATE + 1, flags, ObjectCallbackMasks{}, height, 1, gen_amount, {}} /* Climates * T = Temperate diff --git a/src/table/town_land.h b/src/table/town_land.h index ab682e8f51..776fb23231 100644 --- a/src/table/town_land.h +++ b/src/table/town_land.h @@ -1814,7 +1814,7 @@ static_assert(lengthof(_town_draw_tile_data) == (NEW_HOUSE_OFFSET) * 4 * 4); {ca1, ca2, ca3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, \ {INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO, INVALID_CARGO}, \ bf, ba, true, GRFFileProps(INVALID_HOUSE_ID), HouseCallbackMasks{}, {COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN, COLOUR_BEGIN}, \ - 16, HouseExtraFlags{}, HOUSE_NO_CLASS, {0, 0, 2, 0}, 0, 0, 0, {}, {cg1, cg2, cg3}, } + 16, HouseExtraFlags{}, HOUSE_NO_CLASS, AnimationInfo{}, 0, 0, 0, {}, {cg1, cg2, cg3}, } /** House specifications from original data */ extern const HouseSpec _original_house_specs[] = { /** From fa0814e257f692fcfd5b53dcadd5b283bf9fa2b7 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 15 Apr 2025 21:57:13 +0100 Subject: [PATCH 045/572] Codefix: Codestyle consistency fixes. (#14008) --- src/core/string_builder.hpp | 5 ++--- src/core/string_consumer.hpp | 8 ++++---- src/core/string_inplace.hpp | 6 ++---- src/string.cpp | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/core/string_builder.hpp b/src/core/string_builder.hpp index 77fba335fd..c6058bab05 100644 --- a/src/core/string_builder.hpp +++ b/src/core/string_builder.hpp @@ -53,7 +53,7 @@ public: /** * Append integer 'value' in given number 'base'. */ - template + template void PutIntegerBase(T value, int base) { std::array buf; @@ -67,8 +67,7 @@ public: /** * Compose data into a growing std::string. */ -class StringBuilder final : public BaseStringBuilder -{ +class StringBuilder final : public BaseStringBuilder { std::string *dest; public: /** diff --git a/src/core/string_consumer.hpp b/src/core/string_consumer.hpp index b85bf65eb9..e4e9145fa3 100644 --- a/src/core/string_consumer.hpp +++ b/src/core/string_consumer.hpp @@ -800,7 +800,7 @@ public: void SkipUntilUtf8(char32_t c, SeparatorUsage sep); private: - template + template [[nodiscard]] static std::pair ParseIntegerBase(std::string_view src, int base, bool log_errors) { if (base == 0) { @@ -850,7 +850,7 @@ public: * @return Length of string match, and parsed value. * @note The parser rejects leading whitespace and unary plus. */ - template + template [[nodiscard]] std::pair PeekIntegerBase(int base) const { return ParseIntegerBase(this->src.substr(this->position), base, false); @@ -861,7 +861,7 @@ public: * @return Parsed value, if valid. * @note The parser rejects leading whitespace and unary plus. */ - template + template [[nodiscard]] std::optional TryReadIntegerBase(int base) { auto [len, value] = this->PeekIntegerBase(base); @@ -876,7 +876,7 @@ public: * @note The reader is advanced, even if no valid data was present. * @note The parser rejects leading whitespace and unary plus. */ - template + template [[nodiscard]] T ReadIntegerBase(int base, T def = 0) { auto [len, value] = ParseIntegerBase(this->src.substr(this->position), base, true); diff --git a/src/core/string_inplace.hpp b/src/core/string_inplace.hpp index 855ae55896..eaf16752b0 100644 --- a/src/core/string_inplace.hpp +++ b/src/core/string_inplace.hpp @@ -18,8 +18,7 @@ /** * Builder implementation for InPlaceReplacement. */ -class InPlaceBuilder final : public BaseStringBuilder -{ +class InPlaceBuilder final : public BaseStringBuilder { std::span dest; size_type position = 0; const StringConsumer &consumer; @@ -90,8 +89,7 @@ public: * - The Builder writes data to the buffer, replacing already consumed data. * - The Builder asserts, if it overtakes the consumer. */ -class InPlaceReplacement -{ +class InPlaceReplacement { public: StringConsumer consumer; ///< Consumer from shared buffer InPlaceBuilder builder; ///< Builder into shared buffer diff --git a/src/string.cpp b/src/string.cpp index a9d72efab9..21cd8f0ced 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -117,7 +117,7 @@ static bool IsSccEncodedCode(char32_t c) * @param consumer The string to validate. * @param settings The settings for the string validation. */ -template +template static void StrMakeValid(Builder &builder, StringConsumer &consumer, StringValidationSettings settings) { /* Assume the ABSOLUTE WORST to be in str as it comes from the outside. */ From b57f3262ecb7c7269e20d29eb08863f20c3e821f Mon Sep 17 00:00:00 2001 From: translators Date: Wed, 16 Apr 2025 04:44:48 +0000 Subject: [PATCH 046/572] Update: Translations from eints spanish: 101 changes by MontyMontana --- src/lang/spanish.txt | 158 +++++++++++++++++++++++++++---------------- 1 file changed, 101 insertions(+), 57 deletions(-) diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 0b1b39c029..4cc56411b5 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -453,6 +453,12 @@ STR_SETTINGS_MENU_SANDBOX_OPTIONS :Opciones sandbo STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Opciones de transparencia STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Ver nombres de municipios STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Ver nombres de estaciones +STR_SETTINGS_MENU_STATION_NAMES_TRAIN :Estaciones de tren +STR_SETTINGS_MENU_STATION_NAMES_LORRY :Estaciones de camión +STR_SETTINGS_MENU_STATION_NAMES_BUS :Estaciones de autobús +STR_SETTINGS_MENU_STATION_NAMES_SHIP :Muelles +STR_SETTINGS_MENU_STATION_NAMES_PLANE :Aeropuertos +STR_SETTINGS_MENU_STATION_NAMES_GHOST :Vestigios STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Ver puntos de ruta STR_SETTINGS_MENU_SIGNS_DISPLAYED :Ver letreros STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Letreros y nombres de competidor mostrados @@ -928,7 +934,7 @@ STR_NEWS_SHOW_VEHICLE_GROUP_TOOLTIP :{BLACK}Abre la STR_NEWS_STATION_NO_LONGER_ACCEPTS_CARGO_LIST :{WHITE}{STATION} ya no acepta: {CARGO_LIST} STR_NEWS_STATION_NOW_ACCEPTS_CARGO_LIST :{WHITE}{STATION} ahora acepta: {CARGO_LIST} -STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Oferta de subvención terminada:{}{}{STRING} de {STRING} a {STRING} ya no conlleva una subvención +STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED :{BIG_FONT}{BLACK}Oferta de subvención vencida:{}{}{STRING} de {STRING} a {STRING} ya no conlleva una subvención STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE :{BIG_FONT}{BLACK}Subvención retirada:{}{}El servicio de {STRING} desde {STRING} a {STRING} ya no está subvencionado STR_NEWS_SERVICE_SUBSIDY_OFFERED :{BIG_FONT}{BLACK}Se ofrece subvención:{}{}¡Al primer servicio de {STRING} que cubra la línea desde {STRING} a {STRING} se le otorgará una subvención durante {UNITS_YEARS_OR_MINUTES} por parte de las autoridades locales! ###length 4 @@ -1018,6 +1024,7 @@ STR_GAME_OPTIONS_CURRENCY_IDR :Rupia indonesia STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit malasio STR_GAME_OPTIONS_CURRENCY_LVL :Lats letón STR_GAME_OPTIONS_CURRENCY_PTE :Escudo portugués +STR_GAME_OPTIONS_CURRENCY_UAH :Grivna ucraniana STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autoguardado STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Selección del intervalo entre guardados automáticos del juego @@ -1211,7 +1218,7 @@ STR_CITY_APPROVAL_TOLERANT :Tolerante STR_CITY_APPROVAL_HOSTILE :Hostil STR_CITY_APPROVAL_PERMISSIVE :Permisiva (sin efecto sobre las acciones de las compañías) -STR_WARNING_NO_SUITABLE_AI :{WHITE}No se han encontrado IA apropiadas...{}Puedes descargar IA a través del sistema de 'Contenido Online' +STR_WARNING_NO_SUITABLE_AI :{WHITE}No se han encontrado IA apropiadas...{}Puedes descargar IA a través del sistema de 'Contenido en línea' # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configuración @@ -1980,7 +1987,12 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Prohibido STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Permitido STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Permitido, patrón de carreteras personalizado +STR_CONFIG_SETTING_HOUSE_PLACER :Colocación individual de casas: {STRING} +STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Activar esta opción permite a los jugadores colocar casas manualmente ###length 3 +STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN :Prohibido +STR_CONFIG_SETTING_HOUSE_PLACER_ALLOWED :Permitido +STR_CONFIG_SETTING_HOUSE_PLACER_FULLY_CONSTRUCTED :Permitido, construcción completa STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Generación de carga en municipios: {STRING} STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Cantidad de carga que es producida por las casas del municipio, en relación a la población total del municipio.{}Crecimiento cuadrático: Un municipio de doble tamaño genera el cuádruple de pasajeros.{}Crecimiento lineal: Un municipio de doble tamaño genera el doble de pasajeros @@ -2009,7 +2021,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Máximo número STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Número máximo de ventanas sin anclar que pueden estar abiertas antes de que las más antiguas se cierren automáticamente para dejar paso a las nuevas STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :deshabilitado +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Deshabilitado STR_CONFIG_SETTING_ZOOM_MIN :Máximo acercamiento: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Nivel máximo de acercamiento para las ventanas de vista y la vista principal. Los niveles altos de acercamiento incrementan el consumo de memoria del juego @@ -2194,7 +2206,7 @@ STR_INTRO_HIGHSCORE :{BLACK}Tabla de STR_INTRO_HELP :{BLACK}Ayuda y Manuales STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Configuración STR_INTRO_NEWGRF_SETTINGS :{BLACK}Configuración NewGRF -STR_INTRO_ONLINE_CONTENT :{BLACK}Contenido Online +STR_INTRO_ONLINE_CONTENT :{BLACK}Contenido en línea STR_INTRO_AI_SETTINGS :{BLACK}Configuración de IA STR_INTRO_GAMESCRIPT_SETTINGS :{BLACK}Scripts de Juego STR_INTRO_QUIT :{BLACK}Salir @@ -2243,6 +2255,7 @@ STR_HELP_WINDOW_README :{BLACK}Léeme STR_HELP_WINDOW_CHANGELOG :{BLACK}Registro de cambios STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Fallos conocidos STR_HELP_WINDOW_LICENSE :{BLACK}Licencia +STR_HELP_WINDOW_FONTS :{BLACK}Fuentes STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Manual / Wiki STR_HELP_WINDOW_BUGTRACKER :{BLACK}Informar de un problema @@ -2631,13 +2644,14 @@ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :esperando actua STR_NETWORK_MESSAGE_CLIENT_LEAVING :abandonando STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} se ha unido a la partida STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} se ha unido a la partida (Cliente #{NUM}) +STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} se ha unido a {STRING} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} se ha unido como espectador STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} ha creado una empresa nueva (#{NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} ha abandonado el juego ({STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} ha cambiado su nombre a {STRING} STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} ha transferido {CURRENCY_LONG} a {STRING} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}El servidor ha cerrado la sesión -STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}El servidor está reiniciando...{}Espera por favor... +STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}El servidor se está reiniciando...{}{}Espera por favor... STR_NETWORK_MESSAGE_KICKED :*** {STRING} ha sido expulsado. Razón: ({STRING}) STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}El registro del servidor ha fallado @@ -2646,7 +2660,7 @@ STR_NETWORK_ERROR_COORDINATOR_ISOLATED :{WHITE}Tu servi STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL :{WHITE}Los demás jugadores no podrán conectarse a tu servidor # Content downloading window -STR_CONTENT_TITLE :{WHITE}Descarga de contenido +STR_CONTENT_TITLE :{WHITE}Contenido en línea STR_CONTENT_TYPE_CAPTION :{BLACK}Tipo STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Tipo de contenido STR_CONTENT_NAME_CAPTION :{BLACK}Nombre @@ -2845,6 +2859,7 @@ STR_HOUSE_PICKER_YEARS_FROM :{BLACK}Años: { STR_HOUSE_PICKER_YEARS_UNTIL :{BLACK}Años: {ORANGE}Hasta {NUM} STR_HOUSE_PICKER_SIZE :{BLACK}Tamaño: {ORANGE}{NUM}x{NUM} casillas STR_HOUSE_PICKER_CARGO_ACCEPTED :{BLACK}Carga aceptada: {ORANGE} +STR_HOUSE_PICKER_CARGO_PRODUCED :{BLACK}Carga producida: {ORANGE}{CARGO_LIST} STR_HOUSE_PICKER_CLASS_ZONE1 :Afueras STR_HOUSE_PICKER_CLASS_ZONE2 :Periferia @@ -2852,6 +2867,10 @@ STR_HOUSE_PICKER_CLASS_ZONE3 :Suburbios exter STR_HOUSE_PICKER_CLASS_ZONE4 :Suburbios interiores STR_HOUSE_PICKER_CLASS_ZONE5 :Centro urbano +STR_HOUSE_PICKER_PROTECT_TITLE :Evitar mejoras +STR_HOUSE_PICKER_PROTECT_TOOLTIP :Selecciona si esta casa estará protegida de reemplazos cuando el municipio crezca +STR_HOUSE_PICKER_PROTECT_OFF :No +STR_HOUSE_PICKER_PROTECT_ON :Sí STR_STATION_CLASS_DFLT :Por defecto STR_STATION_CLASS_DFLT_STATION :Estación por defecto @@ -2885,6 +2904,7 @@ STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Selecci STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Selección de puente - Clica en el puente elegido para construirlo STR_SELECT_BRIDGE_INFO_NAME :{GOLD}{STRING} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED :{GOLD}{STRING},{} {VELOCITY} +STR_SELECT_BRIDGE_INFO_NAME_COST :{GOLD}{STRING},{} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED_COST :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_BRIDGE_NAME_SUSPENSION_STEEL :Colgante, Acero STR_BRIDGE_NAME_GIRDER_STEEL :Tirantes, Acero @@ -2943,7 +2963,7 @@ STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Seleccio # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Construcción de Canales STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Canales -STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Construye canales. Con Mayús sólo muestra una estimación del coste +STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Construye canales. Ctrl+clic+arrastrar permite seleccionar un área diagonalmente. Con Mayús sólo muestra una estimación del coste STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Construye esclusas. Con Mayús sólo muestra una estimación del coste STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Contruye un astillero (para comprar y dar mantenimiento a barcos). Con Mayús sólo muestra una estimación del coste STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construye muelles. Ctrl+clic para seleccionar otra estación a la que unirlo. Con Mayús sólo muestra una estimación del coste @@ -3128,6 +3148,8 @@ STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tipo de STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Límite de velocidad de ferrocarril: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Límite de velocidad de carretera: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Límite de velocidad de tranvía: {LTBLUE}{VELOCITY} +STR_LAND_AREA_INFORMATION_TOWN_CAN_UPGRADE :{BLACK}El municipio puede reemplazarlo: {LTBLUE}Sí +STR_LAND_AREA_INFORMATION_TOWN_CANNOT_UPGRADE :{BLACK}El municipio puede reemplazarlo: {LTBLUE}No # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Rocas @@ -3136,6 +3158,9 @@ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Terreno desnudo STR_LAI_CLEAR_DESCRIPTION_GRASS :Pastos STR_LAI_CLEAR_DESCRIPTION_FIELDS :Campos STR_LAI_CLEAR_DESCRIPTION_DESERT :Desierto +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROCKS :Rocas cubiertas con nieve +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROUGH_LAND :Terreno irregular cubierto con nieve +STR_LAI_CLEAR_DESCRIPTION_SNOWY_GRASS :Hierba cubierta de nieve STR_LAI_RAIL_DESCRIPTION_TRACK :Vía de ferrocarril STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Vía de ferrocarril con señales de bloque @@ -3607,17 +3632,17 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Archivo STR_NEWGRF_LIST_MISSING :{RED}Faltan archivos # NewGRF 'it's broken' warnings -STR_NEWGRF_BROKEN :{WHITE}Es probable que el funcionamiento del NewGRF '{0:STRING}' cause desincronizaciones o fallos -STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Ha cambiado el estado 'vagón motorizado' '{1:ENGINE}' cuando no estaba dentro de un depósito -STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ha cambiado la longitud del vehículo '{1:ENGINE}' cuando no estaba dentro de un depósito -STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Ha cambiado la capacidad del vehículo '{1:ENGINE}' fuera de un depósito o mientras no se estaba reformando +STR_NEWGRF_BROKEN :{WHITE}Es probable que el funcionamiento del NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' cause desincronizaciones o fallos +STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Ha cambiado el estado 'vagón motorizado' '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' cuando no estaba dentro de un depósito +STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ha cambiado la longitud del vehículo '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' cuando no estaba dentro de un depósito +STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Ha cambiado la capacidad del vehículo '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' cuando no estaba dentro de un depósito o mientras no se estaba reformando STR_BROKEN_VEHICLE_LENGTH :{WHITE}El tren '{VEHICLE}' perteneciente a '{COMPANY}' tiene una longitud incorrecta. Esto puede deberse a problemas con los NewGRF. El juego puede desincronizarse o fallar por completo -STR_NEWGRF_BUGGY :{WHITE}El NewGRF '{0:STRING}' da información incorrecta -STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}La información de carga/reforma para '{1:ENGINE}' difiere de la de lista de compra después de la construcción. Esto puede causar que la renovación/reemplazo automático no haga la reforma correcta -STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' ha causado un bucle sin fin en la 'callback' de producción +STR_NEWGRF_BUGGY :{WHITE}El NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' da información incorrecta +STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}La información de carga/reforma para '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' difiere de la de lista de compra después de la construcción. Esto puede causar que la renovación/reemplazo automático no haga la reforma correcta +STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' ha causado un bucle sin fin en la 'callback' de producción STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}'Callback' {1:HEX} ha devuelto el resultado desconocido o inválido {2:HEX} -STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' ha devuelto tipo de carga inválida en el 'callback' de producción en {2:HEX} +STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' ha devuelto tipo de carga inválida en el 'callback' de producción en {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : @@ -4013,6 +4038,10 @@ STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Produce: STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Necesita: +STR_INDUSTRY_VIEW_ACCEPT_CARGO_SUFFIX :{YELLOW}{0:STRING}{BLACK}{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_SUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} esperando{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_NOSUFFIX :{YELLOW}{0:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_NOSUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} en espera STR_CONFIG_GAME_PRODUCTION :{WHITE}Cambiar producción (múltiplos de 8, máximo 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Cambiar nivel de producción (porcentaje, hasta un máximo de 800%) @@ -4670,54 +4699,56 @@ STR_ORDER_ROAD_VEHICLE_DEPOT :Depósito de ve STR_ORDER_SHIP_DEPOT :Astillero de barcos ###next-name-looks-similar +STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING}l hangar más cercano +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING}l {STRING} más cercano STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} -STR_ORDER_REFIT_ORDER :(Reformar a {STRING}) -STR_ORDER_REFIT_STOP_ORDER :(Reformar a {STRING} y detenerse) -STR_ORDER_STOP_ORDER :(Detenerse) +STR_ORDER_REFIT_ORDER :{SPACE}(Reformar a {STRING}) +STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Reformar a {STRING} y detenerse) +STR_ORDER_STOP_ORDER :{SPACE}(Detenerse) -STR_ORDER_WAIT_TO_UNBUNCH :(Esperar para distanciarse) +STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(Esperar para distanciarse) STR_ORDER_GO_TO_STATION :{STRING} {STATION} STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(No puede usar la estación){POP_COLOUR} {STRING} {STATION} -STR_ORDER_IMPLICIT :(Implícita) +STR_ORDER_IMPLICIT :{SPACE}(Implícita) -STR_ORDER_FULL_LOAD :(Carga completa) -STR_ORDER_FULL_LOAD_ANY :(Carga completa cualquier carga) -STR_ORDER_NO_LOAD :(Sin carga) -STR_ORDER_UNLOAD :(Descargar y tomar carga) -STR_ORDER_UNLOAD_FULL_LOAD :(Descargar y esperar a carga completa) -STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Descargar y esperar a cualquier carga completa) -STR_ORDER_UNLOAD_NO_LOAD :(Descargar y dejar vacío) -STR_ORDER_TRANSFER :(Transferir y tomar carga) -STR_ORDER_TRANSFER_FULL_LOAD :(Transferir y esperar a carga completa) -STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transferir y esperar a cualquier carga completa) -STR_ORDER_TRANSFER_NO_LOAD :(Transferir y dejar vacío) -STR_ORDER_NO_UNLOAD :(No descargar y tomar carga) -STR_ORDER_NO_UNLOAD_FULL_LOAD :(No descargar y esperar a carga completa) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(No descargar y esperar a cualquier carga completa) -STR_ORDER_NO_UNLOAD_NO_LOAD :(No descargar y no cargar) +STR_ORDER_FULL_LOAD :{SPACE}(Carga completa) +STR_ORDER_FULL_LOAD_ANY :{SPACE}(Carga completa cualquier carga) +STR_ORDER_NO_LOAD :{SPACE}(Sin carga) +STR_ORDER_UNLOAD :{SPACE}(Descargar y tomar carga) +STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Descargar y esperar a carga completa) +STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Descargar y esperar a cualquier carga completa) +STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Descargar y dejar vacío) +STR_ORDER_TRANSFER :{SPACE}(Transferir y cargar) +STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Transferir y esperar a carga completa) +STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Transferir y esperar a cualquier carga completa) +STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Transferir y dejar vacío) +STR_ORDER_NO_UNLOAD :{SPACE}(No descargar y tomar carga) +STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(No descargar y esperar a carga completa) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(No descargar y esperar a cualquier carga completa) +STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(No descargar y no cargar) -STR_ORDER_AUTO_REFIT :(Reforma a {STRING}) -STR_ORDER_FULL_LOAD_REFIT :(Carga completa con reforma a {STRING}) -STR_ORDER_FULL_LOAD_ANY_REFIT :(Cualquier carga completa con reforma a {STRING}) -STR_ORDER_UNLOAD_REFIT :(Descargar y tomar carga con reforma a {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Descargar y esperar carga completa con reforma a {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Descargar y esperar a cualquier carga completa con reforma a {STRING}) -STR_ORDER_TRANSFER_REFIT :(Transferir y tomar carga con reforma a {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transferir y esperar a carga completa con reforma a {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transferir y esperar a cualquier carga completa con reforma a {STRING}) -STR_ORDER_NO_UNLOAD_REFIT :(No descargar y tomar carga con reforma a {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(No descargar y esperar a carga completa con reforma a {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(No descargar y esperar a cualquier carga completa con reforma a {STRING}) +STR_ORDER_AUTO_REFIT :{SPACE}(Reforma a {STRING}) +STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Carga completa con reforma a {STRING}) +STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Cualquier carga completa con reforma a {STRING}) +STR_ORDER_UNLOAD_REFIT :{SPACE}(Descargar y tomar carga con reforma a {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Descargar y esperar carga completa con reforma a {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Descargar y esperar a cualquier carga completa con reforma a {STRING}) +STR_ORDER_TRANSFER_REFIT :{SPACE}(Transferir y cargar con reforma a {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Transferir y esperar a carga completa con reforma a {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Transferir y esperar a cualquier carga completa con reforma a {STRING}) +STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(No descargar y tomar carga con reforma a {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(No descargar y esperar a carga completa con reforma a {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(No descargar y esperar a cualquier carga completa con reforma a {STRING}) STR_ORDER_AUTO_REFIT_ANY :carga disponible ###length 3 -STR_ORDER_STOP_LOCATION_NEAR_END :[extremo cercano] -STR_ORDER_STOP_LOCATION_MIDDLE :[centro] -STR_ORDER_STOP_LOCATION_FAR_END :[extremo lejano] +STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[extremo cercano] +STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[centro] +STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[extremo lejano] STR_ORDER_OUT_OF_RANGE :{RED} (El próximo destino está fuera de alcance) @@ -4742,8 +4773,8 @@ STR_TIMETABLE_TRAVEL_FOR :Viajar durante STR_TIMETABLE_TRAVEL_FOR_SPEED :Viajar durante {STRING} a {VELOCITY} como máximo STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Viajar (durante {STRING}, sin programar) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Viajar (durante {STRING}, sin programar) a {VELOCITY} como máximo -STR_TIMETABLE_STAY_FOR_ESTIMATED :(permanecer {STRING}, sin programar) -STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(viajar durante {STRING}, sin programar) +STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(permanecer {STRING}, sin programar) +STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(viajar durante {STRING}, sin programar) STR_TIMETABLE_STAY_FOR :y permanecer {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :y viajar durante {STRING} @@ -4764,12 +4795,14 @@ STR_TIMETABLE_START_SECONDS_QUERY :Segundos hasta STR_TIMETABLE_CHANGE_TIME :{BLACK}Modificar duración STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Modifica la duración esperada de la orden seleccionada. Ctrl+clic establece la duración para todas las órdenes +STR_TIMETABLE_CHANGE_TIME_QUERY :Cambiar duración STR_TIMETABLE_CLEAR_TIME :{BLACK}Borrar duración STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Borra la duración de la orden resaltada.Ctrl+clic borra la duración de todas las órdenes STR_TIMETABLE_CHANGE_SPEED :{BLACK}Modificar límite de velocidad STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambia el límite de velocidad de la orden resaltada. Ctrl+clic establece el límite para todas las órdenes +STR_TIMETABLE_CHANGE_SPEED_QUERY :Cambiar límite de velocidad STR_TIMETABLE_CLEAR_SPEED :{BLACK}Borrar límite de velocidad STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Borra el límite de velocidad de la orden resaltada. Ctrl+clic borra el límite de todas las órdenes @@ -4819,7 +4852,7 @@ STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Muestra STR_AI_GAME_SCRIPT :{BLACK}Script de Juego STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Analizar el registro del script de juego. Ctrl+click para abrir en una nueva ventana -STR_ERROR_AI_NO_AI_FOUND :No se encontró ninguna IA apropiada para cargar.{}Ésta es una IA por defecto que no realiza acción alguna.{}Puedes descargar nuevas IA mediante el sistema de 'Contenido Online' +STR_ERROR_AI_NO_AI_FOUND :No se encontró ninguna IA apropiada para cargar.{}Ésta es una IA por defecto que no realiza acción alguna.{}Puedes descargar nuevas IA mediante el sistema de 'Contenido en línea' STR_ERROR_AI_PLEASE_REPORT_CRASH :{WHITE}Uno de los scripts ejecutados ha fallado. Por favor, informa del fallo al autor del script con una captura de la ventana de depuración de script/IA STR_ERROR_AI_DEBUG_SERVER_ONLY :{YELLOW}La ventana de depuración de scripts solo está disponible para el servidor @@ -4874,8 +4907,8 @@ STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}Mapa de STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Minimapa # Script Parameters -STR_AI_SETTINGS_CAPTION_AI :{WHITE}IA -STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Script de juego +STR_AI_SETTINGS_CAPTION_AI :{WHITE}Parámetros de IA +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :{WHITE}Parámetros del script de juego STR_AI_SETTINGS_CLOSE :{BLACK}Cerrar STR_AI_SETTINGS_RESET :{BLACK}Reiniciar STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -4936,7 +4969,7 @@ STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}La partida se guardó en una versión sin soporte para tranvías. Todos los tranvías han sido eliminados # Map generation messages -STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Generación de mapa abortada...{}... no hay localizaciones apropiadas para municipios +STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Generación de mapa abortada...{}{}... no hay localizaciones apropiadas para municipios STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... no hay municipios en el escenario STR_ERROR_PNGMAP :{WHITE}No se pudo cargar mapa de alturas PNG... @@ -4965,6 +4998,7 @@ STR_ERROR_SCREENSHOT_FAILED :{WHITE}¡Captur # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Mensaje +STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Mensaje de {COMPANY} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Fuera del borde del mapa @@ -4983,6 +5017,7 @@ STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... lím STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... límite de casillas despejadas alcanzado STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... limite de plantación de árboles alcanzado STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}El nombre debe ser único +STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{STRING} en medio STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}No permitido en pausa # Local authority errors @@ -5025,7 +5060,7 @@ STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... dema STR_ERROR_TOO_MANY_TOWNS :{WHITE}... demasiados municipios STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... no hay más espacio en el mapa STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Obras de carretera en progreso -STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}No se puede borrar este municipio...{}Quedan estaciones o depósitos relacionados con él, o una propiedad suya no puede ser retirada +STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}No se puede borrar este municipio...{}{}Quedan estaciones o depósitos relacionados con él, o una propiedad suya no puede ser retirada STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... no existe un lugar apropiado para una estatua en el centro de este municipio STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}No se puede construir edificio... @@ -5299,8 +5334,16 @@ STR_ERROR_CAN_T_SELL_SHIP :{WHITE}No se pu STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}No se puede vender la aeronave... ###length VEHICLE_TYPES +STR_ERROR_CAN_T_SELL_ALL_TRAIN :{WHITE}No se pueden vender todos los trenes... +STR_ERROR_CAN_T_SELL_ALL_ROAD_VEHICLE :{WHITE}No se pueden vender todos los vehículos de carretera... +STR_ERROR_CAN_T_SELL_ALL_SHIP :{WHITE}No se pueden vender todos los barcos... +STR_ERROR_CAN_T_SELL_ALL_AIRCRAFT :{WHITE}No se pueden vender todas las aeronaves... ###length VEHICLE_TYPES +STR_ERROR_CAN_T_AUTOREPLACE_TRAIN :{WHITE}No se pueden reemplazar automáticamente los trenes... +STR_ERROR_CAN_T_AUTOREPLACE_ROAD_VEHICLE :{WHITE}No se pueden reemplazar automáticamente los vehículos de carretera... +STR_ERROR_CAN_T_AUTOREPLACE_SHIP :{WHITE}No se pueden reemplazar automáticamente los barcos... +STR_ERROR_CAN_T_AUTOREPLACE_AIRCRAFT :{WHITE}No se pueden reemplazar automáticamente las aeronaves... STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Demasiados vehículos en el juego STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}No se puede cambiar intervalo de mantenimiento... @@ -5882,3 +5925,4 @@ STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) +STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING} From f9ab492e645288d308d0406fbb4235f3da8bc88e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 15 Apr 2025 19:39:55 +0100 Subject: [PATCH 047/572] Codechange: Pass HouseSpec by reference to IsHouseSpecValid(). --- src/newgrf.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index ee440aa464..4ec1f05dc3 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -945,40 +945,40 @@ void FinaliseCargoArray() * @param filename The filename of the newgrf this house was defined in. * @return Whether the given housespec is valid. */ -static bool IsHouseSpecValid(HouseSpec *hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const std::string &filename) +static bool IsHouseSpecValid(HouseSpec &hs, const HouseSpec *next1, const HouseSpec *next2, const HouseSpec *next3, const std::string &filename) { - if ((hs->building_flags.Any(BUILDING_HAS_2_TILES) && + if ((hs.building_flags.Any(BUILDING_HAS_2_TILES) && (next1 == nullptr || !next1->enabled || next1->building_flags.Any(BUILDING_HAS_1_TILE))) || - (hs->building_flags.Any(BUILDING_HAS_4_TILES) && + (hs.building_flags.Any(BUILDING_HAS_4_TILES) && (next2 == nullptr || !next2->enabled || next2->building_flags.Any(BUILDING_HAS_1_TILE) || next3 == nullptr || !next3->enabled || next3->building_flags.Any(BUILDING_HAS_1_TILE)))) { - hs->enabled = false; - if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} as multitile, but no suitable tiles follow. Disabling house.", filename, hs->grf_prop.local_id); + hs.enabled = false; + if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} as multitile, but no suitable tiles follow. Disabling house.", filename, hs.grf_prop.local_id); return false; } /* Some places sum population by only counting north tiles. Other places use all tiles causing desyncs. * As the newgrf specs define population to be zero for non-north tiles, we just disable the offending house. * If you want to allow non-zero populations somewhen, make sure to sum the population of all tiles in all places. */ - if ((hs->building_flags.Any(BUILDING_HAS_2_TILES) && next1->population != 0) || - (hs->building_flags.Any(BUILDING_HAS_4_TILES) && (next2->population != 0 || next3->population != 0))) { - hs->enabled = false; - if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines multitile house {} with non-zero population on additional tiles. Disabling house.", filename, hs->grf_prop.local_id); + if ((hs.building_flags.Any(BUILDING_HAS_2_TILES) && next1->population != 0) || + (hs.building_flags.Any(BUILDING_HAS_4_TILES) && (next2->population != 0 || next3->population != 0))) { + hs.enabled = false; + if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines multitile house {} with non-zero population on additional tiles. Disabling house.", filename, hs.grf_prop.local_id); return false; } /* Substitute type is also used for override, and having an override with a different size causes crashes. * This check should only be done for NewGRF houses because grf_prop.subst_id is not set for original houses.*/ - if (!filename.empty() && (hs->building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs->grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) { - hs->enabled = false; - Debug(grf, 1, "FinaliseHouseArray: {} defines house {} with different house size then it's substitute type. Disabling house.", filename, hs->grf_prop.local_id); + if (!filename.empty() && (hs.building_flags & BUILDING_HAS_1_TILE) != (HouseSpec::Get(hs.grf_prop.subst_id)->building_flags & BUILDING_HAS_1_TILE)) { + hs.enabled = false; + Debug(grf, 1, "FinaliseHouseArray: {} defines house {} with different house size then it's substitute type. Disabling house.", filename, hs.grf_prop.local_id); return false; } /* Make sure that additional parts of multitile houses are not available. */ - if (!hs->building_flags.Any(BUILDING_HAS_1_TILE) && (hs->building_availability & HZ_ZONALL) != 0 && (hs->building_availability & HZ_CLIMALL) != 0) { - hs->enabled = false; - if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs->grf_prop.local_id); + if (!hs.building_flags.Any(BUILDING_HAS_1_TILE) && (hs.building_availability & HZ_ZONALL) != 0 && (hs.building_availability & HZ_CLIMALL) != 0) { + hs.enabled = false; + if (!filename.empty()) Debug(grf, 1, "FinaliseHouseArray: {} defines house {} without a size but marked it as available. Disabling house.", filename, hs.grf_prop.local_id); return false; } @@ -1040,7 +1040,7 @@ static void FinaliseHouseArray() const HouseSpec *next2 = (i + 2 < num_houses ? file.housespec[i + 2].get() : nullptr); const HouseSpec *next3 = (i + 3 < num_houses ? file.housespec[i + 3].get() : nullptr); - if (!IsHouseSpecValid(hs, next1, next2, next3, file.filename)) continue; + if (!IsHouseSpecValid(*hs, next1, next2, next3, file.filename)) continue; _house_mngr.SetEntitySpec(hs); } @@ -1054,7 +1054,7 @@ static void FinaliseHouseArray() /* We need to check all houses again to we are sure that multitile houses * did get consecutive IDs and none of the parts are missing. */ - if (!IsHouseSpecValid(hs, next1, next2, next3, std::string{})) { + if (!IsHouseSpecValid(*hs, next1, next2, next3, std::string{})) { /* GetHouseNorthPart checks 3 houses that are directly before * it in the house pool. If any of those houses have multi-tile * flags set it assumes it's part of a multitile house. Since From a281ac4674c81cf2bf4b5bc8627a4fb3d9405701 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 15 Apr 2025 19:42:04 +0100 Subject: [PATCH 048/572] Codefix: Information for NewGRF specs remained duplicated after loading. After loading airports+tiles, industries+tiles, houses and objects, their specs are copied from the NewGRF's loading storage to the final global storage. Instead, move the specs to the their new storage, and clear the NewGRF's storage once done. (Stations and RoadStops are different, and the NewGRF's storage is the final storage location.) --- src/newgrf.cpp | 46 ++++++++++++++++++++++++++----------- src/newgrf_airport.cpp | 8 +++---- src/newgrf_airport.h | 2 ++ src/newgrf_airporttiles.cpp | 8 +++---- src/newgrf_airporttiles.h | 2 +- src/newgrf_commons.cpp | 34 +++++++++++++-------------- src/newgrf_commons.h | 12 +++++----- 7 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 4ec1f05dc3..224e6ca6fc 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1027,12 +1027,12 @@ static void FinaliseHouseArray() * On the other hand, why 1930? Just 'fix' the houses with the lowest * minimum introduction date to 0. */ - for (const auto &file : _grf_files) { + for (auto &file : _grf_files) { if (file.housespec.empty()) continue; size_t num_houses = file.housespec.size(); for (size_t i = 0; i < num_houses; i++) { - HouseSpec *hs = file.housespec[i].get(); + auto &hs = file.housespec[i]; if (hs == nullptr) continue; @@ -1042,8 +1042,12 @@ static void FinaliseHouseArray() if (!IsHouseSpecValid(*hs, next1, next2, next3, file.filename)) continue; - _house_mngr.SetEntitySpec(hs); + _house_mngr.SetEntitySpec(std::move(*hs)); } + + /* Won't be used again */ + file.housespec.clear(); + file.housespec.shrink_to_fit(); } for (size_t i = 0; i < HouseSpec::Specs().size(); i++) { @@ -1096,18 +1100,24 @@ static void FinaliseHouseArray() */ static void FinaliseIndustriesArray() { - for (const auto &file : _grf_files) { - for (const auto &indsp : file.industryspec) { + for (auto &file : _grf_files) { + for (auto &indsp : file.industryspec) { if (indsp == nullptr || !indsp->enabled) continue; - _industry_mngr.SetEntitySpec(indsp.get()); + _industry_mngr.SetEntitySpec(std::move(*indsp)); } - for (const auto &indtsp : file.indtspec) { + for (auto &indtsp : file.indtspec) { if (indtsp != nullptr) { - _industile_mngr.SetEntitySpec(indtsp.get()); + _industile_mngr.SetEntitySpec(std::move(*indtsp)); } } + + /* Won't be used again */ + file.industryspec.clear(); + file.industryspec.shrink_to_fit(); + file.indtspec.clear(); + file.indtspec.shrink_to_fit(); } for (auto &indsp : _industry_specs) { @@ -1144,12 +1154,16 @@ static void FinaliseIndustriesArray() */ static void FinaliseObjectsArray() { - for (const auto &file : _grf_files) { + for (auto &file : _grf_files) { for (auto &objectspec : file.objectspec) { if (objectspec != nullptr && objectspec->grf_prop.HasGrfFile() && objectspec->IsEnabled()) { - _object_mngr.SetEntitySpec(objectspec.get()); + _object_mngr.SetEntitySpec(std::move(*objectspec)); } } + + /* Won't be used again */ + file.objectspec.clear(); + file.objectspec.shrink_to_fit(); } ObjectSpec::BindToClasses(); @@ -1162,18 +1176,24 @@ static void FinaliseObjectsArray() */ static void FinaliseAirportsArray() { - for (const auto &file : _grf_files) { + for (auto &file : _grf_files) { for (auto &as : file.airportspec) { if (as != nullptr && as->enabled) { - _airport_mngr.SetEntitySpec(as.get()); + _airport_mngr.SetEntitySpec(std::move(*as)); } } for (auto &ats : file.airtspec) { if (ats != nullptr && ats->enabled) { - _airporttile_mngr.SetEntitySpec(ats.get()); + _airporttile_mngr.SetEntitySpec(std::move(*ats)); } } + + /* Won't be used again */ + file.airportspec.clear(); + file.airportspec.shrink_to_fit(); + file.airtspec.clear(); + file.airtspec.shrink_to_fit(); } } diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index fdd5fc3739..a22e87bb9d 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -134,22 +134,22 @@ void BindAirportSpecs() } -void AirportOverrideManager::SetEntitySpec(AirportSpec *as) +void AirportOverrideManager::SetEntitySpec(AirportSpec &&as) { - uint8_t airport_id = this->AddEntityID(as->grf_prop.local_id, as->grf_prop.grfid, as->grf_prop.subst_id); + uint8_t airport_id = this->AddEntityID(as.grf_prop.local_id, as.grf_prop.grfid, as.grf_prop.subst_id); if (airport_id == this->invalid_id) { GrfMsg(1, "Airport.SetEntitySpec: Too many airports allocated. Ignoring."); return; } - *AirportSpec::GetWithoutOverride(airport_id) = *as; + AirportSpec::specs[airport_id] = std::move(as); /* Now add the overrides. */ for (int i = 0; i < this->max_offset; i++) { AirportSpec *overridden_as = AirportSpec::GetWithoutOverride(i); - if (this->entity_overrides[i] != as->grf_prop.local_id || this->grfid_overrides[i] != as->grf_prop.grfid) continue; + if (this->entity_overrides[i] != AirportSpec::specs[airport_id].grf_prop.local_id || this->grfid_overrides[i] != AirportSpec::specs[airport_id].grf_prop.grfid) continue; overridden_as->grf_prop.override_id = airport_id; overridden_as->enabled = false; diff --git a/src/newgrf_airport.h b/src/newgrf_airport.h index f9faa33921..59e811b80e 100644 --- a/src/newgrf_airport.h +++ b/src/newgrf_airport.h @@ -141,6 +141,8 @@ struct AirportSpec : NewGRFSpecBase { private: static AirportSpec specs[NUM_AIRPORTS]; ///< Specs of the airports. + + friend void AirportOverrideManager::SetEntitySpec(AirportSpec &&as); }; /** Information related to airport classes. */ diff --git a/src/newgrf_airporttiles.cpp b/src/newgrf_airporttiles.cpp index f47e9e4af6..eea0f118c3 100644 --- a/src/newgrf_airporttiles.cpp +++ b/src/newgrf_airporttiles.cpp @@ -66,22 +66,22 @@ void AirportTileSpec::ResetAirportTiles() _airporttile_mngr.ResetOverride(); } -void AirportTileOverrideManager::SetEntitySpec(const AirportTileSpec *airpts) +void AirportTileOverrideManager::SetEntitySpec(AirportTileSpec &&airpts) { - StationGfx airpt_id = this->AddEntityID(airpts->grf_prop.local_id, airpts->grf_prop.grfid, airpts->grf_prop.subst_id); + StationGfx airpt_id = this->AddEntityID(airpts.grf_prop.local_id, airpts.grf_prop.grfid, airpts.grf_prop.subst_id); if (airpt_id == this->invalid_id) { GrfMsg(1, "AirportTile.SetEntitySpec: Too many airport tiles allocated. Ignoring."); return; } - AirportTileSpec::tiles[airpt_id] = *airpts; + AirportTileSpec::tiles[airpt_id] = std::move(airpts); /* Now add the overrides. */ for (int i = 0; i < this->max_offset; i++) { AirportTileSpec *overridden_airpts = &AirportTileSpec::tiles[i]; - if (this->entity_overrides[i] != airpts->grf_prop.local_id || this->grfid_overrides[i] != airpts->grf_prop.grfid) continue; + if (this->entity_overrides[i] != AirportTileSpec::tiles[airpt_id].grf_prop.local_id || this->grfid_overrides[i] != AirportTileSpec::tiles[airpt_id].grf_prop.grfid) continue; overridden_airpts->grf_prop.override_id = airpt_id; overridden_airpts->enabled = false; diff --git a/src/newgrf_airporttiles.h b/src/newgrf_airporttiles.h index 1f2d989c33..68a62d1b07 100644 --- a/src/newgrf_airporttiles.h +++ b/src/newgrf_airporttiles.h @@ -84,7 +84,7 @@ struct AirportTileSpec { private: static AirportTileSpec tiles[NUM_AIRPORTTILES]; - friend void AirportTileOverrideManager::SetEntitySpec(const AirportTileSpec *airpts); + friend void AirportTileOverrideManager::SetEntitySpec(AirportTileSpec &&airpts); }; void AnimateAirportTile(TileIndex tile); diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index 6ed612ca81..a46b5477d6 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -157,9 +157,9 @@ uint16_t OverrideManagerBase::GetSubstituteID(uint16_t entity_id) const * It will find itself the proper slot on which it will go * @param hs HouseSpec read from the grf file, ready for inclusion */ -void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs) +void HouseOverrideManager::SetEntitySpec(HouseSpec &&hs) { - HouseID house_id = this->AddEntityID(hs->grf_prop.local_id, hs->grf_prop.grfid, hs->grf_prop.subst_id); + HouseID house_id = this->AddEntityID(hs.grf_prop.local_id, hs.grf_prop.grfid, hs.grf_prop.subst_id); if (house_id == this->invalid_id) { GrfMsg(1, "House.SetEntitySpec: Too many houses allocated. Ignoring."); @@ -170,13 +170,13 @@ void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs) /* Now that we know we can use the given id, copy the spec to its final destination. */ if (house_id >= house_specs.size()) house_specs.resize(house_id + 1); - house_specs[house_id] = *hs; + house_specs[house_id] = std::move(hs); /* Now add the overrides. */ for (int i = 0; i < this->max_offset; i++) { HouseSpec *overridden_hs = HouseSpec::Get(i); - if (this->entity_overrides[i] != hs->grf_prop.local_id || this->grfid_overrides[i] != hs->grf_prop.grfid) continue; + if (this->entity_overrides[i] != house_specs[house_id].grf_prop.local_id || this->grfid_overrides[i] != house_specs[house_id].grf_prop.grfid) continue; overridden_hs->grf_prop.override_id = house_id; this->entity_overrides[i] = this->invalid_id; @@ -245,18 +245,18 @@ uint16_t IndustryOverrideManager::AddEntityID(uint16_t grf_local_id, uint32_t gr * checking what is available * @param inds Industryspec that comes from the grf decoding process */ -void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds) +void IndustryOverrideManager::SetEntitySpec(IndustrySpec &&inds) { /* First step : We need to find if this industry is already specified in the savegame data. */ - IndustryType ind_id = this->GetID(inds->grf_prop.local_id, inds->grf_prop.grfid); + IndustryType ind_id = this->GetID(inds.grf_prop.local_id, inds.grf_prop.grfid); if (ind_id == this->invalid_id) { /* Not found. * Or it has already been overridden, so you've lost your place. * Or it is a simple substitute. * We need to find a free available slot */ - ind_id = this->AddEntityID(inds->grf_prop.local_id, inds->grf_prop.grfid, inds->grf_prop.subst_id); - inds->grf_prop.override_id = this->invalid_id; // make sure it will not be detected as overridden + ind_id = this->AddEntityID(inds.grf_prop.local_id, inds.grf_prop.grfid, inds.grf_prop.subst_id); + inds.grf_prop.override_id = this->invalid_id; // make sure it will not be detected as overridden } if (ind_id == this->invalid_id) { @@ -265,27 +265,27 @@ void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds) } /* Now that we know we can use the given id, copy the spec to its final destination... */ - _industry_specs[ind_id] = *inds; + _industry_specs[ind_id] = std::move(inds); /* ... and mark it as usable*/ _industry_specs[ind_id].enabled = true; } -void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its) +void IndustryTileOverrideManager::SetEntitySpec(IndustryTileSpec &&its) { - IndustryGfx indt_id = this->AddEntityID(its->grf_prop.local_id, its->grf_prop.grfid, its->grf_prop.subst_id); + IndustryGfx indt_id = this->AddEntityID(its.grf_prop.local_id, its.grf_prop.grfid, its.grf_prop.subst_id); if (indt_id == this->invalid_id) { GrfMsg(1, "IndustryTile.SetEntitySpec: Too many industry tiles allocated. Ignoring."); return; } - _industry_tile_specs[indt_id] = *its; + _industry_tile_specs[indt_id] = std::move(its); /* Now add the overrides. */ for (int i = 0; i < this->max_offset; i++) { IndustryTileSpec *overridden_its = &_industry_tile_specs[i]; - if (this->entity_overrides[i] != its->grf_prop.local_id || this->grfid_overrides[i] != its->grf_prop.grfid) continue; + if (this->entity_overrides[i] != _industry_tile_specs[indt_id].grf_prop.local_id || this->grfid_overrides[i] != _industry_tile_specs[indt_id].grf_prop.grfid) continue; overridden_its->grf_prop.override_id = indt_id; overridden_its->enabled = false; @@ -300,17 +300,17 @@ void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its) * checking what is available * @param spec ObjectSpec that comes from the grf decoding process */ -void ObjectOverrideManager::SetEntitySpec(ObjectSpec *spec) +void ObjectOverrideManager::SetEntitySpec(ObjectSpec &&spec) { /* First step : We need to find if this object is already specified in the savegame data. */ - ObjectType type = this->GetID(spec->grf_prop.local_id, spec->grf_prop.grfid); + ObjectType type = this->GetID(spec.grf_prop.local_id, spec.grf_prop.grfid); if (type == this->invalid_id) { /* Not found. * Or it has already been overridden, so you've lost your place. * Or it is a simple substitute. * We need to find a free available slot */ - type = this->AddEntityID(spec->grf_prop.local_id, spec->grf_prop.grfid, OBJECT_TRANSMITTER); + type = this->AddEntityID(spec.grf_prop.local_id, spec.grf_prop.grfid, OBJECT_TRANSMITTER); } if (type == this->invalid_id) { @@ -322,7 +322,7 @@ void ObjectOverrideManager::SetEntitySpec(ObjectSpec *spec) /* Now that we know we can use the given id, copy the spec to its final destination. */ if (type >= _object_specs.size()) _object_specs.resize(type + 1); - _object_specs[type] = *spec; + _object_specs[type] = std::move(spec); } /** diff --git a/src/newgrf_commons.h b/src/newgrf_commons.h index 37ecc134e7..d553bd6e49 100644 --- a/src/newgrf_commons.h +++ b/src/newgrf_commons.h @@ -210,7 +210,7 @@ public: HouseOverrideManager(uint16_t offset, uint16_t maximum, uint16_t invalid) : OverrideManagerBase(offset, maximum, invalid) {} - void SetEntitySpec(const HouseSpec *hs); + void SetEntitySpec(HouseSpec &&hs); }; @@ -223,7 +223,7 @@ public: uint16_t AddEntityID(uint16_t grf_local_id, uint32_t grfid, uint16_t substitute_id) override; uint16_t GetID(uint16_t grf_local_id, uint32_t grfid) const override; - void SetEntitySpec(IndustrySpec *inds); + void SetEntitySpec(IndustrySpec &&inds); }; @@ -235,7 +235,7 @@ public: IndustryTileOverrideManager(uint16_t offset, uint16_t maximum, uint16_t invalid) : OverrideManagerBase(offset, maximum, invalid) {} - void SetEntitySpec(const IndustryTileSpec *indts); + void SetEntitySpec(IndustryTileSpec &&indts); }; struct AirportSpec; @@ -244,7 +244,7 @@ public: AirportOverrideManager(uint16_t offset, uint16_t maximum, uint16_t invalid) : OverrideManagerBase(offset, maximum, invalid) {} - void SetEntitySpec(AirportSpec *inds); + void SetEntitySpec(AirportSpec &&inds); }; struct AirportTileSpec; @@ -255,7 +255,7 @@ public: AirportTileOverrideManager(uint16_t offset, uint16_t maximum, uint16_t invalid) : OverrideManagerBase(offset, maximum, invalid) {} - void SetEntitySpec(const AirportTileSpec *ats); + void SetEntitySpec(AirportTileSpec &&ats); }; struct ObjectSpec; @@ -266,7 +266,7 @@ public: ObjectOverrideManager(uint16_t offset, uint16_t maximum, uint16_t invalid) : OverrideManagerBase(offset, maximum, invalid) {} - void SetEntitySpec(ObjectSpec *spec); + void SetEntitySpec(ObjectSpec &&spec); }; extern HouseOverrideManager _house_mngr; From 6ea10edef8e5fb56db8cbe95540dbc1da0487650 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 16 Apr 2025 19:43:45 +0100 Subject: [PATCH 049/572] Codechange: Use std::unique_ptrs for handling station cargo display. (#14009) Replaces manual management of raw pointers. --- src/station_gui.cpp | 175 +++++++++++++++++++++----------------------- 1 file changed, 84 insertions(+), 91 deletions(-) diff --git a/src/station_gui.cpp b/src/station_gui.cpp index 160f1d1eb1..fa35efccb5 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -889,9 +889,13 @@ enum class CargoSortType : uint8_t { class CargoSorter { public: + using is_transparent = void; CargoSorter(CargoSortType t = CargoSortType::StationID, SortOrder o = SO_ASCENDING) : type(t), order(o) {} CargoSortType GetSortType() {return this->type;} - bool operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; + bool operator()(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const; + bool operator()(const CargoDataEntry &cd1, const std::unique_ptr &cd2) const { return this->operator()(cd1, *cd2); } + bool operator()(const std::unique_ptr &cd1, const CargoDataEntry &cd2) const { return this->operator()(*cd1, cd2); } + bool operator()(const std::unique_ptr &cd1, const std::unique_ptr &cd2) const { return this->operator()(*cd1, *cd2); } private: CargoSortType type; @@ -899,11 +903,11 @@ private: template bool SortId(Tid st1, Tid st2) const; - bool SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const; - bool SortStation (StationID st1, StationID st2) const; + bool SortCount(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const; + bool SortStation(StationID st1, StationID st2) const; }; -typedef std::set CargoDataSet; +typedef std::set, CargoSorter> CargoDataSet; /** * A cargo data entry representing one possible row in the station view window's @@ -920,7 +924,7 @@ public: * @param station ID of the station for which an entry shall be created or retrieved * @return a child entry associated with the given station. */ - CargoDataEntry *InsertOrRetrieve(StationID station) + CargoDataEntry &InsertOrRetrieve(StationID station) { return this->InsertOrRetrieve(station); } @@ -930,7 +934,7 @@ public: * @param cargo type of the cargo for which an entry shall be created or retrieved * @return a child entry associated with the given cargo. */ - CargoDataEntry *InsertOrRetrieve(CargoType cargo) + CargoDataEntry &InsertOrRetrieve(CargoType cargo) { return this->InsertOrRetrieve(cargo); } @@ -944,7 +948,7 @@ public: void Remove(StationID station) { CargoDataEntry t(station); - this->Remove(&t); + this->Remove(t); } /** @@ -954,7 +958,7 @@ public: void Remove(CargoType cargo) { CargoDataEntry t(cargo); - this->Remove(&t); + this->Remove(t); } /** @@ -965,7 +969,7 @@ public: CargoDataEntry *Retrieve(StationID station) const { CargoDataEntry t(station); - return this->Retrieve(this->children->find(&t)); + return this->Retrieve(this->children->find(t)); } /** @@ -976,7 +980,7 @@ public: CargoDataEntry *Retrieve(CargoType cargo) const { CargoDataEntry t(cargo); - return this->Retrieve(this->children->find(&t)); + return this->Retrieve(this->children->find(t)); } void Resort(CargoSortType type, SortOrder order); @@ -1027,19 +1031,19 @@ public: void SetTransfers(bool value) { this->transfers = value; } void Clear(); -private: CargoDataEntry(StationID station, uint count, CargoDataEntry *parent); CargoDataEntry(CargoType cargo, uint count, CargoDataEntry *parent); CargoDataEntry(StationID station); CargoDataEntry(CargoType cargo); +private: CargoDataEntry *Retrieve(CargoDataSet::iterator i) const; template - CargoDataEntry *InsertOrRetrieve(Tid s); + CargoDataEntry &InsertOrRetrieve(Tid s); - void Remove(CargoDataEntry *entry); + void Remove(CargoDataEntry &entry); void IncrementSize(); CargoDataEntry *parent; ///< the parent of this entry. @@ -1052,7 +1056,7 @@ private: }; uint num_children; ///< the number of subentries belonging to this entry. uint count; ///< sum of counts of all children or amount of cargo for this entry. - CargoDataSet *children; ///< the children of this entry. + std::unique_ptr children; ///< the children of this entry. }; CargoDataEntry::CargoDataEntry() : @@ -1060,7 +1064,7 @@ CargoDataEntry::CargoDataEntry() : station(StationID::Invalid()), num_children(0), count(0), - children(new CargoDataSet(CargoSorter(CargoSortType::CargoType))) + children(std::make_unique(CargoSorter(CargoSortType::CargoType))) {} CargoDataEntry::CargoDataEntry(CargoType cargo, uint count, CargoDataEntry *parent) : @@ -1068,7 +1072,7 @@ CargoDataEntry::CargoDataEntry(CargoType cargo, uint count, CargoDataEntry *pare cargo(cargo), num_children(0), count(count), - children(new CargoDataSet) + children(std::make_unique()) {} CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *parent) : @@ -1076,7 +1080,7 @@ CargoDataEntry::CargoDataEntry(StationID station, uint count, CargoDataEntry *pa station(station), num_children(0), count(count), - children(new CargoDataSet) + children(std::make_unique()) {} CargoDataEntry::CargoDataEntry(StationID station) : @@ -1098,7 +1102,6 @@ CargoDataEntry::CargoDataEntry(CargoType cargo) : CargoDataEntry::~CargoDataEntry() { this->Clear(); - delete this->children; } /** @@ -1106,13 +1109,7 @@ CargoDataEntry::~CargoDataEntry() */ void CargoDataEntry::Clear() { - if (this->children != nullptr) { - for (auto &it : *this->children) { - assert(it != this); - delete it; - } - this->children->clear(); - } + if (this->children != nullptr) this->children->clear(); if (this->parent != nullptr) this->parent->count -= this->count; this->count = 0; this->num_children = 0; @@ -1124,13 +1121,10 @@ void CargoDataEntry::Clear() * which only contains the ID of the entry to be removed. In this case child is * not deleted. */ -void CargoDataEntry::Remove(CargoDataEntry *entry) +void CargoDataEntry::Remove(CargoDataEntry &entry) { CargoDataSet::iterator i = this->children->find(entry); - if (i != this->children->end()) { - delete *i; - this->children->erase(i); - } + if (i != this->children->end()) this->children->erase(i); } /** @@ -1140,17 +1134,16 @@ void CargoDataEntry::Remove(CargoDataEntry *entry) * @return the new or retrieved subentry */ template -CargoDataEntry *CargoDataEntry::InsertOrRetrieve(Tid child_id) +CargoDataEntry &CargoDataEntry::InsertOrRetrieve(Tid child_id) { CargoDataEntry tmp(child_id); - CargoDataSet::iterator i = this->children->find(&tmp); + CargoDataSet::iterator i = this->children->find(tmp); if (i == this->children->end()) { IncrementSize(); - return *(this->children->insert(new CargoDataEntry(child_id, 0, this)).first); + return **(this->children->insert(std::make_unique(child_id, 0, this)).first); } else { - CargoDataEntry *ret = *i; assert(this->children->value_comp().GetSortType() != CargoSortType::Count); - return ret; + return **i; } } @@ -1176,9 +1169,9 @@ void CargoDataEntry::IncrementSize() void CargoDataEntry::Resort(CargoSortType type, SortOrder order) { - CargoDataSet *new_subs = new CargoDataSet(this->children->begin(), this->children->end(), CargoSorter(type, order)); - delete this->children; - this->children = new_subs; + auto new_children = std::make_unique(CargoSorter(type, order)); + new_children->merge(*this->children); + this->children = std::move(new_children); } CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const @@ -1187,21 +1180,21 @@ CargoDataEntry *CargoDataEntry::Retrieve(CargoDataSet::iterator i) const return nullptr; } else { assert(this->children->value_comp().GetSortType() != CargoSortType::Count); - return *i; + return i->get(); } } -bool CargoSorter::operator()(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const +bool CargoSorter::operator()(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const { switch (this->type) { case CargoSortType::StationID: - return this->SortId(cd1->GetStation(), cd2->GetStation()); + return this->SortId(cd1.GetStation(), cd2.GetStation()); case CargoSortType::CargoType: - return this->SortId(cd1->GetCargo(), cd2->GetCargo()); + return this->SortId(cd1.GetCargo(), cd2.GetCargo()); case CargoSortType::Count: return this->SortCount(cd1, cd2); case CargoSortType::StationString: - return this->SortStation(cd1->GetStation(), cd2->GetStation()); + return this->SortStation(cd1.GetStation(), cd2.GetStation()); default: NOT_REACHED(); } @@ -1213,12 +1206,12 @@ bool CargoSorter::SortId(Tid st1, Tid st2) const return (this->order == SO_ASCENDING) ? st1 < st2 : st2 < st1; } -bool CargoSorter::SortCount(const CargoDataEntry *cd1, const CargoDataEntry *cd2) const +bool CargoSorter::SortCount(const CargoDataEntry &cd1, const CargoDataEntry &cd2) const { - uint c1 = cd1->GetCount(); - uint c2 = cd2->GetCount(); + uint c1 = cd1.GetCount(); + uint c2 = cd2.GetCount(); if (c1 == c2) { - return this->SortStation(cd1->GetStation(), cd2->GetStation()); + return this->SortStation(cd1.GetStation(), cd2.GetStation()); } else if (this->order == SO_ASCENDING) { return c1 < c2; } else { @@ -1392,25 +1385,25 @@ struct StationViewWindow : public Window { switch (groupings[i]) { case GR_CARGO: assert(i == 0); - data = data->InsertOrRetrieve(cargo); + data = &data->InsertOrRetrieve(cargo); data->SetTransfers(source != this->window_number); expand = expand->Retrieve(cargo); break; case GR_SOURCE: if (auto_distributed || source != this->window_number) { - data = data->InsertOrRetrieve(source); + data = &data->InsertOrRetrieve(source); expand = expand->Retrieve(source); } break; case GR_NEXT: if (auto_distributed) { - data = data->InsertOrRetrieve(next); + data = &data->InsertOrRetrieve(next); expand = expand->Retrieve(next); } break; case GR_DESTINATION: if (auto_distributed) { - data = data->InsertOrRetrieve(dest); + data = &data->InsertOrRetrieve(dest); expand = expand->Retrieve(dest); } break; @@ -1498,7 +1491,7 @@ struct StationViewWindow : public Window { /* Draw waiting cargo. */ NWidgetBase *nwi = this->GetWidget(WID_SV_WAITING); Rect waiting_rect = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect); - this->DrawEntries(&cargo, waiting_rect, pos, maxrows, 0); + this->DrawEntries(cargo, waiting_rect, pos, maxrows, 0); scroll_to_row = INT_MAX; } } @@ -1521,20 +1514,20 @@ struct StationViewWindow : public Window { void RecalcDestinations(CargoType cargo) { const Station *st = Station::Get(this->window_number); - CargoDataEntry *entry = cached_destinations.InsertOrRetrieve(cargo); - entry->Clear(); + CargoDataEntry &entry = cached_destinations.InsertOrRetrieve(cargo); + entry.Clear(); if (!st->goods[cargo].HasData()) return; for (const auto &it : st->goods[cargo].GetData().flows) { StationID from = it.first; - CargoDataEntry *source_entry = entry->InsertOrRetrieve(from); + CargoDataEntry &source_entry = entry.InsertOrRetrieve(from); uint32_t prev_count = 0; for (const auto &flow_it : *it.second.GetShares()) { StationID via = flow_it.second; - CargoDataEntry *via_entry = source_entry->InsertOrRetrieve(via); + CargoDataEntry &via_entry = source_entry.InsertOrRetrieve(via); if (via == this->window_number) { - via_entry->InsertOrRetrieve(via)->Update(flow_it.first - prev_count); + via_entry.InsertOrRetrieve(via).Update(flow_it.first - prev_count); } else { EstimateDestinations(cargo, from, via, flow_it.first - prev_count, via_entry); } @@ -1552,7 +1545,7 @@ struct StationViewWindow : public Window { * @param count Size of the batch of cargo. * @param dest CargoDataEntry to save the results in. */ - void EstimateDestinations(CargoType cargo, StationID source, StationID next, uint count, CargoDataEntry *dest) + void EstimateDestinations(CargoType cargo, StationID source, StationID next, uint count, CargoDataEntry &dest) { if (Station::IsValidID(next) && Station::IsValidID(source)) { GoodsEntry &ge = Station::Get(next)->goods[cargo]; @@ -1565,19 +1558,19 @@ struct StationViewWindow : public Window { const FlowStat::SharesMap *shares = map_it->second.GetShares(); uint32_t prev_count = 0; for (FlowStat::SharesMap::const_iterator i = shares->begin(); i != shares->end(); ++i) { - tmp.InsertOrRetrieve(i->second)->Update(i->first - prev_count); + tmp.InsertOrRetrieve(i->second).Update(i->first - prev_count); prev_count = i->first; } } if (tmp.GetCount() == 0) { - dest->InsertOrRetrieve(StationID::Invalid())->Update(count); + dest.InsertOrRetrieve(StationID::Invalid()).Update(count); } else { uint sum_estimated = 0; while (sum_estimated < count) { for (CargoDataSet::iterator i = tmp.Begin(); i != tmp.End() && sum_estimated < count; ++i) { - CargoDataEntry *child = *i; - uint estimate = DivideApprox(child->GetCount() * count, tmp.GetCount()); + CargoDataEntry &child = **i; + uint estimate = DivideApprox(child.GetCount() * count, tmp.GetCount()); if (estimate == 0) estimate = 1; sum_estimated += estimate; @@ -1587,10 +1580,10 @@ struct StationViewWindow : public Window { } if (estimate > 0) { - if (child->GetStation() == next) { - dest->InsertOrRetrieve(next)->Update(estimate); + if (child.GetStation() == next) { + dest.InsertOrRetrieve(next).Update(estimate); } else { - EstimateDestinations(cargo, source, child->GetStation(), estimate, dest); + EstimateDestinations(cargo, source, child.GetStation(), estimate, dest); } } } @@ -1598,7 +1591,7 @@ struct StationViewWindow : public Window { } } } else { - dest->InsertOrRetrieve(StationID::Invalid())->Update(count); + dest.InsertOrRetrieve(StationID::Invalid()).Update(count); } } @@ -1618,8 +1611,8 @@ struct StationViewWindow : public Window { for (FlowStat::SharesMap::const_iterator flow_it = shares->begin(); flow_it != shares->end(); ++flow_it) { const CargoDataEntry *via_entry = source_entry->Retrieve(flow_it->second); for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End(); ++dest_it) { - CargoDataEntry *dest_entry = *dest_it; - ShowCargo(entry, cargo, from, flow_it->second, dest_entry->GetStation(), dest_entry->GetCount()); + CargoDataEntry &dest_entry = **dest_it; + ShowCargo(entry, cargo, from, flow_it->second, dest_entry.GetStation(), dest_entry.GetCount()); } } } @@ -1652,7 +1645,7 @@ struct StationViewWindow : public Window { uint remaining = cp->Count(); for (CargoDataSet::iterator dest_it = via_entry->Begin(); dest_it != via_entry->End();) { - CargoDataEntry *dest_entry = *dest_it; + CargoDataEntry &dest_entry = **dest_it; /* Advance iterator here instead of in the for statement to test whether this is the last entry */ ++dest_it; @@ -1664,10 +1657,10 @@ struct StationViewWindow : public Window { * not matching GoodsEntry::TotalCount() */ val = remaining; } else { - val = std::min(remaining, DivideApprox(cp->Count() * dest_entry->GetCount(), via_entry->GetCount())); + val = std::min(remaining, DivideApprox(cp->Count() * dest_entry.GetCount(), via_entry->GetCount())); remaining -= val; } - this->ShowCargo(entry, cargo, cp->GetFirstStation(), next, dest_entry->GetStation(), val); + this->ShowCargo(entry, cargo, cp->GetFirstStation(), next, dest_entry.GetStation(), val); } } this->ShowCargo(entry, cargo, NEW_STATION, NEW_STATION, NEW_STATION, packets.ReservedCount()); @@ -1701,16 +1694,16 @@ struct StationViewWindow : public Window { * Mark a specific row, characterized by its CargoDataEntry, as expanded. * @param entry The row to be marked as expanded. */ - void SetDisplayedRow(const CargoDataEntry *entry) + void SetDisplayedRow(const CargoDataEntry &entry) { std::list stations; - const CargoDataEntry *parent = entry->GetParent(); + const CargoDataEntry *parent = entry.GetParent(); if (parent->GetParent() == nullptr) { - this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, entry->GetCargo())); + this->displayed_rows.push_back(RowDisplay(&this->expanded_rows, entry.GetCargo())); return; } - StationID next = entry->GetStation(); + StationID next = entry.GetStation(); while (parent->GetParent()->GetParent() != nullptr) { stations.push_back(parent->GetStation()); parent = parent->GetParent(); @@ -1764,9 +1757,9 @@ struct StationViewWindow : public Window { * @param column The "column" the entry will be shown in. * @return either STR_STATION_VIEW_VIA or STR_STATION_VIEW_NONSTOP. */ - StringID SearchNonStop(CargoDataEntry *cd, StationID station, int column) + StringID SearchNonStop(CargoDataEntry &cd, StationID station, int column) { - CargoDataEntry *parent = cd->GetParent(); + CargoDataEntry *parent = cd.GetParent(); for (int i = column - 1; i > 0; --i) { if (this->groupings[i] == GR_DESTINATION) { if (parent->GetStation() == station) { @@ -1779,9 +1772,9 @@ struct StationViewWindow : public Window { } if (this->groupings[column + 1] == GR_DESTINATION) { - CargoDataSet::iterator begin = cd->Begin(); - CargoDataSet::iterator end = cd->End(); - if (begin != end && ++(cd->Begin()) == end && (*(begin))->GetStation() == station) { + CargoDataSet::iterator begin = cd.Begin(); + CargoDataSet::iterator end = cd.End(); + if (begin != end && ++(cd.Begin()) == end && (*(begin))->GetStation() == station) { return STR_STATION_VIEW_NONSTOP; } else { return STR_STATION_VIEW_VIA; @@ -1801,20 +1794,20 @@ struct StationViewWindow : public Window { * @param cargo Current cargo being drawn (if cargo column has been passed). * @return row (in "pos" counting) after the one we have last drawn to. */ - int DrawEntries(CargoDataEntry *entry, const Rect &r, int pos, int maxrows, int column, CargoType cargo = INVALID_CARGO) + int DrawEntries(CargoDataEntry &entry, const Rect &r, int pos, int maxrows, int column, CargoType cargo = INVALID_CARGO) { if (this->sortings[column] == CargoSortType::AsGrouping) { if (this->groupings[column] != GR_CARGO) { - entry->Resort(CargoSortType::StationString, this->sort_orders[column]); + entry.Resort(CargoSortType::StationString, this->sort_orders[column]); } } else { - entry->Resort(CargoSortType::Count, this->sort_orders[column]); + entry.Resort(CargoSortType::Count, this->sort_orders[column]); } - for (CargoDataSet::iterator i = entry->Begin(); i != entry->End(); ++i) { - CargoDataEntry *cd = *i; + for (CargoDataSet::iterator i = entry.Begin(); i != entry.End(); ++i) { + CargoDataEntry &cd = **i; Grouping grouping = this->groupings[column]; - if (grouping == GR_CARGO) cargo = cd->GetCargo(); + if (grouping == GR_CARGO) cargo = cd.GetCargo(); bool auto_distributed = _settings_game.linkgraph.GetDistributionType(cargo) != DT_MANUAL; if (pos > -maxrows && pos <= 0) { @@ -1823,10 +1816,10 @@ struct StationViewWindow : public Window { int y = r.top - pos * GetCharacterHeight(FS_NORMAL); if (this->groupings[column] == GR_CARGO) { str = STR_STATION_VIEW_WAITING_CARGO; - DrawCargoIcons(cd->GetCargo(), cd->GetCount(), r.left + this->expand_shrink_width, r.right - this->expand_shrink_width, y); + DrawCargoIcons(cd.GetCargo(), cd.GetCount(), r.left + this->expand_shrink_width, r.right - this->expand_shrink_width, y); } else { if (!auto_distributed) grouping = GR_SOURCE; - station = cd->GetStation(); + station = cd.GetStation(); str = this->GetGroupingString(grouping, station); if (grouping == GR_NEXT && str == STR_STATION_VIEW_VIA) str = this->SearchNonStop(cd, station, column); @@ -1839,11 +1832,11 @@ struct StationViewWindow : public Window { Rect text = r.Indent(column * WidgetDimensions::scaled.hsep_indent, rtl).Indent(this->expand_shrink_width, !rtl); Rect shrink = r.WithWidth(this->expand_shrink_width, !rtl); - DrawString(text.left, text.right, y, GetString(str, cargo, cd->GetCount(), station)); + DrawString(text.left, text.right, y, GetString(str, cargo, cd.GetCount(), station)); if (column < NUM_COLUMNS - 1) { const char *sym = nullptr; - if (cd->GetNumChildren() > 0) { + if (cd.GetNumChildren() > 0) { sym = "-"; } else if (auto_distributed && str != STR_STATION_VIEW_RESERVED) { sym = "+"; @@ -1852,7 +1845,7 @@ struct StationViewWindow : public Window { const GoodsEntry &ge = Station::Get(this->window_number)->goods[cargo]; if (ge.HasData()) { const StationCargoList &cargo_list = ge.GetData().cargo; - if (grouping == GR_CARGO && (cargo_list.ReservedCount() > 0 || cd->HasTransfers())) { + if (grouping == GR_CARGO && (cargo_list.ReservedCount() > 0 || cd.HasTransfers())) { sym = "+"; } } From ea0817390f1999a6867517b5ec466e5b1e47eca9 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 15 Apr 2025 23:07:24 +0100 Subject: [PATCH 050/572] Codechange: Use EnumBitSet for CzechAllowFlags. --- src/table/townname.h | 139 ++++++++++++++++++++++--------------------- src/townname.cpp | 4 +- 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/src/table/townname.h b/src/table/townname.h index e2ff9279be..149c528efa 100644 --- a/src/table/townname.h +++ b/src/table/townname.h @@ -1727,14 +1727,15 @@ static const char * const _name_czech_patmod[][3] = { /* This way the substantive can choose only some adjectives/endings: * At least one of these flags must be satisfied: */ -enum CzechAllow : uint8_t { - CZA_SHORT = 1, - CZA_MIDDLE = 2, - CZA_LONG = 4, - CZA_ALL = CZA_SHORT | CZA_MIDDLE | CZA_LONG, +enum class CzechAllowFlag : uint8_t { + Short, + Middle, + Long, }; -DECLARE_ENUM_AS_BIT_SET(CzechAllow) +using CzechAllowFlags = EnumBitSet; + +static constexpr CzechAllowFlags CZA_ALL = {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}; /* All these flags must be satisfied (in the stem->others direction): */ enum CzechChoose : uint8_t { @@ -1749,7 +1750,7 @@ DECLARE_ENUM_AS_BIT_SET(CzechChoose) struct CzechNameSubst { CzechGender gender; - CzechAllow allow; + CzechAllowFlags allow; CzechChoose choose; const char *name; }; @@ -1834,48 +1835,48 @@ static const CzechNameSubst _name_czech_subst_full[] = { /* TODO: More stems needed. --pasky */ static const CzechNameSubst _name_czech_subst_stem[] = { - { CZG_SMASC, CZA_MIDDLE, CZC_COLOR, "Kostel" }, - { CZG_SMASC, CZA_MIDDLE, CZC_COLOR, "Kl\u00e1\u0161ter" }, - { CZG_SMASC, CZA_SHORT, CZC_COLOR, "Lhot" }, - { CZG_SFEM, CZA_SHORT, CZC_COLOR, "Lhot" }, - { CZG_SFEM, CZA_SHORT, CZC_COLOR, "Hur" }, - { CZG_FREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Sedl" }, - { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_COLOR, "Hrad" }, - { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Pras" }, - { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Ba\u017e" }, - { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "Tes" }, - { CZG_NFREE, CZA_MIDDLE, CZC_NONE, "U\u017e" }, - { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_POSTFIX, "B\u0159" }, - { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Vod" }, - { CZG_NFREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Jan" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Prach" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Kunr" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Strak" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "V\u00edt" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Vy\u0161" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "\u017dat" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "\u017der" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "St\u0159ed" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Harv" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Pruh" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Tach" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "P\u00edsn" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Jin" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Jes" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Jar" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Sok" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Hod" }, - { CZG_NFREE, CZA_LONG, CZC_NONE, "Net" }, - { CZG_FREE, CZA_LONG, CZC_NONE, "Pra\u017e" }, - { CZG_FREE, CZA_LONG, CZC_NONE, "Nerat" }, - { CZG_FREE, CZA_LONG, CZC_NONE, "Kral" }, - { CZG_FREE, CZA_LONG, CZC_NONE, "Hut" }, - { CZG_FREE, CZA_LONG, CZC_NOPOSTFIX, "Pan" }, - { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_NOPOSTFIX, "Odst\u0159ed" }, - { CZG_FREE, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_COLOR, "Mrat" }, - { CZG_FREE, CZA_LONG, CZC_COLOR, "Hlav" }, - { CZG_FREE, CZA_SHORT | CZA_MIDDLE, CZC_NONE, "M\u011b\u0159" }, - { CZG_FREE, CZA_MIDDLE | CZA_LONG, CZC_NONE, "Lip" }, + { CZG_SMASC, { CzechAllowFlag::Middle }, CZC_COLOR, "Kostel" }, + { CZG_SMASC, { CzechAllowFlag::Middle }, CZC_COLOR, "Kl\u00e1\u0161ter" }, + { CZG_SMASC, {CzechAllowFlag::Short }, CZC_COLOR, "Lhot" }, + { CZG_SFEM, {CzechAllowFlag::Short }, CZC_COLOR, "Lhot" }, + { CZG_SFEM, {CzechAllowFlag::Short }, CZC_COLOR, "Hur" }, + { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Sedl" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_COLOR, "Hrad" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Pras" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Ba\u017e" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Tes" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "U\u017e" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_POSTFIX, "B\u0159" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Vod" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Jan" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Prach" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Kunr" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Strak" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "V\u00edt" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Vy\u0161" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "\u017dat" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "\u017der" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "St\u0159ed" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Harv" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Pruh" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Tach" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "P\u00edsn" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jin" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jes" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jar" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Sok" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Hod" }, + { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Net" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Pra\u017e" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Nerat" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Kral" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Hut" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_NOPOSTFIX, "Pan" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NOPOSTFIX, "Odst\u0159ed" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_COLOR, "Mrat" }, + { CZG_FREE, { CzechAllowFlag::Long}, CZC_COLOR, "Hlav" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_NONE, "M\u011b\u0159" }, + { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Lip" }, }; /* Optional postfix inserted between stem and ending. */ @@ -1887,26 +1888,26 @@ static const char * const _name_czech_subst_postfix[] = { /* This array must have the both neutral genders at the end! */ static const CzechNameSubst _name_czech_subst_ending[] = { - { CZG_SMASC, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "ec" }, - { CZG_SMASC, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "\u00edn" }, - { CZG_SMASC, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "ov" }, - { CZG_SMASC, CZA_SHORT | CZA_LONG, CZC_ANY, "kov" }, - { CZG_SMASC, CZA_LONG, CZC_POSTFIX, "\u00edn" }, - { CZG_SMASC, CZA_LONG, CZC_POSTFIX, "n\u00edk" }, - { CZG_SMASC, CZA_LONG, CZC_ANY, "burk" }, - { CZG_SFEM, CZA_SHORT, CZC_ANY, "ka" }, - { CZG_SFEM, CZA_MIDDLE, CZC_ANY, "inka" }, - { CZG_SFEM, CZA_MIDDLE, CZC_ANY, "n\u00e1" }, - { CZG_SFEM, CZA_LONG, CZC_ANY, "ava" }, - { CZG_PMASC, CZA_LONG, CZC_POSTFIX, "\u00edky" }, - { CZG_PMASC, CZA_LONG, CZC_ANY, "upy" }, - { CZG_PMASC, CZA_LONG, CZC_ANY, "olupy" }, - { CZG_PFEM, CZA_LONG, CZC_ANY, "avy" }, - { CZG_PFEM, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "ice" }, - { CZG_PFEM, CZA_SHORT | CZA_MIDDLE | CZA_LONG, CZC_ANY, "i\u010dky" }, - { CZG_PNEUT, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "na" }, - { CZG_SNEUT, CZA_SHORT | CZA_MIDDLE, CZC_ANY, "no" }, - { CZG_SNEUT, CZA_LONG, CZC_ANY, "i\u0161t\u011b" }, + { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_ANY, "ec" }, + { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_ANY, "\u00edn" }, + { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_ANY, "ov" }, + { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Long}, CZC_ANY, "kov" }, + { CZG_SMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "\u00edn" }, + { CZG_SMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "n\u00edk" }, + { CZG_SMASC, { CzechAllowFlag::Long}, CZC_ANY, "burk" }, + { CZG_SFEM, {CzechAllowFlag::Short }, CZC_ANY, "ka" }, + { CZG_SFEM, { CzechAllowFlag::Middle }, CZC_ANY, "inka" }, + { CZG_SFEM, { CzechAllowFlag::Middle }, CZC_ANY, "n\u00e1" }, + { CZG_SFEM, { CzechAllowFlag::Long}, CZC_ANY, "ava" }, + { CZG_PMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "\u00edky" }, + { CZG_PMASC, { CzechAllowFlag::Long}, CZC_ANY, "upy" }, + { CZG_PMASC, { CzechAllowFlag::Long}, CZC_ANY, "olupy" }, + { CZG_PFEM, { CzechAllowFlag::Long}, CZC_ANY, "avy" }, + { CZG_PFEM, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_ANY, "ice" }, + { CZG_PFEM, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_ANY, "i\u010dky" }, + { CZG_PNEUT, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_ANY, "na" }, + { CZG_SNEUT, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_ANY, "no" }, + { CZG_SNEUT, { CzechAllowFlag::Long}, CZC_ANY, "i\u0161t\u011b" }, }; static const char * const _name_czech_suffix[] = { diff --git a/src/townname.cpp b/src/townname.cpp index b19bfef79e..7f118db394 100644 --- a/src/townname.cpp +++ b/src/townname.cpp @@ -603,7 +603,7 @@ static void MakeCzechTownName(StringBuilder &builder, uint32_t seed) /* The select criteria. */ CzechGender gender; CzechChoose choose; - CzechAllow allow; + CzechAllowFlags allow; if (do_prefix) prefix = SeedModChance(5, std::size(_name_czech_adj) * 12, seed) / 12; if (do_suffix) suffix = SeedModChance(7, std::size(_name_czech_suffix), seed); @@ -671,7 +671,7 @@ static void MakeCzechTownName(StringBuilder &builder, uint32_t seed) for (ending = ending_start; ending <= ending_stop; ending++) { const CzechNameSubst *e = &_name_czech_subst_ending[ending]; - if ((e->choose & choose) == choose && (e->allow & allow) != 0) { + if ((e->choose & choose) == choose && e->allow.Any(allow)) { map[i++] = ending; } } From 378ea52ac60a782e1aeaa3863adc46534ad90a5f Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Tue, 15 Apr 2025 23:17:41 +0100 Subject: [PATCH 051/572] Codechange: Use EnumBitSet for CzechChooseFlags. --- src/table/townname.h | 164 +++++++++++++++++++++---------------------- src/townname.cpp | 10 +-- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/src/table/townname.h b/src/table/townname.h index 149c528efa..685e888a97 100644 --- a/src/table/townname.h +++ b/src/table/townname.h @@ -1738,26 +1738,26 @@ using CzechAllowFlags = EnumBitSet; static constexpr CzechAllowFlags CZA_ALL = {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}; /* All these flags must be satisfied (in the stem->others direction): */ -enum CzechChoose : uint8_t { - CZC_NONE = 0, // No requirements. - CZC_COLOR = 1, - CZC_POSTFIX = 2, // Matched if postfix was inserted. - CZC_NOPOSTFIX = 4, // Matched if no postfix was inserted. - CZC_ANY = CZC_COLOR | CZC_POSTFIX | CZC_NOPOSTFIX, +enum class CzechChooseFlag : uint8_t { + Colour, + Postfix, // Matched if postfix was inserted. + NoPostfix, // Matched if no postfix was inserted. }; -DECLARE_ENUM_AS_BIT_SET(CzechChoose) +using CzechChooseFlags = EnumBitSet; + +static constexpr CzechChooseFlags CZC_ANY = {CzechChooseFlag::Colour, CzechChooseFlag::Postfix, CzechChooseFlag::NoPostfix}; struct CzechNameSubst { CzechGender gender; CzechAllowFlags allow; - CzechChoose choose; + CzechChooseFlags choose; const char *name; }; struct CzechNameAdj { CzechPattern pattern; - CzechChoose choose; + CzechChooseFlags choose; const char *name; }; @@ -1792,18 +1792,18 @@ static const CzechNameAdj _name_czech_adj[] = { { CZP_MLADY, CZC_ANY, "Kamenn" }, { CZP_MLADY, CZC_ANY, "Cihlov" }, { CZP_MLADY, CZC_ANY, "Divn" }, - { CZP_MLADY, CZC_COLOR, "\u010cerven" }, - { CZP_MLADY, CZC_COLOR, "\u010cerven" }, - { CZP_MLADY, CZC_COLOR, "\u010cerven" }, - { CZP_MLADY, CZC_COLOR, "Zelen" }, - { CZP_MLADY, CZC_COLOR, "\u017dlut" }, - { CZP_MLADY, CZC_COLOR, "Siv" }, - { CZP_MLADY, CZC_COLOR, "\u0160ed" }, - { CZP_MLADY, CZC_COLOR, "B\u00edl" }, - { CZP_MLADY, CZC_COLOR, "B\u00edl" }, - { CZP_MLADY, CZC_COLOR, "Modr" }, - { CZP_MLADY, CZC_COLOR, "R\u016f\u017eov" }, - { CZP_MLADY, CZC_COLOR, "\u010cern" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u010cerven" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u010cerven" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u010cerven" }, + { CZP_MLADY, CzechChooseFlag::Colour, "Zelen" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u017dlut" }, + { CZP_MLADY, CzechChooseFlag::Colour, "Siv" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u0160ed" }, + { CZP_MLADY, CzechChooseFlag::Colour, "B\u00edl" }, + { CZP_MLADY, CzechChooseFlag::Colour, "B\u00edl" }, + { CZP_MLADY, CzechChooseFlag::Colour, "Modr" }, + { CZP_MLADY, CzechChooseFlag::Colour, "R\u016f\u017eov" }, + { CZP_MLADY, CzechChooseFlag::Colour, "\u010cern" }, { CZP_PRIVL, CZC_ANY, "Kr\u00e1l" }, { CZP_PRIVL, CZC_ANY, "Jan" }, { CZP_PRIVL, CZC_ANY, "Karl" }, @@ -1815,68 +1815,68 @@ static const CzechNameAdj _name_czech_adj[] = { /* Considered a stem for choose/allow matching purposes. */ static const CzechNameSubst _name_czech_subst_full[] = { - { CZG_SMASC, CZA_ALL, CZC_COLOR, "Sedlec" }, - { CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" }, - { CZG_SMASC, CZA_ALL, CZC_COLOR, "Brod" }, - { CZG_SMASC, CZA_ALL, CZC_NONE, "\u00daval" }, - { CZG_SMASC, CZA_ALL, CZC_COLOR, "\u017d\u010f\u00e1r" }, - { CZG_SMASC, CZA_ALL, CZC_COLOR, "Smrk" }, - { CZG_SFEM, CZA_ALL, CZC_COLOR, "Hora" }, - { CZG_SFEM, CZA_ALL, CZC_COLOR, "Lhota" }, - { CZG_SFEM, CZA_ALL, CZC_COLOR, "Lhota" }, - { CZG_SFEM, CZA_ALL, CZC_COLOR, "Hlava" }, - { CZG_SFEM, CZA_ALL, CZC_COLOR, "L\u00edpa" }, - { CZG_SNEUT, CZA_ALL, CZC_COLOR, "Pole" }, - { CZG_SNEUT, CZA_ALL, CZC_COLOR, "\u00dadol\u00ed" }, - { CZG_PMASC, CZA_ALL, CZC_NONE, "\u00davaly" }, - { CZG_PFEM, CZA_ALL, CZC_COLOR, "Luka" }, - { CZG_PNEUT, CZA_ALL, CZC_COLOR, "Pole" }, + { CZG_SMASC, CZA_ALL, CzechChooseFlag::Colour, "Sedlec" }, + { CZG_SMASC, CZA_ALL, CzechChooseFlag::Colour, "Brod" }, + { CZG_SMASC, CZA_ALL, CzechChooseFlag::Colour, "Brod" }, + { CZG_SMASC, CZA_ALL, {}, "\u00daval" }, + { CZG_SMASC, CZA_ALL, CzechChooseFlag::Colour, "\u017d\u010f\u00e1r" }, + { CZG_SMASC, CZA_ALL, CzechChooseFlag::Colour, "Smrk" }, + { CZG_SFEM, CZA_ALL, CzechChooseFlag::Colour, "Hora" }, + { CZG_SFEM, CZA_ALL, CzechChooseFlag::Colour, "Lhota" }, + { CZG_SFEM, CZA_ALL, CzechChooseFlag::Colour, "Lhota" }, + { CZG_SFEM, CZA_ALL, CzechChooseFlag::Colour, "Hlava" }, + { CZG_SFEM, CZA_ALL, CzechChooseFlag::Colour, "L\u00edpa" }, + { CZG_SNEUT, CZA_ALL, CzechChooseFlag::Colour, "Pole" }, + { CZG_SNEUT, CZA_ALL, CzechChooseFlag::Colour, "\u00dadol\u00ed" }, + { CZG_PMASC, CZA_ALL, {}, "\u00davaly" }, + { CZG_PFEM, CZA_ALL, CzechChooseFlag::Colour, "Luka" }, + { CZG_PNEUT, CZA_ALL, CzechChooseFlag::Colour, "Pole" }, }; /* TODO: More stems needed. --pasky */ static const CzechNameSubst _name_czech_subst_stem[] = { - { CZG_SMASC, { CzechAllowFlag::Middle }, CZC_COLOR, "Kostel" }, - { CZG_SMASC, { CzechAllowFlag::Middle }, CZC_COLOR, "Kl\u00e1\u0161ter" }, - { CZG_SMASC, {CzechAllowFlag::Short }, CZC_COLOR, "Lhot" }, - { CZG_SFEM, {CzechAllowFlag::Short }, CZC_COLOR, "Lhot" }, - { CZG_SFEM, {CzechAllowFlag::Short }, CZC_COLOR, "Hur" }, - { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Sedl" }, - { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_COLOR, "Hrad" }, - { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Pras" }, - { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Ba\u017e" }, - { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "Tes" }, - { CZG_NFREE, { CzechAllowFlag::Middle }, CZC_NONE, "U\u017e" }, - { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_POSTFIX, "B\u0159" }, - { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Vod" }, - { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Jan" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Prach" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Kunr" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Strak" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "V\u00edt" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Vy\u0161" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "\u017dat" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "\u017der" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "St\u0159ed" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Harv" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Pruh" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Tach" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "P\u00edsn" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jin" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jes" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Jar" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Sok" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Hod" }, - { CZG_NFREE, { CzechAllowFlag::Long}, CZC_NONE, "Net" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Pra\u017e" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Nerat" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Kral" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_NONE, "Hut" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_NOPOSTFIX, "Pan" }, - { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NOPOSTFIX, "Odst\u0159ed" }, - { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_COLOR, "Mrat" }, - { CZG_FREE, { CzechAllowFlag::Long}, CZC_COLOR, "Hlav" }, - { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_NONE, "M\u011b\u0159" }, - { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_NONE, "Lip" }, + { CZG_SMASC, { CzechAllowFlag::Middle }, CzechChooseFlag::Colour, "Kostel" }, + { CZG_SMASC, { CzechAllowFlag::Middle }, CzechChooseFlag::Colour, "Kl\u00e1\u0161ter" }, + { CZG_SMASC, {CzechAllowFlag::Short }, CzechChooseFlag::Colour, "Lhot" }, + { CZG_SFEM, {CzechAllowFlag::Short }, CzechChooseFlag::Colour, "Lhot" }, + { CZG_SFEM, {CzechAllowFlag::Short }, CzechChooseFlag::Colour, "Hur" }, + { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, {}, "Sedl" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CzechChooseFlag::Colour, "Hrad" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, {}, "Pras" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, {}, "Ba\u017e" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, {}, "Tes" }, + { CZG_NFREE, { CzechAllowFlag::Middle }, {}, "U\u017e" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, CzechChooseFlag::Postfix, "B\u0159" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, {}, "Vod" }, + { CZG_NFREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, {}, "Jan" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Prach" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Kunr" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Strak" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "V\u00edt" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Vy\u0161" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "\u017dat" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "\u017der" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "St\u0159ed" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Harv" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Pruh" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Tach" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "P\u00edsn" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Jin" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Jes" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Jar" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Sok" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Hod" }, + { CZG_NFREE, { CzechAllowFlag::Long}, {}, "Net" }, + { CZG_FREE, { CzechAllowFlag::Long}, {}, "Pra\u017e" }, + { CZG_FREE, { CzechAllowFlag::Long}, {}, "Nerat" }, + { CZG_FREE, { CzechAllowFlag::Long}, {}, "Kral" }, + { CZG_FREE, { CzechAllowFlag::Long}, {}, "Hut" }, + { CZG_FREE, { CzechAllowFlag::Long}, CzechChooseFlag::NoPostfix, "Pan" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CzechChooseFlag::NoPostfix, "Odst\u0159ed" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CzechChooseFlag::Colour, "Mrat" }, + { CZG_FREE, { CzechAllowFlag::Long}, CzechChooseFlag::Colour, "Hlav" }, + { CZG_FREE, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, {}, "M\u011b\u0159" }, + { CZG_FREE, { CzechAllowFlag::Middle, CzechAllowFlag::Long}, {}, "Lip" }, }; /* Optional postfix inserted between stem and ending. */ @@ -1892,14 +1892,14 @@ static const CzechNameSubst _name_czech_subst_ending[] = { { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Middle }, CZC_ANY, "\u00edn" }, { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Middle, CzechAllowFlag::Long}, CZC_ANY, "ov" }, { CZG_SMASC, {CzechAllowFlag::Short, CzechAllowFlag::Long}, CZC_ANY, "kov" }, - { CZG_SMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "\u00edn" }, - { CZG_SMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "n\u00edk" }, + { CZG_SMASC, { CzechAllowFlag::Long}, CzechChooseFlag::Postfix, "\u00edn" }, + { CZG_SMASC, { CzechAllowFlag::Long}, CzechChooseFlag::Postfix, "n\u00edk" }, { CZG_SMASC, { CzechAllowFlag::Long}, CZC_ANY, "burk" }, { CZG_SFEM, {CzechAllowFlag::Short }, CZC_ANY, "ka" }, { CZG_SFEM, { CzechAllowFlag::Middle }, CZC_ANY, "inka" }, { CZG_SFEM, { CzechAllowFlag::Middle }, CZC_ANY, "n\u00e1" }, { CZG_SFEM, { CzechAllowFlag::Long}, CZC_ANY, "ava" }, - { CZG_PMASC, { CzechAllowFlag::Long}, CZC_POSTFIX, "\u00edky" }, + { CZG_PMASC, { CzechAllowFlag::Long}, CzechChooseFlag::Postfix, "\u00edky" }, { CZG_PMASC, { CzechAllowFlag::Long}, CZC_ANY, "upy" }, { CZG_PMASC, { CzechAllowFlag::Long}, CZC_ANY, "olupy" }, { CZG_PFEM, { CzechAllowFlag::Long}, CZC_ANY, "avy" }, diff --git a/src/townname.cpp b/src/townname.cpp index 7f118db394..0b6a4380f1 100644 --- a/src/townname.cpp +++ b/src/townname.cpp @@ -602,7 +602,7 @@ static void MakeCzechTownName(StringBuilder &builder, uint32_t seed) /* The select criteria. */ CzechGender gender; - CzechChoose choose; + CzechChooseFlags choose; CzechAllowFlags allow; if (do_prefix) prefix = SeedModChance(5, std::size(_name_czech_adj) * 12, seed) / 12; @@ -632,18 +632,18 @@ static void MakeCzechTownName(StringBuilder &builder, uint32_t seed) /* Load the postfix (1:1 chance that a postfix will be inserted) */ postfix = SeedModChance(14, std::size(_name_czech_subst_postfix) * 2, seed); - if (choose & CZC_POSTFIX) { + if (choose.Test(CzechChooseFlag::Postfix)) { /* Always get a real postfix. */ postfix %= std::size(_name_czech_subst_postfix); } - if (choose & CZC_NOPOSTFIX) { + if (choose.Test(CzechChooseFlag::NoPostfix)) { /* Always drop a postfix. */ postfix += std::size(_name_czech_subst_postfix); } if (postfix < std::size(_name_czech_subst_postfix)) { - choose |= CZC_POSTFIX; + choose.Set(CzechChooseFlag::Postfix); } else { - choose |= CZC_NOPOSTFIX; + choose.Set(CzechChooseFlag::NoPostfix); } /* Localize the array segment containing a good gender */ From 1f83ea41fcedf8ecf5fe4d232b78b56f51f5d362 Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Wed, 16 Apr 2025 22:27:36 +0100 Subject: [PATCH 052/572] Fix: [NewGRF] PrepareLayout worked on a copy of the data resulting in bad sprite layouts. (#14013) --- src/newgrf_commons.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index a46b5477d6..3d28b360ad 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -617,7 +617,7 @@ uint32_t NewGRFSpriteLayout::PrepareLayout(uint32_t orig_offset, uint32_t newgrf * and apply the default sprite offsets (unless disabled). */ const TileLayoutRegisters *regs = this->registers.empty() ? nullptr : this->registers.data(); bool ground = true; - for (DrawTileSeqStruct result : result_seq) { + for (DrawTileSeqStruct &result : result_seq) { TileLayoutFlags flags = TLF_NOTHING; if (regs != nullptr) flags = regs->flags; From 421f202539858282cb42c953676b9e210afc7b5e Mon Sep 17 00:00:00 2001 From: translators Date: Thu, 17 Apr 2025 04:45:26 +0000 Subject: [PATCH 053/572] Update: Translations from eints luxembourgish: 103 changes by phreeze83 latvian: 1 change by lexuslatvia --- src/lang/latvian.txt | 2 +- src/lang/luxembourgish.txt | 161 ++++++++++++++++++++++++------------- 2 files changed, 104 insertions(+), 59 deletions(-) diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 14be5c60bc..af11240a97 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -2022,7 +2022,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Maksimālais lo STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Atvērtu nepielipušo logu skaits, pirms tie tiek automātiski aizvērti lai atbrīvotu vietu jauniem logiem STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :izslēgts +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Izslēgts STR_CONFIG_SETTING_ZOOM_MIN :Maksimālais pietuvinājuma līmenis: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Maksimālais pietuvinājuma līmenis skatvietām. Ir jāievēro ka paaugstinot pietuvinājuma līmeni, pieaug operatīvās atmiņas izlietojums diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index 2941add4f2..7e070b41a3 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -452,6 +452,12 @@ STR_SETTINGS_MENU_SANDBOX_OPTIONS :Sandbox Optioun STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Transparenz Optiounen STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Stiednimm uweisen STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Statiounsnimm uweisen +STR_SETTINGS_MENU_STATION_NAMES_TRAIN :Garen +STR_SETTINGS_MENU_STATION_NAMES_LORRY :Camionsgaren +STR_SETTINGS_MENU_STATION_NAMES_BUS :Busarrêten +STR_SETTINGS_MENU_STATION_NAMES_SHIP :Hafen +STR_SETTINGS_MENU_STATION_NAMES_PLANE :Fluchhäfen +STR_SETTINGS_MENU_STATION_NAMES_GHOST :Geescht STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Weepunktnimm uweisen STR_SETTINGS_MENU_SIGNS_DISPLAYED :Schëlder uweisen STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Géignerschëlder an Nimm uweisen @@ -1017,6 +1023,7 @@ STR_GAME_OPTIONS_CURRENCY_IDR :Indonesesch Rup STR_GAME_OPTIONS_CURRENCY_MYR :Malaysesche Ringgit STR_GAME_OPTIONS_CURRENCY_LVL :Lettesch Lat STR_GAME_OPTIONS_CURRENCY_PTE :Portugieseschen Escudo +STR_GAME_OPTIONS_CURRENCY_UAH :Ukrainesch Hryvnia STR_GAME_OPTIONS_AUTOSAVE_FRAME :{BLACK}Autospäicheren STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :{BLACK}Wiel den Intervall aus fir d'Autospäicherung @@ -1210,7 +1217,7 @@ STR_CITY_APPROVAL_TOLERANT :Tolerant STR_CITY_APPROVAL_HOSTILE :Feindlech STR_CITY_APPROVAL_PERMISSIVE :Fräizügeg (keng Auswierkung op Firmenactiounen) -STR_WARNING_NO_SUITABLE_AI :{WHITE}Keng KI fonnt...{}KI kënnen iwwert den 'Online Content' system downgeload ginn +STR_WARNING_NO_SUITABLE_AI :{WHITE}Keng KI fonnt...{}{}KI kënnen iwwert den 'Online Content' system downgeload ginn # Settings tree window STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Astellungen @@ -1923,7 +1930,8 @@ STR_CONFIG_SETTING_ENDING_YEAR_ZERO :Nie STR_CONFIG_SETTING_ECONOMY_TYPE :Wiertschaftstyp: {STRING} ###length 2 -STR_CONFIG_SETTING_ECONOMY_TYPE_HELPTEXT :"Glaat" suergt fir méi oft a kleng Produktiounsännerungen. "Agefruer" stoppt jeglech Ännerungen an der Wiertschaft an Industrieschléissungen. Dës Astellunge kinnten keen Afloss hunn, wann en NewGRF benotzt gëtt +STR_CONFIG_SETTING_ECONOMY_TYPE_HELPTEXT :"Glaat" suergt fir méi oft a kleng Produktiounsännerungen. "Agefruer" stoppt jeglech Ännerungen an der Wiertschaft an Industrieschléissungen. Dës Astellunge kinnten keen Afloss hunn, wann en NewGRF benotzt gëtt.{}{}Industrieproduktioun pro Mount kinnt nach emmer variabel ausgesinn wann d'Ekonomie agefruer ass, wëll d'Produktioun a fixen Intervalle ugefrot gëtt an dat net exakt de equivalent zu de Méint ass +STR_CONFIG_SETTING_ECONOMY_TYPE_HELPTEXT_PERIOD :"Glaat" suergt fir méi oft a kleng Produktiounsännerungen. "Agefruer" stoppt jeglech Ännerungen an der Wiertschaft an Industrieschléissungen. Dës Astellunge kinnten keen Afloss hunn, wann en NewGRF benotzt gëtt.{}{}Industrieproduktioun pro Minut kinnt nach emmer variabel ausgesinn wann d'Ekonomie agefruer ass, wëll d'Produktioun a fixen Intervalle ugefrot gëtt an dat net exakt de equivalent zu Minuten ass ###length 3 STR_CONFIG_SETTING_ECONOMY_TYPE_ORIGINAL :Original @@ -1966,19 +1974,24 @@ STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :Zoufälleg STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :Stied däerfen Stroossen bauen: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :Erlaabt Stied Stroossen ze bauen fir ze wuessen. Ausschalten fir d'Stiedréid dorun ze hënneren fir Stroossen selwer ze bauen STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :Stied dierfe Barrière bauen: {STRING} -STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Wann dës Astellung ugeschalt ass, kënnen Stied Stroossen iwwert Schinne bauen +STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :Wann dës Astellung ugeschalt ass, kënne Stied Stroossen iwwert Schinne bauen STR_CONFIG_SETTING_NOISE_LEVEL :Limitéier de Bau vu Fluchhäfen geméiss dem Kaméidisniveau: {STRING} STR_CONFIG_SETTING_NOISE_LEVEL_HELPTEXT :Erlaabt de Stied de Bau vu Fluchhäfen opgront vum Kaméidisniveau ze blockéiren, wat sech op d'Gréisst vun der Stad an d'Gréisst an Distanz vum Fluchhafe baséiert. Wann dat ausgeschalt ass, erlaabt d'Stad zwee Fluchhäfen ausser d'Gemengenastellung ass "Fräizügeg" STR_CONFIG_SETTING_TOWN_FOUNDING :Stiedgrënnung am Spill: {STRING} -STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Wann dës Astellung ugeschalt ass, kënnen Spiller nei Stied am Spill grënnen +STR_CONFIG_SETTING_TOWN_FOUNDING_HELPTEXT :Wann dës Astellung ugeschalt ass, kënne Spiller nei Stied am Spill grënnen ###length 3 STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :Verbueden STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :Erlaabt STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :Erlaabt, eegene Stad-Layout +STR_CONFIG_SETTING_HOUSE_PLACER :Individuell Haiser plazéiren: {STRING} +STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Wann des Astellung ugeschalt ass, kënne Spiller Haiser manuell plazéiren ###length 3 +STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN :Verbueden +STR_CONFIG_SETTING_HOUSE_PLACER_ALLOWED :Erlabt +STR_CONFIG_SETTING_HOUSE_PLACER_FULLY_CONSTRUCTED :Erlabt, fäerdeg gebaut STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Duerfwuerengeneratioun: {STRING} STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Wéivill Wuere produzéiert ginn, relativ zur Bevölkerung vum Duerf.{}Quadratesche Wuesstum: En duebel sou grousst Duerf, generéiert véier mol souvill Passagéier.{}Lineare Wuesstum: En duebel sou grousst Duerf, generéiert duebel souvill Passagéier @@ -2007,7 +2020,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Maximal Unzuel STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Unzuel un net-gepinnten openen Fënster befier al Fënsteren automatesch zougemaach ginn fir nei Plaz ze man fir nei Fënsteren STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special -STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :ausgeschalt +STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Ausgeschalt STR_CONFIG_SETTING_ZOOM_MIN :Maximale Razoom Level: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Maximal Razoomstuf fir Usiichtsfënsteren. Et gëtt méi Späicher gebraucht wann d'Stufen ze grouss ginn @@ -2192,7 +2205,7 @@ STR_INTRO_HIGHSCORE :{BLACK}Beschtel STR_INTRO_HELP :{BLACK}Hëllef & Handbuch STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Astellungen STR_INTRO_NEWGRF_SETTINGS :{BLACK}NewGRF Astellungen -STR_INTRO_ONLINE_CONTENT :{BLACK}Check Online Inhalt +STR_INTRO_ONLINE_CONTENT :{BLACK}Online Content STR_INTRO_AI_SETTINGS :{BLACK}KI Astellungen STR_INTRO_GAMESCRIPT_SETTINGS :{BLACK}Spillscriptastellungen STR_INTRO_QUIT :{BLACK}Eraus @@ -2241,6 +2254,7 @@ STR_HELP_WINDOW_README :{BLACK}Readme STR_HELP_WINDOW_CHANGELOG :{BLACK}Changelog STR_HELP_WINDOW_KNOWN_BUGS :{BLACK}Bekannte Bugs STR_HELP_WINDOW_LICENSE :{BLACK}Lizenz +STR_HELP_WINDOW_FONTS :{BLACK}Schrëften STR_HELP_WINDOW_MAIN_WEBSITE :{BLACK}OpenTTD STR_HELP_WINDOW_MANUAL_WIKI :{BLACK}Handbuch / Wiki STR_HELP_WINDOW_BUGTRACKER :{BLACK}E Bug melden @@ -2629,13 +2643,14 @@ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :warden op d'Akt STR_NETWORK_MESSAGE_CLIENT_LEAVING :verloossen STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ass dem Spill bäigetrueden STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} ass an d'Spill komm (Client #{NUM}) +STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} ass bei d'Firma {STRING} gaang STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} ass als Zuschauer do STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} huet eng nei Firma gegrënnt (#{NUM}) STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} huet d'Spill verlooss ({STRING}) STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} huet säin Numm op {STRING} gewiesselt STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} huet {CURRENCY_LONG} der Firma {STRING} ginn STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}De Server huet d'Sessioun zougemaach -STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}De Server gëtt nei gestart...{}W.e.g. waarden... +STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}De Server gëtt nei gestart...{}{}W.e.g. waarden... STR_NETWORK_MESSAGE_KICKED :*** {STRING} gouf gekickt. Grond: ({STRING}) STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Server Registration huet net geklappt @@ -2644,7 +2659,7 @@ STR_NETWORK_ERROR_COORDINATOR_ISOLATED :{WHITE}De Serve STR_NETWORK_ERROR_COORDINATOR_ISOLATED_DETAIL :{WHITE}Aner Spiller wäerte sech net op de Server verbanne kënnen # Content downloading window -STR_CONTENT_TITLE :{WHITE}Lueden Inhalt erof +STR_CONTENT_TITLE :{WHITE}Online Content STR_CONTENT_TYPE_CAPTION :{BLACK}Typ STR_CONTENT_TYPE_CAPTION_TOOLTIP :{BLACK}Typ vum Inhalt STR_CONTENT_NAME_CAPTION :{BLACK}Numm @@ -2843,6 +2858,7 @@ STR_HOUSE_PICKER_YEARS_FROM :{BLACK}Joer: {O STR_HOUSE_PICKER_YEARS_UNTIL :{BLACK}Joer: {ORANGE}Bis {NUM} STR_HOUSE_PICKER_SIZE :{BLACK}Gréisst: {ORANGE}{NUM}x{NUM} Felder STR_HOUSE_PICKER_CARGO_ACCEPTED :{BLACK}Akzeptéiert Wuer: {ORANGE} +STR_HOUSE_PICKER_CARGO_PRODUCED :{BLACK}Produzéiert Wuer: {ORANGE}{CARGO_LIST} STR_HOUSE_PICKER_CLASS_ZONE1 :Rand STR_HOUSE_PICKER_CLASS_ZONE2 :Ausseberäich @@ -2850,6 +2866,10 @@ STR_HOUSE_PICKER_CLASS_ZONE3 :Aner Viruerter STR_HOUSE_PICKER_CLASS_ZONE4 :Bannescht Viruerter STR_HOUSE_PICKER_CLASS_ZONE5 :Stadzentrum +STR_HOUSE_PICKER_PROTECT_TITLE :Upgrades verhënneren +STR_HOUSE_PICKER_PROTECT_TOOLTIP :Wiel aus ob dëst Haus firun engem Ersetze geschützt gëtt wann d'Stad wiisst +STR_HOUSE_PICKER_PROTECT_OFF :Aus +STR_HOUSE_PICKER_PROTECT_ON :Un STR_STATION_CLASS_DFLT :Standard STR_STATION_CLASS_DFLT_STATION :Standardstatioun @@ -2883,6 +2903,7 @@ STR_SELECT_ROAD_BRIDGE_CAPTION :{WHITE}Stroosse STR_SELECT_BRIDGE_SELECTION_TOOLTIP :{BLACK}Bréckenauswiel - Wiel deng Bréck aus STR_SELECT_BRIDGE_INFO_NAME :{GOLD}{STRING} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED :{GOLD}{STRING},{} {VELOCITY} +STR_SELECT_BRIDGE_INFO_NAME_COST :{GOLD}{STRING},{} {WHITE}{CURRENCY_LONG} STR_SELECT_BRIDGE_INFO_NAME_MAX_SPEED_COST :{GOLD}{STRING},{} {VELOCITY} {WHITE}{CURRENCY_LONG} STR_BRIDGE_NAME_SUSPENSION_STEEL :Stolen Hängebréck STR_BRIDGE_NAME_GIRDER_STEEL :Stoldréier Bréck @@ -2941,7 +2962,7 @@ STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP :{BLACK}Wueren-T # Waterways toolbar (last two for SE only) STR_WATERWAYS_TOOLBAR_CAPTION :{WHITE}Waasserstroosse bauen STR_WATERWAYS_TOOLBAR_CAPTION_SE :{WHITE}Waasserstroossen -STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Kanäl bauen. Dréck Shift fir nëmmen déi ongeféier Käschten unzeweisen +STR_WATERWAYS_TOOLBAR_BUILD_CANALS_TOOLTIP :{BLACK}Kanäl bauen. Ctrl+Klick+Zéien fir wielt d'Areal diagonal aus. Dréck Shift fir nëmmen déi ongeféier Käschten unzeweisen STR_WATERWAYS_TOOLBAR_BUILD_LOCKS_TOOLTIP :{BLACK}Schleise bauen. Dréck Shift fir nëmmen déi ongeféier Käschten unzeweisen STR_WATERWAYS_TOOLBAR_BUILD_DEPOT_TOOLTIP :{BLACK}Schëffsschapp bauen (fir Schëffer ze bauen an ze reparéiren). Dréck Shift fir nëmmen déi ongeféier Käschten unzeweisen STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Schëffsdock bauen. Ctrl aktivéiert ubaue vu Statiounen. Shift wiesselt tëscht bauen/ongeféier Käschten uweisen @@ -3126,6 +3147,8 @@ STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tramtyp: STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Schinne-Geschw.-Limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Stroosse-Geschw.-Limit: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tram-Geschw.-Limit: {LTBLUE}{VELOCITY} +STR_LAND_AREA_INFORMATION_TOWN_CAN_UPGRADE :{BLACK}Stad kann upgraden: {LTBLUE}Jo +STR_LAND_AREA_INFORMATION_TOWN_CANNOT_UPGRADE :{BLACK}Stad kann upgraden: {LTBLUE}Nee # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Fielsen @@ -3134,6 +3157,9 @@ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Eidelt Land STR_LAI_CLEAR_DESCRIPTION_GRASS :Gras STR_LAI_CLEAR_DESCRIPTION_FIELDS :Felder STR_LAI_CLEAR_DESCRIPTION_DESERT :Wüst +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROCKS :Schnéibedeckt Fielsen +STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROUGH_LAND :Schnéibedeckt knubbelegt Land +STR_LAI_CLEAR_DESCRIPTION_SNOWY_GRASS :Schnéibedeckt Gras STR_LAI_RAIL_DESCRIPTION_TRACK :Schinn STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Schinn mat Blocksignaler @@ -3605,17 +3631,17 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Kompati STR_NEWGRF_LIST_MISSING :{RED}Dateien feelen # NewGRF 'it's broken' warnings -STR_NEWGRF_BROKEN :{WHITE}Verhalen vun der NewGRF '{0:STRING}' kann Desyncs oder Crashen verursachen -STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Ännert den Zoustand fir '{1:ENGINE}' wann net an engem Schapp -STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ännert d'Gefierlängt fir '{1:ENGINE}' wann net an engem Schapp -STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Geännerte Gefierkapazitéit vun '{1:ENGINE}' wann net an engem Schapp oder amgaang emgebaut ze ginn +STR_NEWGRF_BROKEN :{WHITE}Verhalen vun der NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' kann Desyncs oder Crashen verursachen +STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Ännert den Zoustand fir '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' wann net an engem Schapp +STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Ännert d'Gefierlängt fir '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' wann net an engem Schapp +STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Geännerte Gefierkapazitéit vun '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' wann net an engem Schapp oder amgaang emgebaut ze ginn STR_BROKEN_VEHICLE_LENGTH :{WHITE}Zuch'{VEHICLE}' vun der Firma '{COMPANY}' huet eng falsch Längt. Et kënnt wahrscheinlech wéinst den NewGRFs. Spill kann desyncroniséiren oder ofstierzen -STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' huet Fehlinformatiounen -STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit Informatioun fir '{1:ENGINE}' ass anescht wéi an der Kaflëscht no der Constructioun. Dëst kann en Autoerneirung/-ersetzen Feeler oprufen -STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' huet eng Endlosschläif am Production callback verursaacht +STR_NEWGRF_BUGGY :{WHITE}NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' huet Fehlinformatiounen +STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Cargo/refit Informatioun fir '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' ass anescht wéi an der Kaflëscht no der Constructioun. Dëst kann en Autoerneirung/-ersetzen Feeler oprufen +STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' huet eng Endlosschläif am Production callback verursaacht STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Callback {1:HEX} huet en onbekannten/invalid Resultat {2:HEX} -STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' huet en ongültegen Wuerentyp am Production-callback bei {2:HEX} +STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' huet en ongültegen Wuerentyp am Production-callback bei {2:HEX} # 'User removed essential NewGRFs'-placeholders for stuff without specs STR_NEWGRF_INVALID_CARGO : @@ -4011,6 +4037,10 @@ STR_INDUSTRY_VIEW_PRODUCES_N_CARGO :{BLACK}Produzé STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :, {STRING}{STRING} STR_INDUSTRY_VIEW_REQUIRES :{BLACK}Brauch: +STR_INDUSTRY_VIEW_ACCEPT_CARGO_SUFFIX :{YELLOW}{0:STRING}{BLACK}{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_SUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} warden{3:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_NOSUFFIX :{YELLOW}{0:STRING} +STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT_NOSUFFIX :{YELLOW}{0:STRING}{BLACK}: {1:CARGO_SHORT} warden STR_CONFIG_GAME_PRODUCTION :{WHITE}D'Produktioun änneren (Multipel vun 8, bis op 2040) STR_CONFIG_GAME_PRODUCTION_LEVEL :{WHITE}Änner de Produktiounslevel (Prozenter, bis zu 800%) @@ -4668,54 +4698,56 @@ STR_ORDER_ROAD_VEHICLE_DEPOT :Stroossegefier- STR_ORDER_SHIP_DEPOT :Schëffswerft ###next-name-looks-similar +STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING} den noosten Hangar +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} den noosten {STRING} STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} -STR_ORDER_REFIT_ORDER :(Ëmbau op {STRING}) -STR_ORDER_REFIT_STOP_ORDER :(Ëmbau op {STRING} an stoppen) -STR_ORDER_STOP_ORDER :(Stop) +STR_ORDER_REFIT_ORDER :{SPACE}(Ëmbau op {STRING}) +STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Ëmbau op {STRING} an stoppen) +STR_ORDER_STOP_ORDER :{SPACE}(Stop) -STR_ORDER_WAIT_TO_UNBUNCH :(Warden fir ze verspreeën) +STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(Warden fir ze verspreeën) STR_ORDER_GO_TO_STATION :{STRING} {STATION} STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Statioun kann net benotzt ginn){POP_COLOUR} {STRING} {STATION} -STR_ORDER_IMPLICIT :(Implizit) +STR_ORDER_IMPLICIT :{SPACE}(Implizit) -STR_ORDER_FULL_LOAD :(Voll lueden) -STR_ORDER_FULL_LOAD_ANY :(Voll lueden mat all Wuer) -STR_ORDER_NO_LOAD :(Net lueden) -STR_ORDER_UNLOAD :(Entlueden an Luedung huelen) -STR_ORDER_UNLOAD_FULL_LOAD :(Entlueden an erem voll lueden) -STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Entlueden an mat all Wuer voll lueden) -STR_ORDER_UNLOAD_NO_LOAD :(Entlueden an eidel loosen) -STR_ORDER_TRANSFER :(Transferéieren an Lueden) -STR_ORDER_TRANSFER_FULL_LOAD :(Transferéieren an voll lueden) -STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Transferéieren an mat all Wuer voll lueden) -STR_ORDER_TRANSFER_NO_LOAD :(Transferéieren an eidel loosen) -STR_ORDER_NO_UNLOAD :(Net entlueden an Wueren lueden) -STR_ORDER_NO_UNLOAD_FULL_LOAD :(Net entlueden an op voll Beluedung waarden) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Net entlueden an op iergendeng voll Beluedung waarden) -STR_ORDER_NO_UNLOAD_NO_LOAD :(Keen Ent- an Belueden) +STR_ORDER_FULL_LOAD :{SPACE}(Voll lueden) +STR_ORDER_FULL_LOAD_ANY :{SPACE}(Voll lueden mat all Wuer) +STR_ORDER_NO_LOAD :{SPACE}(Net lueden) +STR_ORDER_UNLOAD :{SPACE}(Entlueden an Luedung huelen) +STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Entlueden an erem voll lueden) +STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Entlueden an mat all Wuer voll lueden) +STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Entlueden an eidel loosen) +STR_ORDER_TRANSFER :{SPACE}(Transferéieren an Lueden) +STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Transferéieren an voll lueden) +STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Transferéieren an mat all Wuer voll lueden) +STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Transferéieren an eidel loosen) +STR_ORDER_NO_UNLOAD :{SPACE}(Net entlueden an Wueren lueden) +STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(Net entlueden an op voll Beluedung waarden) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(Net entlueden an op iergendeng voll Beluedung waarden) +STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(Keen Ent- an Belueden) -STR_ORDER_AUTO_REFIT :(Embauen op {STRING}) -STR_ORDER_FULL_LOAD_REFIT :(Voll lueden mat ëmbauen op {STRING}) -STR_ORDER_FULL_LOAD_ANY_REFIT :(Voll lueden mat all Wueren mat ëmbauen op {STRING}) -STR_ORDER_UNLOAD_REFIT :(Entlueden an Wueren lueden mat Embauen op {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Entlueden an op voll Luedung waarden mat Embauen op {STRING}) -STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Entlueden an waard op iergendeng Volluedung mat Embauen op {STRING}) -STR_ORDER_TRANSFER_REFIT :(Transfer an lued Wueren mat Auto-Embauen zu {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Transfer an waard op Vollueden mat Auto-Embauen op {STRING}) -STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Transfer an waard op iergendeng Volluedung mat Auto-Embauen op {STRING}) -STR_ORDER_NO_UNLOAD_REFIT :(Keen Entlueden an huel Wueren mat Auto-Embauen op {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Keen Entlueden an waard op Vollueden mat Auto-Embauen op {STRING}) -STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Keen Entlueden an waard op iergendend Volluedung mat Auto-Embauen op {STRING}) +STR_ORDER_AUTO_REFIT :{SPACE}(Embauen op {STRING}) +STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Voll lueden mat ëmbauen op {STRING}) +STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Voll lueden mat all Wueren mat ëmbauen op {STRING}) +STR_ORDER_UNLOAD_REFIT :{SPACE}(Entlueden an Wueren lueden mat Embauen op {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Entlueden an op voll Luedung waarden mat Embauen op {STRING}) +STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Entlueden an waard op iergendeng Volluedung mat Embauen op {STRING}) +STR_ORDER_TRANSFER_REFIT :{SPACE}(Transfer an lued Wueren mat Auto-Embauen zu {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Transfer an waard op Vollueden mat Auto-Embauen op {STRING}) +STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Transfer an waard op iergendeng Volluedung mat Auto-Embauen op {STRING}) +STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(Keen Entlueden an huel Wueren mat Auto-Embauen op {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Keen Entlueden an waard op Vollueden mat Auto-Embauen op {STRING}) +STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Keen Entlueden an waard op iergendend Volluedung mat Auto-Embauen op {STRING}) STR_ORDER_AUTO_REFIT_ANY :verfügbar Wueren ###length 3 -STR_ORDER_STOP_LOCATION_NEAR_END :[noosten Enn] -STR_ORDER_STOP_LOCATION_MIDDLE :[Mëtt] -STR_ORDER_STOP_LOCATION_FAR_END :[wäit Enn] +STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[no um Enn] +STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[Mëtt] +STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[wäit Enn] STR_ORDER_OUT_OF_RANGE :{RED} (Nächst Destinatioun ass ze wäit fort) @@ -4740,8 +4772,8 @@ STR_TIMETABLE_TRAVEL_FOR :Ënnerwee währ STR_TIMETABLE_TRAVEL_FOR_SPEED :Fiert während {STRING} mat maximal {VELOCITY} STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Fuer (während {STRING}, ouni Zäitplang) STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Fuer (während {STRING}, ouni Zäitplang) mat maximal {VELOCITY} -STR_TIMETABLE_STAY_FOR_ESTIMATED :(bleif während {STRING}, ouni Zäitplang) -STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(fuer während {STRING}, ouni Zäitplang) +STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(waard {STRING}, ouni Zäitplang) +STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(fuer während {STRING}, ouni Zäitplang) STR_TIMETABLE_STAY_FOR :an bleif fir {STRING} STR_TIMETABLE_AND_TRAVEL_FOR :an ënnerwee während {STRING} @@ -4762,12 +4794,14 @@ STR_TIMETABLE_START_SECONDS_QUERY :Sekonne bis den STR_TIMETABLE_CHANGE_TIME :{BLACK}Zäit wiesselen STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Änner Zäit déi den ugewielten Optrag brauche soll. Ctrl+Klick ännert d'Zäit fir all Opträg +STR_TIMETABLE_CHANGE_TIME_QUERY :Zäit änneren STR_TIMETABLE_CLEAR_TIME :{BLACK}Zäit läschen STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Läsch Zäit fir de gewielten Optrag. Ctrl+Klick läscht d'Zäite fir all opträg STR_TIMETABLE_CHANGE_SPEED :{BLACK}Änner de Geschwindegkeetslimit STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Änner d'maximal Reesgeschwindëgkeet fir de gewielten Optrag. Ctrl+Klick ännert d'Geschwindegkeet fir all Opträg +STR_TIMETABLE_CHANGE_SPEED_QUERY :Geschwindegkeetslimit änneren STR_TIMETABLE_CLEAR_SPEED :{BLACK}Geschwindegkeetslimit läschen STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Maximal Reesgeschwindegkeet vum gewielten Optrag läschen. Ctrl+Klick läscht d'Geschwindegkeet fir all Opträg @@ -4873,7 +4907,7 @@ STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Minimap- # Script Parameters STR_AI_SETTINGS_CAPTION_AI :KI -STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Spill-Script +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :{WHITE}Spill-Script-Parameter STR_AI_SETTINGS_CLOSE :{BLACK}Zoumaachen STR_AI_SETTINGS_RESET :{BLACK}Reset STR_AI_SETTINGS_SETTING :{STRING}: {ORANGE}{STRING} @@ -4934,7 +4968,7 @@ STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Spill gouf an enger Versioun ouni Tram support gesaved. All Tram gouf wechgeholl # Map generation messages -STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Kaartenerstellung ofgebrach...{}... keng passend Stadplazen +STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Kaartenerstellung ofgebrach...{}{}... keng passend Stadplazen STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... et ass keng Stad an dësem Szenario STR_ERROR_PNGMAP :{WHITE}Kann d'Landschaft net vum PNG lueden... @@ -4963,6 +4997,7 @@ STR_ERROR_SCREENSHOT_FAILED :{WHITE}Screensh # Error message titles STR_ERROR_MESSAGE_CAPTION :{YELLOW}Meldung +STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY :{YELLOW}Matdeelung vun {COMPANY} # Generic construction errors STR_ERROR_OFF_EDGE_OF_MAP :{WHITE}Ausserhalb vun der Kaart @@ -4981,6 +5016,7 @@ STR_ERROR_TERRAFORM_LIMIT_REACHED :{WHITE}... Limi STR_ERROR_CLEARING_LIMIT_REACHED :{WHITE}... Limit fir d'Raume vu Felder erreecht STR_ERROR_TREE_PLANT_LIMIT_REACHED :{WHITE}... Limit fir Beem ze planzen erreecht STR_ERROR_NAME_MUST_BE_UNIQUE :{WHITE}Numm muss eenzegarteg sinn +STR_ERROR_GENERIC_OBJECT_IN_THE_WAY :{WHITE}{STRING} am Wee STR_ERROR_NOT_ALLOWED_WHILE_PAUSED :{WHITE}Net erlaabt an der Paus # Local authority errors @@ -5023,7 +5059,7 @@ STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... ze n STR_ERROR_TOO_MANY_TOWNS :{WHITE}... ze vill Stied STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... et ass keng Plaz méi op der Kaart STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Stroossenarbeschten amgaangen -STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kann des Stad net läschen...{}Eng Statioun oder Schapp huet den Numm vun dëser Stad oder en Stéck dat der Stad gehéiert kann net ewechgeholl ginn +STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Kann des Stad net läschen...{}{}Eng Statioun oder Schapp huet den Numm vun dëser Stad oder en Stéck dat der Stad gehéiert kann net ewechgeholl ginn STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... et gëtt keng gëeegent Plaz fir eng Statu am Stadzentrum STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}Kann d'Haus net bauen... @@ -5297,8 +5333,16 @@ STR_ERROR_CAN_T_SELL_SHIP :{WHITE}Kann Sch STR_ERROR_CAN_T_SELL_AIRCRAFT :{WHITE}Kann de Fliger net verkafen... ###length VEHICLE_TYPES +STR_ERROR_CAN_T_SELL_ALL_TRAIN :{WHITE}Kann net all Zich verkafen... +STR_ERROR_CAN_T_SELL_ALL_ROAD_VEHICLE :{WHITE}Kann net all Gefierer verkafen... +STR_ERROR_CAN_T_SELL_ALL_SHIP :{WHITE}Kann net all Schëffer verkafen... +STR_ERROR_CAN_T_SELL_ALL_AIRCRAFT :{WHITE}Kann all Fligeren net verkafen... ###length VEHICLE_TYPES +STR_ERROR_CAN_T_AUTOREPLACE_TRAIN :{WHITE}Kann Zich net automatesch ersetzen... +STR_ERROR_CAN_T_AUTOREPLACE_ROAD_VEHICLE :{WHITE}Ka Gefierer net automatesch ersetzen... +STR_ERROR_CAN_T_AUTOREPLACE_SHIP :{WHITE}Ka Schëffer net automatesch ersetzen... +STR_ERROR_CAN_T_AUTOREPLACE_AIRCRAFT :{WHITE}Ka Fliger net automatesch ersetzen... STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}Ze vill Gefierer am Spill STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}De Service-Intervall kann net geännert ginn... @@ -5818,7 +5862,7 @@ STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STR STR_SAVEGAME_NAME_SPECTATOR :Zuschauer, {1:STRING} # Viewport strings -STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA}) +STR_VIEWPORT_TOWN_POP :{TOWN} ({COMMA}) STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} # Simple strings to get specific types of data @@ -5880,3 +5924,4 @@ STR_SHIP :{BLACK}{SHIP} STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY}) +STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING} From 5aed046d11a38fc4a5c48c79cb5023424ae68b06 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 17 Apr 2025 12:15:49 +0200 Subject: [PATCH 054/572] Fix: [NewGRF] Strange things happened, when using the synchronised tile loop animation trigger for houses. (#14011) --- src/newgrf_house.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/newgrf_house.cpp b/src/newgrf_house.cpp index 3203688e43..99cbf7b0e1 100644 --- a/src/newgrf_house.cpp +++ b/src/newgrf_house.cpp @@ -628,12 +628,20 @@ bool CanDeleteHouse(TileIndex tile) } } -static void AnimationControl(TileIndex tile, uint16_t random_bits) +/** + * Call the tile loop animation trigger for houses, if enabled. + * @param tile House tile + * @param sync Whether to call the synchronized or the unsynchronized trigger. + * @param random_bits Shared random bits for the synchronized trigger. + */ +static void AnimationControl(TileIndex tile, bool sync, uint16_t random_bits) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); - if (hs->callback_mask.Test(HouseCallbackMask::AnimationStartStop)) { - uint32_t param = hs->extra_flags.Test(HouseExtraFlag::SynchronisedCallback1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); + /* Check whether the matching trigger is enabled */ + if (hs->callback_mask.Test(HouseCallbackMask::AnimationStartStop) && + hs->extra_flags.Test(HouseExtraFlag::SynchronisedCallback1B) == sync) { + uint32_t param = sync ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); HouseAnimationBase::ChangeAnimationFrame(CBID_HOUSE_ANIMATION_START_STOP, hs, Town::GetByTile(tile), tile, param, 0); } } @@ -650,21 +658,16 @@ bool NewHouseTileLoop(TileIndex tile) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP); if (hs->building_flags.Any(BUILDING_HAS_1_TILE)) TriggerHouse(tile, HOUSE_TRIGGER_TILE_LOOP_TOP); - if (hs->callback_mask.Test(HouseCallbackMask::AnimationStartStop)) { - /* If this house is marked as having a synchronised callback, all the - * tiles will have the callback called at once, rather than when the - * tile loop reaches them. This should only be enabled for the northern - * tile, or strange things will happen (here, and in TTDPatch). */ - if (hs->extra_flags.Test(HouseExtraFlag::SynchronisedCallback1B)) { - uint16_t random = GB(Random(), 0, 16); + /* Call the unsynchronized tile loop trigger */ + AnimationControl(tile, false, 0); - if (hs->building_flags.Any(BUILDING_HAS_1_TILE)) AnimationControl(tile, random); - if (hs->building_flags.Any(BUILDING_2_TILES_Y)) AnimationControl(TileAddXY(tile, 0, 1), random); - if (hs->building_flags.Any(BUILDING_2_TILES_X)) AnimationControl(TileAddXY(tile, 1, 0), random); - if (hs->building_flags.Any(BUILDING_HAS_4_TILES)) AnimationControl(TileAddXY(tile, 1, 1), random); - } else { - AnimationControl(tile, 0); - } + /* Call the synchronized tile loop trigger, if this is the north tile */ + if (hs->building_flags.Any(BUILDING_HAS_1_TILE)) { + uint16_t random = GB(Random(), 0, 16); + AnimationControl(tile, true, random); + if (hs->building_flags.Any(BUILDING_2_TILES_Y)) AnimationControl(TileAddXY(tile, 0, 1), true, random); + if (hs->building_flags.Any(BUILDING_2_TILES_X)) AnimationControl(TileAddXY(tile, 1, 0), true, random); + if (hs->building_flags.Any(BUILDING_HAS_4_TILES)) AnimationControl(TileAddXY(tile, 1, 1), true, random); } /* Check callback 21, which determines if a house should be destroyed. */ From 31e716449dfa512222246e318ee3018ff2014f91 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 18 Apr 2025 15:06:46 +0200 Subject: [PATCH 055/572] Codechange: Change StationNameInformation to not use macros. (#14020) --- src/station_cmd.cpp | 134 +++++++++++++++++++++++++------------------- 1 file changed, 75 insertions(+), 59 deletions(-) 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 From 2c59838acb974cdea17da184283f8e4621be45ee Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Fri, 18 Apr 2025 14:07:57 +0100 Subject: [PATCH 056/572] Codechange: (re)set multiple bitset flags in one call. (#14017) --- src/newgrf.cpp | 2 +- src/newgrf/newgrf_act0_houses.cpp | 2 +- src/object_cmd.cpp | 2 +- src/pathfinder/yapf/yapf_costrail.hpp | 3 +-- src/script/api/script_tilelist.cpp | 4 ++-- src/station_cmd.cpp | 2 +- src/vehicle_cmd.cpp | 2 +- src/viewport.cpp | 2 +- src/waypoint_cmd.cpp | 2 +- src/window.cpp | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 224e6ca6fc..34febb2d90 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -909,7 +909,7 @@ static void FinaliseEngineArray() } if (e->info.variant_id != EngineID::Invalid()) { - Engine::Get(e->info.variant_id)->display_flags.Set(EngineDisplayFlag::HasVariants).Set(EngineDisplayFlag::IsFolded); + Engine::Get(e->info.variant_id)->display_flags.Set({EngineDisplayFlag::HasVariants, EngineDisplayFlag::IsFolded}); } } } diff --git a/src/newgrf/newgrf_act0_houses.cpp b/src/newgrf/newgrf_act0_houses.cpp index d512666fdf..c73ff6fd6e 100644 --- a/src/newgrf/newgrf_act0_houses.cpp +++ b/src/newgrf/newgrf_act0_houses.cpp @@ -145,7 +145,7 @@ static ChangeInfoResult TownHouseChangeInfo(uint first, uint last, int prop, Byt housespec->random_colour[3] = COLOUR_GREEN; /* House flags 40 and 80 are exceptions; these flags are never set automatically. */ - housespec->building_flags.Reset(BuildingFlag::IsChurch).Reset(BuildingFlag::IsStadium); + housespec->building_flags.Reset({BuildingFlag::IsChurch, BuildingFlag::IsStadium}); /* Make sure that the third cargo type is valid in this * climate. This can cause problems when copying the properties diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp index 94af931e8a..f3032be4ac 100644 --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -240,7 +240,7 @@ CommandCost CmdBuildObject(DoCommandFlags flags, TileIndex tile, ObjectType type if (!IsWaterTile(t)) { /* Normal water tiles don't have to be cleared. For all other tile types clear * the tile but leave the water. */ - cost.AddCost(Command::Do(DoCommandFlags{flags}.Reset(DoCommandFlag::NoWater).Reset(DoCommandFlag::Execute), t)); + cost.AddCost(Command::Do(DoCommandFlags{flags}.Reset({DoCommandFlag::NoWater, DoCommandFlag::Execute}), t)); } else { /* Can't build on water owned by another company. */ Owner o = GetTileOwner(t); diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 65e0c59648..1c2b1e61fb 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -517,8 +517,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th end_segment_reason.Set(EndSegmentReason::SafeTile); } else if (HasSignalOnTrackdir(next.tile, ReverseTrackdir(next.td)) && GetSignalType(next.tile, TrackdirToTrack(next.td)) == SIGTYPE_PBS_ONEWAY) { /* Possible safe tile, but not so good as it's the back of a signal... */ - end_segment_reason.Set(EndSegmentReason::SafeTile); - end_segment_reason.Set(EndSegmentReason::DeadEnd); + end_segment_reason.Set({EndSegmentReason::SafeTile, EndSegmentReason::DeadEnd}); extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; } } diff --git a/src/script/api/script_tilelist.cpp b/src/script/api/script_tilelist.cpp index 83596d22bc..4eefa8daca 100644 --- a/src/script/api/script_tilelist.cpp +++ b/src/script/api/script_tilelist.cpp @@ -144,8 +144,8 @@ ScriptTileList_StationType::ScriptTileList_StationType(StationID station_id, Scr if ((station_type & ScriptStation::STATION_TRAIN) != 0) station_types.Set(::StationType::Rail); if ((station_type & ScriptStation::STATION_TRUCK_STOP) != 0) station_types.Set(::StationType::Truck); if ((station_type & ScriptStation::STATION_BUS_STOP) != 0) station_types.Set(::StationType::Bus); - if ((station_type & ScriptStation::STATION_AIRPORT) != 0) station_types.Set(::StationType::Airport).Set(::StationType::Oilrig); - if ((station_type & ScriptStation::STATION_DOCK) != 0) station_types.Set(::StationType::Dock).Set(::StationType::Oilrig); + if ((station_type & ScriptStation::STATION_AIRPORT) != 0) station_types.Set({::StationType::Airport, ::StationType::Oilrig}); + if ((station_type & ScriptStation::STATION_DOCK) != 0) station_types.Set({::StationType::Dock, ::StationType::Oilrig}); TileArea ta(::TileXY(rect->left, rect->top), rect->Width(), rect->Height()); for (TileIndex cur_tile : ta) { diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index e563c1de28..ab76fd4788 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -2308,7 +2308,7 @@ CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlags flags, int rep /* if we deleted the whole waypoint, delete the road facility. */ if (wp->road_waypoint_area.tile == INVALID_TILE) { - wp->facilities.Reset(StationFacility::BusStop).Reset(StationFacility::TruckStop); + wp->facilities.Reset({StationFacility::BusStop, StationFacility::TruckStop}); SetWindowWidgetDirty(WC_STATION_VIEW, wp->index, WID_SV_ROADVEHS); wp->UpdateVirtCoord(); DeleteStationIfEmpty(wp); diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index 89bae13ccd..ad41d7f17c 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -139,7 +139,7 @@ std::tuple CmdBuildVehicle(D /* If we are refitting we need to temporarily purchase the vehicle to be able to * test it. */ DoCommandFlags subflags = flags; - if (refitting && !flags.Test(DoCommandFlag::Execute)) subflags.Set(DoCommandFlag::Execute).Set(DoCommandFlag::AutoReplace); + if (refitting && !flags.Test(DoCommandFlag::Execute)) subflags.Set({DoCommandFlag::Execute, DoCommandFlag::AutoReplace}); /* Vehicle construction needs random bits, so we have to save the random * seeds to prevent desyncs. */ diff --git a/src/viewport.cpp b/src/viewport.cpp index 01d6c70897..7950b7d4a2 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1352,7 +1352,7 @@ static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom) static void ViewportAddTownStrings(DrawPixelInfo *dpi, const std::vector &towns, bool small) { ViewportStringFlags flags{}; - if (small) flags.Set(ViewportStringFlag::Small).Set(ViewportStringFlag::Shadow); + if (small) flags.Set({ViewportStringFlag::Small, ViewportStringFlag::Shadow}); StringID stringid = !small && _settings_client.gui.population_in_label ? STR_VIEWPORT_TOWN_POP : STR_TOWN_NAME; for (const Town *t : towns) { diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index 559d2e55a3..acd461abba 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -409,7 +409,7 @@ CommandCost CmdBuildRoadWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi } wp->delete_ctr = 0; - wp->facilities.Set(StationFacility::BusStop).Set(StationFacility::TruckStop); + wp->facilities.Set({StationFacility::BusStop, StationFacility::TruckStop}); wp->build_date = TimerGameCalendar::date; wp->string_id = STR_SV_STNAME_WAYPOINT; diff --git a/src/window.cpp b/src/window.cpp index 0e36096d2a..7b3a694ab3 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -1837,7 +1837,7 @@ static void DecreaseWindowCounters() if (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR) { NWidgetScrollbar *sb = static_cast(nwid); if (sb->disp_flags.Any({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown})) { - sb->disp_flags.Reset(NWidgetDisplayFlag::ScrollbarUp).Reset(NWidgetDisplayFlag::ScrollbarDown); + sb->disp_flags.Reset({NWidgetDisplayFlag::ScrollbarUp, NWidgetDisplayFlag::ScrollbarDown}); w->mouse_capture_widget = -1; sb->SetDirty(w); } From b862d4937f35f803a09cfa5211aee214c6df92c0 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 18 Apr 2025 15:19:28 +0200 Subject: [PATCH 057/572] Codechange: Turn custom vehicle spritenums into enum, and use them consistently. (#14022) --- src/aircraft_cmd.cpp | 6 +++--- src/depot_gui.cpp | 2 +- src/newgrf/newgrf_act0_aircraft.cpp | 4 ++-- src/newgrf/newgrf_act0_roadvehs.cpp | 4 ++-- src/newgrf/newgrf_act0_ships.cpp | 4 ++-- src/newgrf/newgrf_act0_trains.cpp | 2 +- src/newgrf/newgrf_internal_vehicle.h | 4 ++-- src/newgrf_engine.cpp | 4 ++-- src/roadveh_cmd.cpp | 7 ++++--- src/ship_cmd.cpp | 4 ++-- src/train_cmd.cpp | 11 ++++++----- src/vehicle_func.h | 15 ++++++++++++--- 12 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 78597e3a30..82d9af94b4 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -175,7 +175,7 @@ void Aircraft::GetImage(Direction direction, EngineImageType image_type, Vehicle { uint8_t spritenum = this->spritenum; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleSprite(this, direction, image_type, result); if (result->IsValid()) return; @@ -191,7 +191,7 @@ void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteS assert(v->subtype == AIR_HELICOPTER); const Aircraft *w = v->Next()->Next(); - if (is_custom_sprite(v->spritenum)) { + if (IsCustomVehicleSpriteNum(v->spritenum)) { GetCustomRotorSprite(v, image_type, result); if (result->IsValid()) return; } @@ -205,7 +205,7 @@ static void GetAircraftIcon(EngineID engine, EngineImageType image_type, Vehicle const Engine *e = Engine::Get(engine); uint8_t spritenum = e->u.air.image_index; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleIcon(engine, DIR_W, image_type, result); if (result->IsValid()) return; diff --git a/src/depot_gui.cpp b/src/depot_gui.cpp index cd2b28111a..1aabc6bcc2 100644 --- a/src/depot_gui.cpp +++ b/src/depot_gui.cpp @@ -228,7 +228,7 @@ void InitDepotWindowBlockSizes() if (!e->IsEnabled()) continue; uint w = TRAININFO_DEFAULT_VEHICLE_WIDTH; - if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { + if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->u.rail.image_index)) { w = e->GetGRF()->traininfo_vehicle_width; if (w != VEHICLEINFO_FULL_VEHICLE_WIDTH) { /* Hopeless. diff --git a/src/newgrf/newgrf_act0_aircraft.cpp b/src/newgrf/newgrf_act0_aircraft.cpp index 1c614d0d32..d246544784 100644 --- a/src/newgrf/newgrf_act0_aircraft.cpp +++ b/src/newgrf/newgrf_act0_aircraft.cpp @@ -43,9 +43,9 @@ static ChangeInfoResult AircraftVehicleChangeInfo(uint first, uint last, int pro uint8_t orig_spriteid = spriteid; /* aircraft have different custom id in the GRF file */ - if (spriteid == 0xFF) spriteid = 0xFD; + if (spriteid == 0xFF) spriteid = CUSTOM_VEHICLE_SPRITENUM; - if (spriteid < 0xFD) spriteid >>= 1; + if (spriteid < CUSTOM_VEHICLE_SPRITENUM) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { avi->image_index = spriteid; diff --git a/src/newgrf/newgrf_act0_roadvehs.cpp b/src/newgrf/newgrf_act0_roadvehs.cpp index aba759f8f7..e8cf67f6bb 100644 --- a/src/newgrf/newgrf_act0_roadvehs.cpp +++ b/src/newgrf/newgrf_act0_roadvehs.cpp @@ -62,9 +62,9 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint first, uint last, int prop, B uint8_t orig_spriteid = spriteid; /* cars have different custom id in the GRF file */ - if (spriteid == 0xFF) spriteid = 0xFD; + if (spriteid == 0xFF) spriteid = CUSTOM_VEHICLE_SPRITENUM; - if (spriteid < 0xFD) spriteid >>= 1; + if (spriteid < CUSTOM_VEHICLE_SPRITENUM) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { rvi->image_index = spriteid; diff --git a/src/newgrf/newgrf_act0_ships.cpp b/src/newgrf/newgrf_act0_ships.cpp index f24be94bda..0e1bfe0b17 100644 --- a/src/newgrf/newgrf_act0_ships.cpp +++ b/src/newgrf/newgrf_act0_ships.cpp @@ -45,9 +45,9 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint first, uint last, int prop, B uint8_t orig_spriteid = spriteid; /* ships have different custom id in the GRF file */ - if (spriteid == 0xFF) spriteid = 0xFD; + if (spriteid == 0xFF) spriteid = CUSTOM_VEHICLE_SPRITENUM; - if (spriteid < 0xFD) spriteid >>= 1; + if (spriteid < CUSTOM_VEHICLE_SPRITENUM) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { svi->image_index = spriteid; diff --git a/src/newgrf/newgrf_act0_trains.cpp b/src/newgrf/newgrf_act0_trains.cpp index 29fa3e473a..445dbf294b 100644 --- a/src/newgrf/newgrf_act0_trains.cpp +++ b/src/newgrf/newgrf_act0_trains.cpp @@ -98,7 +98,7 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead /* TTD sprite IDs point to a location in a 16bit array, but we use it * as an array index, so we need it to be half the original value. */ - if (spriteid < 0xFD) spriteid >>= 1; + if (spriteid < CUSTOM_VEHICLE_SPRITENUM) spriteid >>= 1; if (IsValidNewGRFImageIndex(spriteid)) { rvi->image_index = spriteid; diff --git a/src/newgrf/newgrf_internal_vehicle.h b/src/newgrf/newgrf_internal_vehicle.h index 53526e7526..2e1abf3b70 100644 --- a/src/newgrf/newgrf_internal_vehicle.h +++ b/src/newgrf/newgrf_internal_vehicle.h @@ -58,12 +58,12 @@ void ConvertTTDBasePrice(uint32_t base_pointer, const char *error_location, Pric * Helper to check whether an image index is valid for a particular NewGRF vehicle. * @tparam T The type of vehicle. * @param image_index The image index to check. - * @return True iff the image index is valid, or 0xFD (use new graphics). + * @return True iff the image index is valid, or CUSTOM_VEHICLE_SPRITENUM (use new graphics). */ template static inline bool IsValidNewGRFImageIndex(uint8_t image_index) { - return image_index == 0xFD || IsValidImageIndex(image_index); + return image_index == CUSTOM_VEHICLE_SPRITENUM || IsValidImageIndex(image_index); } ChangeInfoResult CommonVehicleChangeInfo(EngineInfo *ei, int prop, ByteReader &buf); diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 88dfd74b33..62158dca6e 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -838,8 +838,8 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec case 0x46: return v->GetEngine()->grf_prop.local_id; case 0x47: return GB(v->GetEngine()->grf_prop.local_id, 8, 8); case 0x48: - if (v->type != VEH_TRAIN || v->spritenum != 0xFD) return v->spritenum; - return HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION) ? 0xFE : 0xFD; + if (v->type != VEH_TRAIN || v->spritenum != CUSTOM_VEHICLE_SPRITENUM) return v->spritenum; + return HasBit(Train::From(v)->flags, VRF_REVERSE_DIRECTION) ? CUSTOM_VEHICLE_SPRITENUM_REVERSED : CUSTOM_VEHICLE_SPRITENUM; case 0x49: return v->day_counter; case 0x4A: return v->breakdowns_since_last_service; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index b56e8b772d..71649eaa5c 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -107,7 +107,7 @@ static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleS const Engine *e = Engine::Get(engine); uint8_t spritenum = e->u.road.image_index; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleIcon(engine, DIR_W, image_type, result); if (result->IsValid()) return; @@ -122,8 +122,9 @@ void RoadVehicle::GetImage(Direction direction, EngineImageType image_type, Vehi { uint8_t spritenum = this->spritenum; - if (is_custom_sprite(spritenum)) { - GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result); + if (IsCustomVehicleSpriteNum(spritenum)) { + if (spritenum == CUSTOM_VEHICLE_SPRITENUM_REVERSED) direction = ReverseDir(direction); + GetCustomVehicleSprite(this, direction, image_type, result); if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index badc781ab0..2ed052c76f 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -83,7 +83,7 @@ static void GetShipIcon(EngineID engine, EngineImageType image_type, VehicleSpri const Engine *e = Engine::Get(engine); uint8_t spritenum = e->u.ship.image_index; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleIcon(engine, DIR_W, image_type, result); if (result->IsValid()) return; @@ -137,7 +137,7 @@ void Ship::GetImage(Direction direction, EngineImageType image_type, VehicleSpri if (image_type == EIT_ON_MAP) direction = this->rotation; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleSprite(this, direction, image_type, result); if (result->IsValid()) return; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index b7b10f543e..3cc2755b69 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -441,7 +441,7 @@ int Train::GetCursorImageOffset() const int reference_width = TRAININFO_DEFAULT_VEHICLE_WIDTH; const Engine *e = this->GetEngine(); - if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { + if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->u.rail.image_index)) { reference_width = e->GetGRF()->traininfo_vehicle_width; } @@ -461,7 +461,7 @@ int Train::GetDisplayImageWidth(Point *offset) const int vehicle_pitch = 0; const Engine *e = this->GetEngine(); - if (e->GetGRF() != nullptr && is_custom_sprite(e->u.rail.image_index)) { + if (e->GetGRF() != nullptr && IsCustomVehicleSpriteNum(e->u.rail.image_index)) { reference_width = e->GetGRF()->traininfo_vehicle_width; vehicle_pitch = e->GetGRF()->traininfo_vehicle_pitch; } @@ -495,8 +495,9 @@ void Train::GetImage(Direction direction, EngineImageType image_type, VehicleSpr if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); - if (is_custom_sprite(spritenum)) { - GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result); + if (IsCustomVehicleSpriteNum(spritenum)) { + if (spritenum == CUSTOM_VEHICLE_SPRITENUM_REVERSED) direction = ReverseDir(direction); + GetCustomVehicleSprite(this, direction, image_type, result); if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; @@ -516,7 +517,7 @@ static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType Direction dir = rear_head ? DIR_E : DIR_W; uint8_t spritenum = e->u.rail.image_index; - if (is_custom_sprite(spritenum)) { + if (IsCustomVehicleSpriteNum(spritenum)) { GetCustomVehicleIcon(engine, dir, image_type, result); if (result->IsValid()) { if (e->GetGRF() != nullptr) { diff --git a/src/vehicle_func.h b/src/vehicle_func.h index e5207e969e..33701feae2 100644 --- a/src/vehicle_func.h +++ b/src/vehicle_func.h @@ -21,9 +21,18 @@ #include "track_type.h" #include "livery.h" -#define is_custom_sprite(x) (x >= 0xFD) -#define IS_CUSTOM_FIRSTHEAD_SPRITE(x) (x == 0xFD) -#define IS_CUSTOM_SECONDHEAD_SPRITE(x) (x == 0xFE) +/** + * Special values for Vehicle::spritenum and (Aircraft|Rail|Road|Ship)VehicleInfo::image_index + */ +enum CustomVehicleSpriteNum { + CUSTOM_VEHICLE_SPRITENUM = 0xFD, ///< Vehicle sprite from NewGRF + CUSTOM_VEHICLE_SPRITENUM_REVERSED = 0xFE, ///< Vehicle sprite from NewGRF with reverse driving direction (from articulation callback) +}; + +static inline bool IsCustomVehicleSpriteNum(uint8_t spritenum) +{ + return spritenum >= CUSTOM_VEHICLE_SPRITENUM; +} static const TimerGameEconomy::Date VEHICLE_PROFIT_MIN_AGE{CalendarTime::DAYS_IN_YEAR * 2}; ///< Only vehicles older than this have a meaningful profit. static const Money VEHICLE_PROFIT_THRESHOLD = 10000; ///< Threshold for a vehicle to be considered making good profit. From 26db4ccf09f4615747aa92942f05cadb12edbb07 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 18 Apr 2025 15:20:55 +0200 Subject: [PATCH 058/572] Codechange: Turn bit-stuffed FiosType enum into a struct. (#14019) --- src/console_cmds.cpp | 14 ++++---- src/fileio_type.h | 60 +++++++++------------------------- src/fios.cpp | 20 ++++-------- src/fios_gui.cpp | 12 +++---- src/genworld_gui.cpp | 2 +- src/landscape.cpp | 2 +- src/network/network_client.cpp | 2 +- src/network/network_server.cpp | 2 +- src/openttd.cpp | 18 +++++----- src/saveload/afterload.cpp | 2 +- src/saveload/saveload.cpp | 22 +++---------- src/saveload/saveload.h | 6 ++-- src/saveload/signs_sl.cpp | 2 +- 13 files changed, 59 insertions(+), 105 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index cb091832ff..948f1c0aef 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -462,7 +462,7 @@ DEF_CONSOLE_CMD(ConLoad) _console_file_list_savegame.ValidateFileList(); const FiosItem *item = _console_file_list_savegame.FindItem(file); if (item != nullptr) { - if (GetAbstractFileType(item->type) == FT_SAVEGAME) { + if (item->type.abstract == FT_SAVEGAME) { _switch_mode = SM_LOAD_GAME; _file_to_saveload.Set(*item); } else { @@ -488,7 +488,7 @@ DEF_CONSOLE_CMD(ConLoadScenario) _console_file_list_scenario.ValidateFileList(); const FiosItem *item = _console_file_list_scenario.FindItem(file); if (item != nullptr) { - if (GetAbstractFileType(item->type) == FT_SCENARIO) { + if (item->type.abstract == FT_SCENARIO) { _switch_mode = SM_LOAD_GAME; _file_to_saveload.Set(*item); } else { @@ -514,7 +514,7 @@ DEF_CONSOLE_CMD(ConLoadHeightmap) _console_file_list_heightmap.ValidateFileList(); const FiosItem *item = _console_file_list_heightmap.FindItem(file); if (item != nullptr) { - if (GetAbstractFileType(item->type) == FT_HEIGHTMAP) { + if (item->type.abstract == FT_HEIGHTMAP) { _switch_mode = SM_START_HEIGHTMAP; _file_to_saveload.Set(*item); } else { @@ -614,8 +614,10 @@ DEF_CONSOLE_CMD(ConChangeDirectory) _console_file_list_savegame.ValidateFileList(true); const FiosItem *item = _console_file_list_savegame.FindItem(file); if (item != nullptr) { - switch (item->type) { - case FIOS_TYPE_DIR: case FIOS_TYPE_DRIVE: case FIOS_TYPE_PARENT: + switch (item->type.detailed) { + case DFT_FIOS_DIR: + case DFT_FIOS_DRIVE: + case DFT_FIOS_PARENT: FiosBrowseTo(item); break; default: IConsolePrint(CC_ERROR, "{}: Not a directory.", file); @@ -1307,7 +1309,7 @@ DEF_CONSOLE_CMD(ConReload) return true; } - if (_file_to_saveload.abstract_ftype == FT_NONE || _file_to_saveload.abstract_ftype == FT_INVALID) { + if (_file_to_saveload.ftype.abstract == FT_NONE || _file_to_saveload.ftype.abstract == FT_INVALID) { IConsolePrint(CC_ERROR, "No game loaded to reload."); return true; } diff --git a/src/fileio_type.h b/src/fileio_type.h index 46d1fbfdca..54e47aeff4 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -21,8 +21,6 @@ enum AbstractFileType : uint8_t { FT_TOWN_DATA, ///< town data file FT_INVALID = 7, ///< Invalid or unknown file type. - FT_NUMBITS = 3, ///< Number of bits required for storing a #AbstractFileType value. - FT_MASK = (1 << FT_NUMBITS) - 1, ///< Bitmask for extracting an abstract file type. }; /** Kinds of files in each #AbstractFileType. */ @@ -58,56 +56,30 @@ enum SaveLoadOperation : uint8_t { SLO_INVALID, ///< Unknown file operation. }; -/** - * Construct an enum value for #FiosType as a combination of an abstract and a detailed file type. - * @param abstract Abstract file type (one of #AbstractFileType). - * @param detailed Detailed file type (one of #DetailedFileType). - */ -#define MAKE_FIOS_TYPE(abstract, detailed) ((abstract) | ((detailed) << FT_NUMBITS)) - /** * Elements of a file system that are recognized. - * Values are a combination of #AbstractFileType and #DetailedFileType. - * @see GetAbstractFileType GetDetailedFileType */ -enum FiosType : uint16_t { - FIOS_TYPE_DRIVE = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DRIVE), - FIOS_TYPE_PARENT = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_PARENT), - FIOS_TYPE_DIR = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DIR), - FIOS_TYPE_DIRECT = MAKE_FIOS_TYPE(FT_NONE, DFT_FIOS_DIRECT), +struct FiosType { + AbstractFileType abstract; ///< Abstract file type. + DetailedFileType detailed; ///< Detailed file type. - FIOS_TYPE_FILE = MAKE_FIOS_TYPE(FT_SAVEGAME, DFT_GAME_FILE), - FIOS_TYPE_OLDFILE = MAKE_FIOS_TYPE(FT_SAVEGAME, DFT_OLD_GAME_FILE), - FIOS_TYPE_SCENARIO = MAKE_FIOS_TYPE(FT_SCENARIO, DFT_GAME_FILE), - FIOS_TYPE_OLD_SCENARIO = MAKE_FIOS_TYPE(FT_SCENARIO, DFT_OLD_GAME_FILE), - FIOS_TYPE_PNG = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_PNG), - FIOS_TYPE_BMP = MAKE_FIOS_TYPE(FT_HEIGHTMAP, DFT_HEIGHTMAP_BMP), - FIOS_TYPE_JSON = MAKE_FIOS_TYPE(FT_TOWN_DATA, DFT_TOWN_DATA_JSON), - - FIOS_TYPE_INVALID = MAKE_FIOS_TYPE(FT_INVALID, DFT_INVALID), + constexpr bool operator==(const FiosType &) const noexcept = default; }; -#undef MAKE_FIOS_TYPE +constexpr FiosType FIOS_TYPE_DRIVE{FT_NONE, DFT_FIOS_DRIVE}; +constexpr FiosType FIOS_TYPE_PARENT{FT_NONE, DFT_FIOS_PARENT}; +constexpr FiosType FIOS_TYPE_DIR{FT_NONE, DFT_FIOS_DIR}; +constexpr FiosType FIOS_TYPE_DIRECT{FT_NONE, DFT_FIOS_DIRECT}; -/** - * Extract the abstract file type from a #FiosType. - * @param fios_type Type to query. - * @return The Abstract file type of the \a fios_type. - */ -inline AbstractFileType GetAbstractFileType(FiosType fios_type) -{ - return static_cast(static_cast(fios_type) & FT_MASK); -} +constexpr FiosType FIOS_TYPE_FILE{FT_SAVEGAME, DFT_GAME_FILE}; +constexpr FiosType FIOS_TYPE_OLDFILE{FT_SAVEGAME, DFT_OLD_GAME_FILE}; +constexpr FiosType FIOS_TYPE_SCENARIO{FT_SCENARIO, DFT_GAME_FILE}; +constexpr FiosType FIOS_TYPE_OLD_SCENARIO{FT_SCENARIO, DFT_OLD_GAME_FILE}; +constexpr FiosType FIOS_TYPE_PNG{FT_HEIGHTMAP, DFT_HEIGHTMAP_PNG}; +constexpr FiosType FIOS_TYPE_BMP{FT_HEIGHTMAP, DFT_HEIGHTMAP_BMP}; +constexpr FiosType FIOS_TYPE_JSON{FT_TOWN_DATA, DFT_TOWN_DATA_JSON}; -/** - * Extract the detailed file type from a #FiosType. - * @param fios_type Type to query. - * @return The Detailed file type of the \a fios_type. - */ -inline DetailedFileType GetDetailedFileType(FiosType fios_type) -{ - return static_cast(fios_type >> FT_NUMBITS); -} +constexpr FiosType FIOS_TYPE_INVALID{FT_INVALID, DFT_INVALID}; /** * The different kinds of subdirectories OpenTTD uses diff --git a/src/fios.cpp b/src/fios.cpp index 9206aa101a..4e74c2e246 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -142,18 +142,18 @@ std::string FiosGetCurrentPath() */ bool FiosBrowseTo(const FiosItem *item) { - switch (item->type) { - case FIOS_TYPE_DRIVE: + switch (item->type.detailed) { + case DFT_FIOS_DRIVE: #if defined(_WIN32) assert(_fios_path != nullptr); *_fios_path = std::string{ item->title, 0, 1 } + ":" PATHSEP; #endif break; - case FIOS_TYPE_INVALID: + case DFT_INVALID: break; - case FIOS_TYPE_PARENT: { + case DFT_FIOS_PARENT: { assert(_fios_path != nullptr); auto s = _fios_path->find_last_of(PATHSEPCHAR); if (s != std::string::npos && s != 0) { @@ -167,24 +167,18 @@ bool FiosBrowseTo(const FiosItem *item) break; } - case FIOS_TYPE_DIR: + case DFT_FIOS_DIR: assert(_fios_path != nullptr); *_fios_path += item->name; *_fios_path += PATHSEP; break; - case FIOS_TYPE_DIRECT: + case DFT_FIOS_DIRECT: assert(_fios_path != nullptr); *_fios_path = item->name; break; - case FIOS_TYPE_FILE: - case FIOS_TYPE_OLDFILE: - case FIOS_TYPE_SCENARIO: - case FIOS_TYPE_OLD_SCENARIO: - case FIOS_TYPE_PNG: - case FIOS_TYPE_BMP: - case FIOS_TYPE_JSON: + default: return false; } diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index e3ff376497..6bf9210eee 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -309,10 +309,10 @@ static void SortSaveGameList(FileList &file_list) * Only sort savegames/scenarios, not directories */ for (const auto &item : file_list) { - switch (item.type) { - case FIOS_TYPE_DIR: sort_start++; break; - case FIOS_TYPE_PARENT: sort_start++; break; - case FIOS_TYPE_DRIVE: sort_end++; break; + switch (item.type.detailed) { + case DFT_FIOS_DIR: sort_start++; break; + case DFT_FIOS_PARENT: sort_start++; break; + case DFT_FIOS_DRIVE: sort_end++; break; default: break; } } @@ -514,7 +514,7 @@ public: } else if (item == this->highlighted) { GfxFillRect(br.left, tr.top, br.right, tr.bottom, PC_VERY_DARK_BLUE); } - DrawString(tr, item->title, _fios_colours[GetDetailedFileType(item->type)]); + DrawString(tr, item->title, _fios_colours[item->type.detailed]); tr = tr.Translate(0, this->resize.step_height); } break; @@ -719,7 +719,7 @@ public: this->selected = file; _load_check_data.Clear(); - if (GetDetailedFileType(file->type) == DFT_GAME_FILE) { + if (file->type.detailed == DFT_GAME_FILE) { /* Other detailed file types cannot be checked before. */ SaveOrLoad(file->name, SLO_CHECK, DFT_GAME_FILE, NO_DIRECTORY, false); } diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index a646638cff..854ae3d226 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -997,7 +997,7 @@ static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode) if (mode == GLWM_HEIGHTMAP) { /* If the function returns negative, it means there was a problem loading the heightmap */ - if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str(), &x, &y)) return; + if (!GetHeightmapDimensions(_file_to_saveload.ftype.detailed, _file_to_saveload.name.c_str(), &x, &y)) return; } WindowDesc &desc = (mode == GLWM_HEIGHTMAP) ? _heightmap_load_desc : _generate_landscape_desc; diff --git a/src/landscape.cpp b/src/landscape.cpp index 702889a922..02a61ddfc0 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1543,7 +1543,7 @@ bool GenerateLandscape(uint8_t mode) if (mode == GWM_HEIGHTMAP) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP); - if (!LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str())) { + if (!LoadHeightmap(_file_to_saveload.ftype.detailed, _file_to_saveload.name.c_str())) { return false; } IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 928b01f828..c662f9f6d3 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -823,7 +823,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet ClearErrorMessages(); /* Set the abstract filetype. This is read during savegame load. */ - _file_to_saveload.SetMode(SLO_LOAD, FT_SAVEGAME, DFT_GAME_FILE); + _file_to_saveload.SetMode(FIOS_TYPE_FILE, SLO_LOAD); bool load_success = SafeLoad({}, SLO_LOAD, DFT_GAME_FILE, GM_NORMAL, NO_DIRECTORY, this->savegame); this->savegame = nullptr; diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 6247807a39..5eb29ad2a0 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1814,7 +1814,7 @@ void NetworkServer_Tick(bool send_frame) static void NetworkRestartMap() { _settings_newgame.game_creation.generation_seed = GENERATE_NEW_SEED; - switch (_file_to_saveload.abstract_ftype) { + switch (_file_to_saveload.ftype.abstract) { case FT_SAVEGAME: case FT_SCENARIO: _switch_mode = SM_LOAD_GAME; diff --git a/src/openttd.cpp b/src/openttd.cpp index 6d5dd18ad9..d095f23b01 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -579,14 +579,14 @@ int openttd_main(std::span arguments) } /* Allow for '-e' before or after '-g'. */ - switch (GetAbstractFileType(ft)) { + switch (ft.abstract) { case FT_SAVEGAME: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break; case FT_SCENARIO: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME); break; case FT_HEIGHTMAP: _switch_mode = (_switch_mode == SM_EDITOR ? SM_LOAD_HEIGHTMAP : SM_START_HEIGHTMAP); break; default: break; } - _file_to_saveload.SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft)); + _file_to_saveload.SetMode(ft, SLO_LOAD); break; } @@ -886,7 +886,7 @@ static void MakeNewGame(bool from_heightmap, bool reset_settings) _game_mode = GM_NORMAL; if (!from_heightmap) { /* "reload" command needs to know what mode we were in. */ - _file_to_saveload.SetMode(SLO_INVALID, FT_INVALID, DFT_INVALID); + _file_to_saveload.SetMode(FIOS_TYPE_INVALID, SLO_INVALID); } ResetGRFConfig(true); @@ -904,7 +904,7 @@ static void MakeNewEditorWorld() { _game_mode = GM_EDITOR; /* "reload" command needs to know what mode we were in. */ - _file_to_saveload.SetMode(SLO_INVALID, FT_INVALID, DFT_INVALID); + _file_to_saveload.SetMode(FIOS_TYPE_INVALID, SLO_INVALID); ResetGRFConfig(true); @@ -1054,12 +1054,12 @@ void SwitchToMode(SwitchMode new_mode) break; case SM_RELOADGAME: // Reload with what-ever started the game - if (_file_to_saveload.abstract_ftype == FT_SAVEGAME || _file_to_saveload.abstract_ftype == FT_SCENARIO) { + if (_file_to_saveload.ftype.abstract == FT_SAVEGAME || _file_to_saveload.ftype.abstract == FT_SCENARIO) { /* Reload current savegame/scenario */ _switch_mode = _game_mode == GM_EDITOR ? SM_LOAD_SCENARIO : SM_LOAD_GAME; SwitchToMode(_switch_mode); break; - } else if (_file_to_saveload.abstract_ftype == FT_HEIGHTMAP) { + } else if (_file_to_saveload.ftype.abstract == FT_HEIGHTMAP) { /* Restart current heightmap */ _switch_mode = _game_mode == GM_EDITOR ? SM_LOAD_HEIGHTMAP : SM_RESTART_HEIGHTMAP; SwitchToMode(_switch_mode); @@ -1084,10 +1084,10 @@ void SwitchToMode(SwitchMode new_mode) ResetGRFConfig(true); ResetWindowSystem(); - if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_NORMAL, NO_DIRECTORY)) { + if (!SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.ftype.detailed, GM_NORMAL, NO_DIRECTORY)) { ShowErrorMessage(GetSaveLoadErrorType(), GetSaveLoadErrorMessage(), WL_CRITICAL); } else { - if (_file_to_saveload.abstract_ftype == FT_SCENARIO) { + if (_file_to_saveload.ftype.abstract == FT_SCENARIO) { OnStartScenario(); } OnStartGame(_network_dedicated); @@ -1120,7 +1120,7 @@ void SwitchToMode(SwitchMode new_mode) break; case SM_LOAD_SCENARIO: { // Load scenario from scenario editor - if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.detail_ftype, GM_EDITOR, NO_DIRECTORY)) { + if (SafeLoad(_file_to_saveload.name, _file_to_saveload.file_op, _file_to_saveload.ftype.detailed, GM_EDITOR, NO_DIRECTORY)) { SetLocalCompany(OWNER_NONE); GenerateSavegameId(); _settings_newgame.game_creation.starting_year = TimerGameCalendar::year; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 23de2d9de1..9fca094948 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -256,7 +256,7 @@ static void InitializeWindowsAndCaches() /* For each company, verify (while loading a scenario) that the inauguration date is the current year and set it * accordingly if it is not the case. No need to set it on companies that are not been used already, * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */ - if (_file_to_saveload.abstract_ftype == FT_SCENARIO && c->inaugurated_year != EconomyTime::MIN_YEAR) { + if (_file_to_saveload.ftype.abstract == FT_SCENARIO && c->inaugurated_year != EconomyTime::MIN_YEAR) { c->inaugurated_year = TimerGameEconomy::year; } } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index 9c7bcc32c6..d6f2536f67 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -3370,33 +3370,21 @@ std::string GenerateDefaultSaveName() return filename; } -/** - * Set the mode and file type of the file to save or load based on the type of file entry at the file system. - * @param ft Type of file entry of the file system. - */ -void FileToSaveLoad::SetMode(FiosType ft) -{ - this->SetMode(SLO_LOAD, GetAbstractFileType(ft), GetDetailedFileType(ft)); -} - /** * Set the mode and file type of the file to save or load. + * @param ft File type. * @param fop File operation being performed. - * @param aft Abstract file type. - * @param dft Detailed file type. */ -void FileToSaveLoad::SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft) +void FileToSaveLoad::SetMode(const FiosType &ft, SaveLoadOperation fop) { - if (aft == FT_INVALID || aft == FT_NONE) { + if (ft.abstract == FT_INVALID || ft.abstract == FT_NONE) { this->file_op = SLO_INVALID; - this->detail_ftype = DFT_INVALID; - this->abstract_ftype = FT_INVALID; + this->ftype = FIOS_TYPE_INVALID; return; } this->file_op = fop; - this->detail_ftype = dft; - this->abstract_ftype = aft; + this->ftype = ft; } /** diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index b665661d7d..246088625e 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -414,13 +414,11 @@ enum SaveOrLoadResult : uint8_t { /** Deals with the type of the savegame, independent of extension */ struct FileToSaveLoad { SaveLoadOperation file_op; ///< File operation to perform. - DetailedFileType detail_ftype; ///< Concrete file type (PNG, BMP, old save, etc). - AbstractFileType abstract_ftype; ///< Abstract type of file (scenario, heightmap, etc). + FiosType ftype; ///< File type. std::string name; ///< Name of the file. std::string title; ///< Internal name of the game. - void SetMode(FiosType ft); - void SetMode(SaveLoadOperation fop, AbstractFileType aft, DetailedFileType dft); + void SetMode(const FiosType &ft, SaveLoadOperation fop = SLO_LOAD); void Set(const FiosItem &item); }; diff --git a/src/saveload/signs_sl.cpp b/src/saveload/signs_sl.cpp index 698bd9f176..e8c1061374 100644 --- a/src/saveload/signs_sl.cpp +++ b/src/saveload/signs_sl.cpp @@ -62,7 +62,7 @@ struct SIGNChunkHandler : ChunkHandler { } /* Signs placed in scenario editor shall now be OWNER_DEITY */ - if (IsSavegameVersionBefore(SLV_171) && si->owner == OWNER_NONE && _file_to_saveload.abstract_ftype == FT_SCENARIO) { + if (IsSavegameVersionBefore(SLV_171) && si->owner == OWNER_NONE && _file_to_saveload.ftype.abstract == FT_SCENARIO) { si->owner = OWNER_DEITY; } } From 252376ce3eb6ffd4b9cd1b7ebbdb257d4b96cac8 Mon Sep 17 00:00:00 2001 From: frosch Date: Fri, 18 Apr 2025 15:24:34 +0200 Subject: [PATCH 059/572] Codechange: Rename DrawRoadAsSnowDesert to DrawRoadAsSnowOrDesert to be consistent with other functions. --- src/road_cmd.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 2d9a6d2de5..6e23f63c59 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1356,7 +1356,7 @@ static uint GetRoadSpriteOffset(Slope slope, RoadBits bits) * @param roadside What sort of road this is * @return True if snow/desert road sprites should be used. */ -static bool DrawRoadAsSnowDesert(bool snow_or_desert, Roadside roadside) +static bool DrawRoadAsSnowOrDesert(bool snow_or_desert, Roadside roadside) { return (snow_or_desert && !(_settings_game.game_creation.landscape == LandscapeType::Tropic && HasGrfMiscBit(GrfMiscBit::DesertPavedRoads) && @@ -1556,7 +1556,7 @@ static SpriteID GetRoadGroundSprite(const TileInfo *ti, Roadside roadside, const { /* Draw bare ground sprite if no road or road uses overlay system. */ if (rti == nullptr || rti->UsesOverlay()) { - if (DrawRoadAsSnowDesert(snow_or_desert, roadside)) { + if (DrawRoadAsSnowOrDesert(snow_or_desert, roadside)) { return SPR_FLAT_SNOW_DESERT_TILE + SlopeToSpriteOffset(ti->tileh); } @@ -1571,7 +1571,7 @@ static SpriteID GetRoadGroundSprite(const TileInfo *ti, Roadside roadside, const /* Draw original road base sprite */ SpriteID image = SPR_ROAD_Y + offset; - if (DrawRoadAsSnowDesert(snow_or_desert, roadside)) { + if (DrawRoadAsSnowOrDesert(snow_or_desert, roadside)) { image += 19; } else { switch (roadside) { @@ -1720,7 +1720,7 @@ static void DrawTile_Road(TileInfo *ti) SpriteID image = SPR_ROAD_Y + axis; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(IsOnSnow(ti->tile), roadside)) { + if (DrawRoadAsSnowOrDesert(IsOnSnow(ti->tile), roadside)) { image += 19; } else { switch (roadside) { @@ -1736,7 +1736,7 @@ static void DrawTile_Road(TileInfo *ti) if (IsCrossingBarred(ti->tile)) image += 2; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowDesert(IsOnSnow(ti->tile), roadside)) { + if (DrawRoadAsSnowOrDesert(IsOnSnow(ti->tile), roadside)) { image += 8; } else { switch (roadside) { From 42deccc4f541b7e4aa12e80395fadd11096b5dc9 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 17 Apr 2025 13:41:18 +0200 Subject: [PATCH 060/572] Codechange: Merge (IsOn|Toggle)(Snow|Desert) into (IsOn|Toggle)SnowOrDesert. --- src/newgrf_commons.cpp | 2 +- src/road_cmd.cpp | 14 +++++++------- src/road_map.h | 8 ++------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/newgrf_commons.cpp b/src/newgrf_commons.cpp index 3d28b360ad..3b03f253ff 100644 --- a/src/newgrf_commons.cpp +++ b/src/newgrf_commons.cpp @@ -357,7 +357,7 @@ uint32_t GetTerrainType(TileIndex tile, TileContext context) case MP_ROAD: /* During map generation the snowstate may not be valid yet, as the tileloop may not have run yet. */ if (_generating_world) goto genworld; // we do not care about foundations here - has_snow = IsOnSnow(tile); + has_snow = IsOnSnowOrDesert(tile); break; case MP_TREES: { diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp index 6e23f63c59..c12587c90e 100644 --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1628,7 +1628,7 @@ static void DrawRoadBits(TileInfo *ti) /* DrawFoundation() modifies ti. */ } - DrawRoadGroundSprites(ti, road, tram, road_rti, tram_rti, GetRoadside(ti->tile), IsOnSnow(ti->tile)); + DrawRoadGroundSprites(ti, road, tram, road_rti, tram_rti, GetRoadside(ti->tile), IsOnSnowOrDesert(ti->tile)); /* Draw one way */ if (road_rti != nullptr) { @@ -1720,7 +1720,7 @@ static void DrawTile_Road(TileInfo *ti) SpriteID image = SPR_ROAD_Y + axis; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowOrDesert(IsOnSnow(ti->tile), roadside)) { + if (DrawRoadAsSnowOrDesert(IsOnSnowOrDesert(ti->tile), roadside)) { image += 19; } else { switch (roadside) { @@ -1736,7 +1736,7 @@ static void DrawTile_Road(TileInfo *ti) if (IsCrossingBarred(ti->tile)) image += 2; Roadside roadside = GetRoadside(ti->tile); - if (DrawRoadAsSnowOrDesert(IsOnSnow(ti->tile), roadside)) { + if (DrawRoadAsSnowOrDesert(IsOnSnowOrDesert(ti->tile), roadside)) { image += 8; } else { switch (roadside) { @@ -1975,16 +1975,16 @@ static void TileLoop_Road(TileIndex tile) case LandscapeType::Arctic: { /* Roads on flat foundations use the snow level of the height they are elevated to. All others use the snow level of their minimum height. */ int tile_z = (std::get(GetFoundationSlope(tile)) == SLOPE_FLAT) ? GetTileMaxZ(tile) : GetTileZ(tile); - if (IsOnSnow(tile) != (tile_z > GetSnowLine())) { - ToggleSnow(tile); + if (IsOnSnowOrDesert(tile) != (tile_z > GetSnowLine())) { + ToggleSnowOrDesert(tile); MarkTileDirtyByTile(tile); } break; } case LandscapeType::Tropic: - if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnDesert(tile)) { - ToggleDesert(tile); + if (GetTropicZone(tile) == TROPICZONE_DESERT && !IsOnSnowOrDesert(tile)) { + ToggleSnowOrDesert(tile); MarkTileDirtyByTile(tile); } break; diff --git a/src/road_map.h b/src/road_map.h index 4d53bfdbe5..3ee5de72c1 100644 --- a/src/road_map.h +++ b/src/road_map.h @@ -433,25 +433,21 @@ inline void BarCrossing(Tile t) SetCrossingBarred(t, true); } -/** Check if a road tile has snow/desert. */ -#define IsOnDesert IsOnSnow /** * Check if a road tile has snow/desert. * @param t The tile to query. * @return True if the tile has snow/desert. */ -inline bool IsOnSnow(Tile t) +inline bool IsOnSnowOrDesert(Tile t) { return HasBit(t.m7(), 5); } -/** Toggle the snow/desert state of a road tile. */ -#define ToggleDesert ToggleSnow /** * Toggle the snow/desert state of a road tile. * @param t The tile to change. */ -inline void ToggleSnow(Tile t) +inline void ToggleSnowOrDesert(Tile t) { ToggleBit(t.m7(), 5); } From f82e172610970a1fd4aac889c4fef1e3ba285bc5 Mon Sep 17 00:00:00 2001 From: frosch Date: Thu, 17 Apr 2025 12:20:55 +0200 Subject: [PATCH 061/572] Codechange: Expand and remove DEF_CONSOLE_CMD and DEF_CONSOLE_HOOK macros. --- src/console_cmds.cpp | 184 +++++++++++++++++++++---------------------- 1 file changed, 88 insertions(+), 96 deletions(-) diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 948f1c0aef..1a7e1d6908 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -105,11 +105,6 @@ static ConsoleFileList _console_file_list_savegame{FT_SAVEGAME, true}; ///< File static ConsoleFileList _console_file_list_scenario{FT_SCENARIO, false}; ///< File storage cache for scenarios. static ConsoleFileList _console_file_list_heightmap{FT_HEIGHTMAP, false}; ///< File storage cache for heightmaps. -/* console command defines */ -#define DEF_CONSOLE_CMD(function) static bool function([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) -#define DEF_CONSOLE_HOOK(function) static ConsoleHookResult function(bool echo) - - /**************** * command hooks ****************/ @@ -131,7 +126,7 @@ static inline bool NetworkAvailable(bool echo) * Check whether we are a server. * @return Are we a server? True when yes, false otherwise. */ -DEF_CONSOLE_HOOK(ConHookServerOnly) +static ConsoleHookResult ConHookServerOnly(bool echo) { if (!NetworkAvailable(echo)) return CHR_DISALLOW; @@ -146,7 +141,7 @@ DEF_CONSOLE_HOOK(ConHookServerOnly) * Check whether we are a client in a network game. * @return Are we a client in a network game? True when yes, false otherwise. */ -DEF_CONSOLE_HOOK(ConHookClientOnly) +static ConsoleHookResult ConHookClientOnly(bool echo) { if (!NetworkAvailable(echo)) return CHR_DISALLOW; @@ -161,7 +156,7 @@ DEF_CONSOLE_HOOK(ConHookClientOnly) * Check whether we are in a multiplayer game. * @return True when we are client or server in a network game. */ -DEF_CONSOLE_HOOK(ConHookNeedNetwork) +static ConsoleHookResult ConHookNeedNetwork(bool echo) { if (!NetworkAvailable(echo)) return CHR_DISALLOW; @@ -176,7 +171,7 @@ DEF_CONSOLE_HOOK(ConHookNeedNetwork) * Check whether we are in a multiplayer game and are playing, i.e. we are not the dedicated server. * @return Are we a client or non-dedicated server in a network game? True when yes, false otherwise. */ -DEF_CONSOLE_HOOK(ConHookNeedNonDedicatedNetwork) +static ConsoleHookResult ConHookNeedNonDedicatedNetwork(bool echo) { if (!NetworkAvailable(echo)) return CHR_DISALLOW; @@ -191,7 +186,7 @@ DEF_CONSOLE_HOOK(ConHookNeedNonDedicatedNetwork) * Check whether we are in singleplayer mode. * @return True when no network is active. */ -DEF_CONSOLE_HOOK(ConHookNoNetwork) +static ConsoleHookResult ConHookNoNetwork(bool echo) { if (_networking) { if (echo) IConsolePrint(CC_ERROR, "This command is forbidden in multiplayer."); @@ -204,7 +199,7 @@ DEF_CONSOLE_HOOK(ConHookNoNetwork) * Check if are either in singleplayer or a server. * @return True iff we are either in singleplayer or a server. */ -DEF_CONSOLE_HOOK(ConHookServerOrNoNetwork) +static ConsoleHookResult ConHookServerOrNoNetwork(bool echo) { if (_networking && !_network_server) { if (echo) IConsolePrint(CC_ERROR, "This command is only available to a network server."); @@ -213,7 +208,7 @@ DEF_CONSOLE_HOOK(ConHookServerOrNoNetwork) return CHR_ALLOW; } -DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) +static ConsoleHookResult ConHookNewGRFDeveloperTool(bool echo) { if (_settings_client.gui.newgrf_developer_tools) { if (_game_mode == GM_MENU) { @@ -229,7 +224,7 @@ DEF_CONSOLE_HOOK(ConHookNewGRFDeveloperTool) * Reset status of all engines. * @return Will always succeed. */ -DEF_CONSOLE_CMD(ConResetEngines) +static bool ConResetEngines([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Reset status data of all engines. This might solve some issues with 'lost' engines. Usage: 'resetengines'."); @@ -245,7 +240,7 @@ DEF_CONSOLE_CMD(ConResetEngines) * @return Will always return true. * @note Resetting the pool only succeeds when there are no vehicles ingame. */ -DEF_CONSOLE_CMD(ConResetEnginePool) +static bool ConResetEnginePool([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Reset NewGRF allocations of engine slots. This will remove invalid engine definitions, and might make default engines available again."); @@ -271,7 +266,7 @@ DEF_CONSOLE_CMD(ConResetEnginePool) * param tile number. * @return True when the tile is reset or the help on usage was printed (0 or two parameters). */ -DEF_CONSOLE_CMD(ConResetTile) +static bool ConResetTile([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Reset a tile to bare land. Usage: 'resettile '."); @@ -296,7 +291,7 @@ DEF_CONSOLE_CMD(ConResetTile) * param level As defined by ZoomLevel and as limited by zoom_min/zoom_max from GUISettings. * @return True when either console help was shown or a proper amount of parameters given. */ -DEF_CONSOLE_CMD(ConZoomToLevel) +static bool ConZoomToLevel([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { switch (argc) { case 0: @@ -355,7 +350,7 @@ DEF_CONSOLE_CMD(ConZoomToLevel) * and y coordinates. * @return True when either console help was shown or a proper amount of parameters given. */ -DEF_CONSOLE_CMD(ConScrollToTile) +static bool ConScrollToTile([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Center the screen on a given tile."); @@ -409,7 +404,7 @@ DEF_CONSOLE_CMD(ConScrollToTile) * param filename the filename to save the map to. * @return True when help was displayed or the file attempted to be saved. */ -DEF_CONSOLE_CMD(ConSave) +static bool ConSave([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Save the current game. Usage: 'save '."); @@ -436,7 +431,7 @@ DEF_CONSOLE_CMD(ConSave) * Explicitly save the configuration. * @return True. */ -DEF_CONSOLE_CMD(ConSaveConfig) +static bool ConSaveConfig([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Saves the configuration for new games to the configuration file, typically 'openttd.cfg'."); @@ -449,7 +444,7 @@ DEF_CONSOLE_CMD(ConSaveConfig) return true; } -DEF_CONSOLE_CMD(ConLoad) +static bool ConLoad([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Load a game by name or index. Usage: 'load '."); @@ -475,7 +470,7 @@ DEF_CONSOLE_CMD(ConLoad) return true; } -DEF_CONSOLE_CMD(ConLoadScenario) +static bool ConLoadScenario([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Load a scenario by name or index. Usage: 'load_scenario '."); @@ -501,7 +496,7 @@ DEF_CONSOLE_CMD(ConLoadScenario) return true; } -DEF_CONSOLE_CMD(ConLoadHeightmap) +static bool ConLoadHeightmap([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Load a heightmap by name or index. Usage: 'load_heightmap '."); @@ -527,7 +522,7 @@ DEF_CONSOLE_CMD(ConLoadHeightmap) return true; } -DEF_CONSOLE_CMD(ConRemove) +static bool ConRemove([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Remove a savegame by name or index. Usage: 'rm '."); @@ -553,7 +548,7 @@ DEF_CONSOLE_CMD(ConRemove) /* List all the files in the current dir via console */ -DEF_CONSOLE_CMD(ConListFiles) +static bool ConListFiles([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List all loadable savegames and directories in the current dir via console. Usage: 'ls | dir'."); @@ -569,7 +564,7 @@ DEF_CONSOLE_CMD(ConListFiles) } /* List all the scenarios */ -DEF_CONSOLE_CMD(ConListScenarios) +static bool ConListScenarios([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List all loadable scenarios. Usage: 'list_scenarios'."); @@ -585,7 +580,7 @@ DEF_CONSOLE_CMD(ConListScenarios) } /* List all the heightmaps */ -DEF_CONSOLE_CMD(ConListHeightmaps) +static bool ConListHeightmaps([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List all loadable heightmaps. Usage: 'list_heightmaps'."); @@ -601,7 +596,7 @@ DEF_CONSOLE_CMD(ConListHeightmaps) } /* Change the dir via console */ -DEF_CONSOLE_CMD(ConChangeDirectory) +static bool ConChangeDirectory([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Change the dir via console. Usage: 'cd '."); @@ -630,7 +625,7 @@ DEF_CONSOLE_CMD(ConChangeDirectory) return true; } -DEF_CONSOLE_CMD(ConPrintWorkingDirectory) +static bool ConPrintWorkingDirectory([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Print out the current working directory. Usage: 'pwd'."); @@ -645,7 +640,7 @@ DEF_CONSOLE_CMD(ConPrintWorkingDirectory) return true; } -DEF_CONSOLE_CMD(ConClearBuffer) +static bool ConClearBuffer([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Clear the console buffer. Usage: 'clear'."); @@ -705,7 +700,7 @@ static bool ConKickOrBan(const char *argv, bool ban, const std::string &reason) return true; } -DEF_CONSOLE_CMD(ConKick) +static bool ConKick([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Kick a client from a network game. Usage: 'kick []'."); @@ -728,7 +723,7 @@ DEF_CONSOLE_CMD(ConKick) } } -DEF_CONSOLE_CMD(ConBan) +static bool ConBan([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Ban a client from a network game. Usage: 'ban []'."); @@ -752,7 +747,7 @@ DEF_CONSOLE_CMD(ConBan) } } -DEF_CONSOLE_CMD(ConUnBan) +static bool ConUnBan([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Unban a client from a network game. Usage: 'unban '."); @@ -784,7 +779,7 @@ DEF_CONSOLE_CMD(ConUnBan) return true; } -DEF_CONSOLE_CMD(ConBanList) +static bool ConBanList([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List the IP's of banned clients: Usage 'banlist'."); @@ -802,7 +797,7 @@ DEF_CONSOLE_CMD(ConBanList) return true; } -DEF_CONSOLE_CMD(ConPauseGame) +static bool ConPauseGame([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Pause a network game. Usage: 'pause'."); @@ -824,7 +819,7 @@ DEF_CONSOLE_CMD(ConPauseGame) return true; } -DEF_CONSOLE_CMD(ConUnpauseGame) +static bool ConUnpauseGame([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Unpause a network game. Usage: 'unpause'."); @@ -850,7 +845,7 @@ DEF_CONSOLE_CMD(ConUnpauseGame) return true; } -DEF_CONSOLE_CMD(ConRcon) +static bool ConRcon([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Remote control the server from another client. Usage: 'rcon '."); @@ -869,7 +864,7 @@ DEF_CONSOLE_CMD(ConRcon) return true; } -DEF_CONSOLE_CMD(ConStatus) +static bool ConStatus([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List the status of all clients connected to the server. Usage 'status'."); @@ -880,7 +875,7 @@ DEF_CONSOLE_CMD(ConStatus) return true; } -DEF_CONSOLE_CMD(ConServerInfo) +static bool ConServerInfo([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "List current and maximum client/company limits. Usage 'server_info'."); @@ -896,7 +891,7 @@ DEF_CONSOLE_CMD(ConServerInfo) return true; } -DEF_CONSOLE_CMD(ConClientNickChange) +static bool ConClientNickChange([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc != 3) { IConsolePrint(CC_HELP, "Change the nickname of a connected client. Usage: 'client_name '."); @@ -930,7 +925,7 @@ DEF_CONSOLE_CMD(ConClientNickChange) return true; } -DEF_CONSOLE_CMD(ConJoinCompany) +static bool ConJoinCompany([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc < 2) { IConsolePrint(CC_HELP, "Request joining another company. Usage: 'join '."); @@ -977,7 +972,7 @@ DEF_CONSOLE_CMD(ConJoinCompany) return true; } -DEF_CONSOLE_CMD(ConMoveClient) +static bool ConMoveClient([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc < 3) { IConsolePrint(CC_HELP, "Move a client to another company. Usage: 'move '."); @@ -1020,7 +1015,7 @@ DEF_CONSOLE_CMD(ConMoveClient) return true; } -DEF_CONSOLE_CMD(ConResetCompany) +static bool ConResetCompany([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Remove an idle company from the game. Usage: 'reset_company '."); @@ -1061,7 +1056,7 @@ DEF_CONSOLE_CMD(ConResetCompany) return true; } -DEF_CONSOLE_CMD(ConNetworkClients) +static bool ConNetworkClients([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Get a list of connected clients including their ID, name, company-id, and IP. Usage: 'clients'."); @@ -1073,7 +1068,7 @@ DEF_CONSOLE_CMD(ConNetworkClients) return true; } -DEF_CONSOLE_CMD(ConNetworkReconnect) +static bool ConNetworkReconnect([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Reconnect to server to which you were connected last time. Usage: 'reconnect []'."); @@ -1104,7 +1099,7 @@ DEF_CONSOLE_CMD(ConNetworkReconnect) return NetworkClientConnectGame(_settings_client.network.last_joined, playas); } -DEF_CONSOLE_CMD(ConNetworkConnect) +static bool ConNetworkConnect([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Connect to a remote OTTD server and join the game. Usage: 'connect '."); @@ -1122,7 +1117,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect) * script file console commands *********************************/ -DEF_CONSOLE_CMD(ConExec) +static bool ConExec([[maybe_unused]] uint8_t argc, [[maybe_unused]] char *argv[]) { if (argc == 0) { IConsolePrint(CC_HELP, "Execute a local script file. Usage: 'exec