diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 06d9af2185..3d68b85958 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -14,6 +14,10 @@ on: env: CTEST_OUTPUT_ON_FAILURE: 1 +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + jobs: emscripten: name: Emscripten diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 84d20ccbc0..b05300775a 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -14,6 +14,10 @@ on: description: 'Ref to build (for Pull Requests, use refs/pull/NNN/head)' required: true +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + jobs: analyze: name: Analyze diff --git a/.github/workflows/unused-strings.yml b/.github/workflows/unused-strings.yml index 2f9be039b1..1f6da48cbc 100644 --- a/.github/workflows/unused-strings.yml +++ b/.github/workflows/unused-strings.yml @@ -4,6 +4,10 @@ on: workflow_dispatch: # pull_request: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + jobs: unused-strings: name: Unused strings diff --git a/CMakeLists.txt b/CMakeLists.txt index d4f76ae213..2dbf18bc34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -367,6 +367,8 @@ if(NOT OPTION_DEDICATED) endif() endif() +include(CheckAtomic) + if(APPLE) link_package(Iconv TARGET Iconv::Iconv) diff --git a/cmake/CheckAtomic.cmake b/cmake/CheckAtomic.cmake new file mode 100644 index 0000000000..52d93f4f5b --- /dev/null +++ b/cmake/CheckAtomic.cmake @@ -0,0 +1,87 @@ +# atomic builtins are required for threading support. + +INCLUDE(CheckCXXSourceCompiles) +INCLUDE(CheckLibraryExists) + +# Sometimes linking against libatomic is required for atomic ops, if +# the platform doesn't support lock-free atomics. + +function(check_working_cxx_atomics varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++17") + check_cxx_source_compiles(" +#include +std::atomic x; +std::atomic y; +std::atomic z; +int main() { + ++z; + ++y; + return ++x; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics) + +function(check_working_cxx_atomics64 varname) + set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + set(CMAKE_REQUIRED_FLAGS "-std=c++17 ${CMAKE_REQUIRED_FLAGS}") + check_cxx_source_compiles(" +#include +#include +std::atomic x (0); +int main() { + uint64_t i = x.load(std::memory_order_relaxed); + (void)i; + return 0; +} +" ${varname}) + set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS}) +endfunction(check_working_cxx_atomics64) + + +# Check for (non-64-bit) atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS_WITHOUT_LIB True) +else() + # First check if atomics work without the library. + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB) + # If not, check if the library exists, and atomics work with it. + if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB) + check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC) + if(HAVE_LIBATOMIC) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS_WITH_LIB) + message(FATAL_ERROR "Host compiler must support std::atomic!") + endif() + else() + message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.") + endif() + endif() +endif() + +# Check for 64 bit atomic operations. +if(MSVC) + set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True) +else() + # First check if atomics work without the library. + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB) + # If not, check if the library exists, and atomics work with it. + if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB) + check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64) + if(HAVE_CXX_LIBATOMICS64) + list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic") + check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB) + if (NOT HAVE_CXX_ATOMICS64_WITH_LIB) + message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!") + endif() + else() + message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.") + endif() + endif() +endif() + +if(HAVE_CXX_ATOMICS_WITH_LIB OR HAVE_CXX_ATOMICS64_WITH_LIB) + target_link_libraries(openttd atomic) +endif() diff --git a/cmake/scripts/SquirrelExport.cmake b/cmake/scripts/SquirrelExport.cmake index e5d83714b9..d13bd8d4d0 100644 --- a/cmake/scripts/SquirrelExport.cmake +++ b/cmake/scripts/SquirrelExport.cmake @@ -28,25 +28,27 @@ endmacro() macro(dump_class_templates NAME) string(REGEX REPLACE "^Script" "" REALNAME ${NAME}) - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${NAME} *GetParam(ForceType<${NAME} *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${NAME} &GetParam(ForceType<${NAME} &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline const ${NAME} &GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} *> { static inline ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${NAME} &> { static inline ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return (${NAME} *)instance; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param { static inline const ${NAME} &Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, nullptr); return *(${NAME} *)instance; } };") if("${NAME}" STREQUAL "ScriptEvent") - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${NAME} *>(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };") elseif("${NAME}" STREQUAL "ScriptText") string(APPEND SQUIRREL_EXPORT "\n") - string(APPEND SQUIRREL_EXPORT "\n template <> inline Text *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {") - string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {") - string(APPEND SQUIRREL_EXPORT "\n return GetParam(ForceType(), vm, index, ptr);") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param {") + string(APPEND SQUIRREL_EXPORT "\n static inline Text *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) {") + string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_INSTANCE) {") + string(APPEND SQUIRREL_EXPORT "\n return Param::Get(vm, index, ptr);") + string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") + string(APPEND SQUIRREL_EXPORT "\n return new RawText(Param::Get(vm, index, ptr));") + string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n return nullptr;") string(APPEND SQUIRREL_EXPORT "\n }") - string(APPEND SQUIRREL_EXPORT "\n if (sq_gettype(vm, index) == OT_STRING) {") - string(APPEND SQUIRREL_EXPORT "\n return new RawText(GetParam(ForceType(), vm, index, ptr));") - string(APPEND SQUIRREL_EXPORT "\n }") - string(APPEND SQUIRREL_EXPORT "\n return nullptr;") - string(APPEND SQUIRREL_EXPORT "\n }") + string(APPEND SQUIRREL_EXPORT "\n };") else() - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${NAME} *>(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${NAME} *> { static inline int Set(HSQUIRRELVM vm, ${NAME} *res) { if (res == nullptr) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, \"${REALNAME}\", res, nullptr, DefSQDestructorCallback<${NAME}>, true); return 1; } };") endif() endmacro() @@ -297,8 +299,8 @@ foreach(LINE IN LISTS SOURCE_LINES) endif() string(APPEND SQUIRREL_EXPORT "\n /* Allow enums to be used as Squirrel parameters */") foreach(ENUM IN LISTS ENUMS) - string(APPEND SQUIRREL_EXPORT "\n template <> inline ${ENUM} GetParam(ForceType<${ENUM}>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; }") - string(APPEND SQUIRREL_EXPORT "\n template <> inline int Return<${ENUM}>(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; }") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Param<${ENUM}> { static inline ${ENUM} Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (${ENUM})tmp; } };") + string(APPEND SQUIRREL_EXPORT "\n template <> struct Return<${ENUM}> { static inline int Set(HSQUIRRELVM vm, ${ENUM} res) { sq_pushinteger(vm, res); return 1; } };") endforeach() endif() @@ -625,7 +627,7 @@ foreach(LINE IN LISTS SOURCE_LINES) string(APPEND TYPES "p") elseif("${PARAM}" MATCHES "^Array") string(APPEND TYPES "a") - elseif("${PARAM}" MATCHES "^struct Array") + elseif("${PARAM}" MATCHES "^const Array") string(APPEND TYPES "a") elseif("${PARAM}" MATCHES "^Text") string(APPEND TYPES ".") diff --git a/regression/regression/result.txt b/regression/regression/result.txt index 13a770a8aa..9942857cfb 100644 --- a/regression/regression/result.txt +++ b/regression/regression/result.txt @@ -588,7 +588,7 @@ ERROR: IsEnd() is invalid as Begin() is never called SetName(): false GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE GetName(): Regression - GetPresidentName(): E. McAlpine + GetPresidentName(): J. Green SetPresidentName(): true GetPresidentName(): Regression AI GetBankBalance(): 100000 diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp index e1b73448dd..977b5e674a 100644 --- a/src/autoreplace.cpp +++ b/src/autoreplace.cpp @@ -69,7 +69,18 @@ EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, /* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */ er = GetEngineReplacement(erl, engine, ALL_GROUP); } - if (replace_when_old != nullptr) *replace_when_old = er == nullptr ? false : er->replace_when_old; + if (replace_when_old != nullptr) { + if (er == nullptr) { + /* Not replacing */ + *replace_when_old = false; + } else if (er->to == engine) { + /* When replacing with same model, only ever do it when old */ + *replace_when_old = true; + } else { + /* Use player setting */ + *replace_when_old = er->replace_when_old; + } + } return er == nullptr ? INVALID_ENGINE : er->to; } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index 49d3a81c54..36e2556b5f 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -56,9 +56,6 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company) { assert(Engine::IsValidID(from) && Engine::IsValidID(to)); - /* we can't replace an engine into itself (that would be autorenew) */ - if (from == to) return false; - const Engine *e_from = Engine::Get(from); const Engine *e_to = Engine::Get(to); VehicleType type = e_from->type; diff --git a/src/company_gui.cpp b/src/company_gui.cpp index e9bf2c045d..d797daef9f 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2544,6 +2544,70 @@ struct CompanyWindow : Window } } + void DrawVehicleCountsWidget(const Rect &r, const Company *c) const + { + static_assert(VEH_COMPANY_END == lengthof(_company_view_vehicle_count_strings)); + + int y = r.top; + for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) { + uint amount = c->group_all[type].num_vehicle; + if (amount != 0) { + SetDParam(0, amount); + DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[type]); + y += FONT_HEIGHT_NORMAL; + } + } + + if (y == r.top) { + /* No String was emited before, so there must be no vehicles at all. */ + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE); + } + } + + void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const + { + int y = r.top; + + uint rail_pieces = c->infrastructure.signal; + for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pieces += c->infrastructure.rail[i]; + if (rail_pieces != 0) { + SetDParam(0, rail_pieces); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL); + y += FONT_HEIGHT_NORMAL; + } + + uint road_pieces = 0; + for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i]; + if (road_pieces != 0) { + SetDParam(0, road_pieces); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD); + y += FONT_HEIGHT_NORMAL; + } + + if (c->infrastructure.water != 0) { + SetDParam(0, c->infrastructure.water); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER); + y += FONT_HEIGHT_NORMAL; + } + + if (c->infrastructure.station != 0) { + SetDParam(0, c->infrastructure.station); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION); + y += FONT_HEIGHT_NORMAL; + } + + if (c->infrastructure.airport != 0) { + SetDParam(0, c->infrastructure.airport); + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT); + y += FONT_HEIGHT_NORMAL; + } + + if (y == r.top) { + /* No String was emited before, so there must be no infrastructure at all. */ + DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + } + } + void DrawWidget(const Rect &r, int widget) const override { const Company *c = Company::Get((CompanyID)this->window_number); @@ -2565,70 +2629,13 @@ struct CompanyWindow : Window break; } - case WID_C_DESC_VEHICLE_COUNTS: { - uint amounts[4]; - amounts[0] = c->group_all[VEH_TRAIN].num_vehicle; - amounts[1] = c->group_all[VEH_ROAD].num_vehicle; - amounts[2] = c->group_all[VEH_SHIP].num_vehicle; - amounts[3] = c->group_all[VEH_AIRCRAFT].num_vehicle; - - int y = r.top; - if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) { - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE); - } else { - static_assert(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); - - for (uint i = 0; i < lengthof(amounts); i++) { - if (amounts[i] != 0) { - SetDParam(0, amounts[i]); - DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]); - y += FONT_HEIGHT_NORMAL; - } - } - } + case WID_C_DESC_VEHICLE_COUNTS: + DrawVehicleCountsWidget(r, c); break; - } - - case WID_C_DESC_INFRASTRUCTURE_COUNTS: { - uint y = r.top; - - /* Collect rail and road counts. */ - uint rail_pieces = c->infrastructure.signal; - uint road_pieces = 0; - for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pieces += c->infrastructure.rail[i]; - for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i]; - - if (rail_pieces == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) { - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); - } else { - if (rail_pieces != 0) { - SetDParam(0, rail_pieces); - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL); - y += FONT_HEIGHT_NORMAL; - } - if (road_pieces != 0) { - SetDParam(0, road_pieces); - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD); - y += FONT_HEIGHT_NORMAL; - } - if (c->infrastructure.water != 0) { - SetDParam(0, c->infrastructure.water); - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER); - y += FONT_HEIGHT_NORMAL; - } - if (c->infrastructure.station != 0) { - SetDParam(0, c->infrastructure.station); - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION); - y += FONT_HEIGHT_NORMAL; - } - if (c->infrastructure.airport != 0) { - SetDParam(0, c->infrastructure.airport); - DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT); - } - } + case WID_C_DESC_INFRASTRUCTURE_COUNTS: + DrawInfrastructureCountsWidget(r, c); break; - } case WID_C_DESC_OWNERS: { uint y = r.top; diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index ad509c04e7..74cfb6fc54 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -19,6 +19,7 @@ #include "game_info.hpp" #include "table/strings.h" +#include "table/strgen_tables.h" #include #include @@ -273,6 +274,31 @@ GameStrings *LoadTranslations() } } +static StringParam::ParamType GetParamType(const CmdStruct *cs) +{ + if (cs->value == SCC_RAW_STRING_POINTER) return StringParam::RAW_STRING; + if (cs->value == SCC_STRING || cs != TranslateCmdForCompare(cs)) return StringParam::STRING; + return StringParam::OTHER; +} + +static void ExtractStringParams(const StringData &data, StringParamsList ¶ms) +{ + for (size_t i = 0; i < data.max_strings; i++) { + const LangString *ls = data.strings[i]; + + if (ls != nullptr) { + StringParams ¶m = params.emplace_back(); + ParsedCommandStruct pcs; + ExtractCommandString(&pcs, ls->english, false); + + for (const CmdStruct *cs : pcs.cmd) { + if (cs == nullptr) break; + param.emplace_back(GetParamType(cs), cs->consumes); + } + } + } +} + /** Compile the language. */ void GameStrings::Compile() { @@ -283,6 +309,8 @@ void GameStrings::Compile() this->version = data.Version(); + ExtractStringParams(data, this->string_params); + StringNameWriter id_writer(this->string_names); id_writer.WriteHeader(data); @@ -312,6 +340,20 @@ const char *GetGameStringPtr(uint id) return _current_data->cur_language->lines[id].c_str(); } +/** + * Get the string parameters of a particular game string. + * @param id The ID of the game string. + * @return The string parameters. + */ +const StringParams &GetGameStringParams(uint id) +{ + /* An empty result for STR_UNDEFINED. */ + static StringParams empty; + + if (id >= _current_data->string_params.size()) return empty; + return _current_data->string_params[id]; +} + /** * Register the current translation to the Squirrel engine. * @param engine The engine to update/ diff --git a/src/game/game_text.hpp b/src/game/game_text.hpp index 91d85847df..7aebf885e3 100644 --- a/src/game/game_text.hpp +++ b/src/game/game_text.hpp @@ -12,7 +12,23 @@ #include "../core/smallvec_type.hpp" +struct StringParam { + enum ParamType { + RAW_STRING, + STRING, + OTHER + }; + + ParamType type; + uint8 consumes; + + StringParam(ParamType type, uint8 consumes) : type(type), consumes(consumes) {} +}; +using StringParams = std::vector; +using StringParamsList = std::vector; + const char *GetGameStringPtr(uint id); +const StringParams &GetGameStringParams(uint id); void RegisterGameTranslation(class Squirrel *engine); void ReconsiderGameScriptLanguage(); @@ -37,6 +53,7 @@ struct GameStrings { std::vector raw_strings; ///< The raw strings per language, first must be English/the master language!. std::vector compiled_strings; ///< The compiled strings per language, first must be English/the master language!. StringList string_names; ///< The names of the compiled strings. + StringParamsList string_params; ///< The parameters for the strings. void Compile(); diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 3e5d2daa3d..376b26ea36 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -189,11 +189,13 @@ void GamelogPrint(GamelogPrintProc *proc) switch (lc->ct) { default: NOT_REACHED(); case GLCT_MODE: + /* Changing landscape, or going from scenario editor to game or back. */ buf += seprintf(buf, lastof(buffer), "New game mode: %u landscape: %u", (uint)lc->mode.mode, (uint)lc->mode.landscape); break; case GLCT_REVISION: + /* The game was loaded in a diffferent version than before. */ buf += seprintf(buf, lastof(buffer), "Revision text changed to %s, savegame version %u, ", lc->revision.text, lc->revision.slver); @@ -207,6 +209,7 @@ void GamelogPrint(GamelogPrintProc *proc) break; case GLCT_OLDVER: + /* The game was loaded from before 0.7.0-beta1. */ buf += seprintf(buf, lastof(buffer), "Conversion from "); switch (lc->oldver.type) { default: NOT_REACHED(); @@ -237,10 +240,12 @@ void GamelogPrint(GamelogPrintProc *proc) break; case GLCT_SETTING: + /* A setting with the SF_NO_NETWORK flag got changed; these settings usually affect NewGRFs, such as road side or wagon speed limits. */ buf += seprintf(buf, lastof(buffer), "Setting changed: %s : %d -> %d", lc->setting.name, lc->setting.oldval, lc->setting.newval); break; case GLCT_GRFADD: { + /* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */ const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum); buf += seprintf(buf, lastof(buffer), "Added NewGRF: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfadd.grfid, lc->grfadd.md5sum, gc); @@ -251,6 +256,7 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_GRFREM: { + /* A NewGRF got removed from the game, either manually or by it missing when loading the game. */ GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), la->at == GLAT_LOAD ? "Missing NewGRF: " : "Removed NewGRF: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfrem.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); @@ -268,6 +274,7 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_GRFCOMPAT: { + /* Another version of the same NewGRF got loaded. */ const GRFConfig *gc = FindGRFConfig(lc->grfadd.grfid, FGCM_EXACT, lc->grfadd.md5sum); buf += seprintf(buf, lastof(buffer), "Compatible NewGRF loaded: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfcompat.grfid, lc->grfcompat.md5sum, gc); @@ -277,6 +284,7 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_GRFPARAM: { + /* A parameter of a NewGRF got changed after the game was started. */ GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF parameter changed: "); buf = PrintGrfInfo(buf, lastof(buffer), lc->grfparam.grfid, nullptr, gm != grf_names.End() ? gm->second.gc : nullptr); @@ -285,6 +293,7 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_GRFMOVE: { + /* The order of NewGRFs got changed, which might cause some other NewGRFs to behave differently. */ GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); buf += seprintf(buf, lastof(buffer), "GRF order changed: %08X moved %d places %s", BSWAP32(lc->grfmove.grfid), abs(lc->grfmove.offset), lc->grfmove.offset >= 0 ? "down" : "up" ); @@ -294,6 +303,7 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_GRFBUG: { + /* A specific bug in a NewGRF, that could cause wide spread problems, has been noted during the execution of the game. */ GrfIDMapping::Pair *gm = grf_names.Find(lc->grfrem.grfid); switch (lc->grfbug.bug) { default: NOT_REACHED(); @@ -307,6 +317,8 @@ void GamelogPrint(GamelogPrintProc *proc) } case GLCT_EMERGENCY: + /* At one point the savegame was made during the handling of a game crash. + * The generic code already mentioned the emergency savegame, and there is no extra information to log. */ break; } diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 5a5529f7c4..94ea2bf9b3 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -556,171 +556,194 @@ static bool TransportIndustryGoods(TileIndex tile) return moved_cargo; } +static void AnimateSugarSieve(TileIndex tile) +{ + byte m = GetAnimationFrame(tile) + 1; -void AnimateTile_Industry(TileIndex tile) + if (_settings_client.sound.ambient) { + switch (m & 7) { + case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break; + case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break; + } + } + + if (m >= 96) { + m = 0; + DeleteAnimatedTile(tile); + } + SetAnimationFrame(tile, m); + + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); +} + +static void AnimateToffeeQuarry(TileIndex tile) { - IndustryGfx gfx = GetIndustryGfx(tile); + byte m = GetAnimationFrame(tile); - if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) { - AnimateNewIndustryTile(tile); - return; + if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) { + SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile); } - switch (gfx) { - case GFX_SUGAR_MINE_SIEVE: - if ((_scaled_tick_counter & 1) == 0) { - byte m = GetAnimationFrame(tile) + 1; + if (++m >= 70) { + m = 0; + DeleteAnimatedTile(tile); + } + SetAnimationFrame(tile, m); - if (_settings_client.sound.ambient) { - switch (m & 7) { - case 2: SndPlayTileFx(SND_2D_SUGAR_MINE_1, tile); break; - case 6: SndPlayTileFx(SND_29_SUGAR_MINE_2, tile); break; - } - } + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); +} - if (m >= 96) { - m = 0; - DeleteAnimatedTile(tile); - } - SetAnimationFrame(tile, m); +static void AnimateBubbleCatcher(TileIndex tile) +{ + byte m = GetAnimationFrame(tile); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } - break; + if (++m >= 40) { + m = 0; + DeleteAnimatedTile(tile); + } + SetAnimationFrame(tile, m); - case GFX_TOFFEE_QUARY: - if ((_scaled_tick_counter & 3) == 0) { - byte m = GetAnimationFrame(tile); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); +} - if (_industry_anim_offs_toffee[m] == 0xFF && _settings_client.sound.ambient) { - SndPlayTileFx(SND_30_TOFFEE_QUARRY, tile); - } +static void AnimatePowerPlantSparks(TileIndex tile) +{ + byte m = GetAnimationFrame(tile); + if (m == 6) { + SetAnimationFrame(tile, 0); + DeleteAnimatedTile(tile); + } else { + SetAnimationFrame(tile, m + 1); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + } +} - if (++m >= 70) { +static void AnimateToyFactory(TileIndex tile) +{ + byte m = GetAnimationFrame(tile) + 1; + + switch (m) { + case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break; + case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break; + case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break; + default: + if (m >= 50) { + int n = GetIndustryAnimationLoop(tile) + 1; m = 0; - DeleteAnimatedTile(tile); + if (n >= 8) { + n = 0; + DeleteAnimatedTile(tile); + } + SetIndustryAnimationLoop(tile, n); } - SetAnimationFrame(tile, m); + } - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } - break; + SetAnimationFrame(tile, m); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); +} - case GFX_BUBBLE_CATCHER: - if ((_scaled_tick_counter & 1) == 0) { - byte m = GetAnimationFrame(tile); +static void AnimatePlasticFountain(TileIndex tile, IndustryGfx gfx) +{ + gfx = (gfx < GFX_PLASTIC_FOUNTAIN_ANIMATED_8) ? gfx + 1 : GFX_PLASTIC_FOUNTAIN_ANIMATED_1; + SetIndustryGfx(tile, gfx); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); +} - if (++m >= 40) { - m = 0; - DeleteAnimatedTile(tile); - } - SetAnimationFrame(tile, m); +static void AnimateOilWell(TileIndex tile, IndustryGfx gfx) +{ + bool b = Chance16(1, 7); + byte m = GetAnimationFrame(tile) + 1; + if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) { + SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED); + SetIndustryConstructionStage(tile, 3); + DeleteAnimatedTile(tile); + } else { + SetAnimationFrame(tile, m); + SetIndustryGfx(tile, gfx); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + } +} - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } - break; +static void AnimateMineTower(TileIndex tile) +{ + int state = _scaled_tick_counter & 0x7FF; - /* Sparks on a coal plant */ - case GFX_POWERPLANT_SPARKS: - if ((_scaled_tick_counter & 3) == 0) { + if ((state -= 0x400) < 0) return; + + if (state < 0x1A0) { + if (state < 0x20 || state >= 0x180) { byte m = GetAnimationFrame(tile); - if (m == 6) { - SetAnimationFrame(tile, 0); - DeleteAnimatedTile(tile); - } else { - SetAnimationFrame(tile, m + 1); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + if (!(m & 0x40)) { + SetAnimationFrame(tile, m | 0x40); + if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile); } + if (state & 7) return; + } else { + if (state & 3) return; } + byte m = (GetAnimationFrame(tile) + 1) | 0x40; + if (m > 0xC2) m = 0xC0; + SetAnimationFrame(tile, m); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + } else if (state >= 0x200 && state < 0x3A0) { + int i = (state < 0x220 || state >= 0x380) ? 7 : 3; + if (state & i) return; + + byte m = (GetAnimationFrame(tile) & 0xBF) - 1; + if (m < 0x80) m = 0x82; + SetAnimationFrame(tile, m); + MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); + } +} + +void AnimateTile_Industry(TileIndex tile) +{ + IndustryGfx gfx = GetIndustryGfx(tile); + + if (GetIndustryTileSpec(gfx)->animation.status != ANIM_STATUS_NO_ANIMATION) { + AnimateNewIndustryTile(tile); + return; + } + + switch (gfx) { + case GFX_SUGAR_MINE_SIEVE: + if ((_scaled_tick_counter & 1) == 0) AnimateSugarSieve(tile); break; - case GFX_TOY_FACTORY: - if ((_scaled_tick_counter & 1) == 0) { - byte m = GetAnimationFrame(tile) + 1; - - switch (m) { - case 1: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2C_TOY_FACTORY_1, tile); break; - case 23: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2B_TOY_FACTORY_2, tile); break; - case 28: if (_settings_client.sound.ambient) SndPlayTileFx(SND_2A_TOY_FACTORY_3, tile); break; - default: - if (m >= 50) { - int n = GetIndustryAnimationLoop(tile) + 1; - m = 0; - if (n >= 8) { - n = 0; - DeleteAnimatedTile(tile); - } - SetIndustryAnimationLoop(tile, n); - } - } + case GFX_TOFFEE_QUARY: + if ((_scaled_tick_counter & 3) == 0) AnimateToffeeQuarry(tile); + break; - SetAnimationFrame(tile, m); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } + case GFX_BUBBLE_CATCHER: + if ((_scaled_tick_counter & 1) == 0) AnimateBubbleCatcher(tile); + break; + + case GFX_POWERPLANT_SPARKS: + if ((_scaled_tick_counter & 3) == 0) AnimatePowerPlantSparks(tile); + break; + + case GFX_TOY_FACTORY: + if ((_scaled_tick_counter & 1) == 0) AnimateToyFactory(tile); break; case GFX_PLASTIC_FOUNTAIN_ANIMATED_1: case GFX_PLASTIC_FOUNTAIN_ANIMATED_2: case GFX_PLASTIC_FOUNTAIN_ANIMATED_3: case GFX_PLASTIC_FOUNTAIN_ANIMATED_4: case GFX_PLASTIC_FOUNTAIN_ANIMATED_5: case GFX_PLASTIC_FOUNTAIN_ANIMATED_6: case GFX_PLASTIC_FOUNTAIN_ANIMATED_7: case GFX_PLASTIC_FOUNTAIN_ANIMATED_8: - if ((_scaled_tick_counter & 3) == 0) { - IndustryGfx new_gfx = (gfx < 155) ? gfx + 1 : 148; - SetIndustryGfx(tile, new_gfx); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } + if ((_scaled_tick_counter & 3) == 0) AnimatePlasticFountain(tile, gfx); break; case GFX_OILWELL_ANIMATED_1: case GFX_OILWELL_ANIMATED_2: case GFX_OILWELL_ANIMATED_3: - if ((_scaled_tick_counter & 7) == 0) { - bool b = Chance16(1, 7); - byte m = GetAnimationFrame(tile) + 1; - if (m == 4 && (m = 0, ++gfx) == GFX_OILWELL_ANIMATED_3 + 1 && (gfx = GFX_OILWELL_ANIMATED_1, b)) { - SetIndustryGfx(tile, GFX_OILWELL_NOT_ANIMATED); - SetIndustryConstructionStage(tile, 3); - DeleteAnimatedTile(tile); - } else { - SetAnimationFrame(tile, m); - SetIndustryGfx(tile, gfx); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } - } + if ((_scaled_tick_counter & 7) == 0) AnimateOilWell(tile, gfx); break; case GFX_COAL_MINE_TOWER_ANIMATED: case GFX_COPPER_MINE_TOWER_ANIMATED: - case GFX_GOLD_MINE_TOWER_ANIMATED: { - int state = _scaled_tick_counter & 0x7FF; - - if ((state -= 0x400) < 0) return; - - if (state < 0x1A0) { - if (state < 0x20 || state >= 0x180) { - byte m = GetAnimationFrame(tile); - if (!(m & 0x40)) { - SetAnimationFrame(tile, m | 0x40); - if (_settings_client.sound.ambient) SndPlayTileFx(SND_0B_MINE, tile); - } - if (state & 7) return; - } else { - if (state & 3) return; - } - byte m = (GetAnimationFrame(tile) + 1) | 0x40; - if (m > 0xC2) m = 0xC0; - SetAnimationFrame(tile, m); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } else if (state >= 0x200 && state < 0x3A0) { - int i = (state < 0x220 || state >= 0x380) ? 7 : 3; - if (state & i) return; - - byte m = (GetAnimationFrame(tile) & 0xBF) - 1; - if (m < 0x80) m = 0x82; - SetAnimationFrame(tile, m); - MarkTileDirtyByTile(tile, VMDF_NOT_MAP_MODE); - } - break; - } + case GFX_GOLD_MINE_TOWER_ANIMATED: + AnimateMineTower(tile); + break; } } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index 41f8ed08ad..8edb01c2b2 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -39,6 +39,8 @@ #include "widgets/industry_widget.h" #include "clear_map.h" #include "zoom_func.h" +#include "querystring_gui.h" +#include "stringfilter_type.h" #include "table/strings.h" @@ -1248,12 +1250,17 @@ static const NWidgetPart _nested_industry_directory_widgets[] = { EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_ACC_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), - NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_PROD_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), - NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_ID_DROPDOWN_ORDER), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_DROPDOWN_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), + NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_ID_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_ACC_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_ID_FILTER_BY_PROD_CARGO), SetMinimalSize(225, 12), SetFill(0, 1), SetDataTip(STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER, STR_TOOLTIP_FILTER_CRITERIA), + NWidget(WWT_PANEL, COLOUR_BROWN), SetResize(1, 0), EndContainer(), + EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN, WID_ID_INDUSTRY_LIST), SetDataTip(0x0, STR_INDUSTRY_DIRECTORY_LIST_CAPTION), SetResize(1, 1), SetScrollbar(WID_ID_SCROLLBAR), EndContainer(), EndContainer(), @@ -1349,6 +1356,10 @@ protected: byte accepted_cargo_filter_criteria; ///< Selected accepted cargo filter index static CargoID produced_cargo_filter; + const int MAX_FILTER_LENGTH = 16; ///< The max length of the filter, in chars + StringFilter string_filter; ///< Filter for industries + QueryString industry_editbox; ///< Filter editbox + enum class SorterType : uint8 { ByName, ///< Sorter type to sort by name ByType, ///< Sorter type to sort by type @@ -1433,7 +1444,13 @@ protected: this->industries.clear(); for (const Industry *i : Industry::Iterate()) { - this->industries.push_back(i); + if (this->string_filter.IsEmpty()) { + this->industries.push_back(i); + continue; + } + this->string_filter.ResetState(); + this->string_filter.AddLine(i->GetCachedName()); + if (this->string_filter.GetState()) this->industries.push_back(i); } this->industries.shrink_to_fit(); @@ -1633,7 +1650,7 @@ protected: } public: - IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc) + IndustryDirectoryWindow(WindowDesc *desc, WindowNumber number) : Window(desc), industry_editbox(MAX_FILTER_LENGTH * MAX_CHAR_LENGTH, MAX_FILTER_LENGTH) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_ID_SCROLLBAR); @@ -1644,6 +1661,9 @@ public: this->BuildSortIndustriesList(); this->FinishInitNested(0); + + this->querystrings[WID_ID_FILTER] = &this->industry_editbox; + this->industry_editbox.cancel_button = QueryString::ACTION_CLEAR; } ~IndustryDirectoryWindow() @@ -1809,6 +1829,14 @@ public: this->vscroll->SetCapacityFromWidget(this, WID_ID_INDUSTRY_LIST); } + void OnEditboxChanged(int wid) override + { + if (wid == WID_ID_FILTER) { + this->string_filter.SetFilterTerm(this->industry_editbox.text.buf); + this->InvalidateData(IDIWD_FORCE_REBUILD); + } + } + void OnPaint() override { if (this->industries.NeedRebuild()) this->BuildSortIndustriesList(); diff --git a/src/landscape.cpp b/src/landscape.cpp index 3bfecf06f4..5381006de2 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -930,12 +930,15 @@ static void GenerateTerrain(int type, uint flag) { uint32 r = Random(); - const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + 4845, ST_MAPGEN); + /* Choose one of the templates from the graphics file. */ + const Sprite *templ = GetSprite((((r >> 24) * _genterrain_tbl_1[type]) >> 8) + _genterrain_tbl_2[type] + SPR_MAPGEN_BEGIN, ST_MAPGEN); if (templ == nullptr) usererror("Map generator sprites could not be loaded"); + /* Chose a random location to apply the template to. */ uint x = r & MapMaxX(); uint y = (r >> MapLogX()) & MapMaxY(); + /* Make sure the template is not too close to the upper edges; bottom edges are checked later. */ uint edge_distance = 1 + (_settings_game.construction.freeform_edges ? 1 : 0); if (x <= edge_distance || y <= edge_distance) return; @@ -948,6 +951,9 @@ static void GenerateTerrain(int type, uint flag) const byte *p = templ->data; if ((flag & 4) != 0) { + /* This is only executed in secondary/tertiary loops to generate the terrain for arctic and tropic. + * It prevents the templates to be applied to certain parts of the map based on the flags, thus + * creating regions with different elevations/topography. */ uint xw = x * MapSizeY(); uint yw = y * MapSizeX(); uint bias = (MapSizeX() + MapSizeY()) * 16; @@ -972,11 +978,15 @@ static void GenerateTerrain(int type, uint flag) } } + /* Ensure the template does not overflow at the bottom edges of the map; upper edges were checked before. */ if (x + w >= MapMaxX()) return; if (y + h >= MapMaxY()) return; TileIndex tile = TileXY(x, y); + /* Get the template and overlay in a particular direction over the map's height from the given + * origin point (tile), and update the map's height everywhere where the height from the template + * is higher than the height of the map. In other words, this only raises the tile heights. */ switch (direction) { default: NOT_REACHED(); case DIAGDIR_NE: diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index a5c075c828..0bb7b3fc61 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Cria uma nova empresa e se une a ela STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Esse é você STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Esse é o hospedeiro do jogo -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s} / {NUM} empresa{P "" s} # Matches ConnectionType ###length 5 diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 7bf877fafa..0343b42e20 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Companyia nova STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una companyia nova i uniu-vos. STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Aquest ets tu. STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Aquest és l'hoste de la partida. -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} companyi{P a es} # Matches ConnectionType ###length 5 diff --git a/src/lang/czech.txt b/src/lang/czech.txt index eb4828360f..ff56ed24ba 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -2445,7 +2445,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nová společn STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Vytvořit novou společnost a připojit se do ní STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tohle jsi ty STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Toto je hostitel hry -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" i i} / {NUM} společnost{P “” i i} # Matches ConnectionType ###length 5 diff --git a/src/lang/danish.txt b/src/lang/danish.txt index a9452a12e8..d8f87ec570 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -2320,7 +2320,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nyt selskab) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Etabler et nyt selskab og tilslut dig det STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dette er dig STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dette er værten for dette spil -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" er} / {NUM} selskab{P "" er} # Matches ConnectionType ###length 5 diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index aa5b30eb0a..ec1cf81bd1 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -2358,7 +2358,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nieuw bedrijf) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Een nieuw bedrijf maken en meedoen STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dit ben jij STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dit is de host van het spel -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} speler{P "" s} / {NUM} bedrij{P f ven} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} speler{P "" s} - {NUM}/{NUM} bedrij{P f ven} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Het aantal momenteel verbonden clients, het aantal bedrijven en het maximale aantal toegestane bedrijven door de serverbeheerder # Matches ConnectionType ###length 5 diff --git a/src/lang/english.txt b/src/lang/english.txt index ef80b11ac5..80c9dd9e3f 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2358,7 +2358,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(New company) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company and join it STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is you STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} - {NUM}/{NUM} compan{P y ies} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}The number of currently connected clients, number of companies and maximum number of companies allowed by the server administrator # Matches ConnectionType ###length 5 @@ -5084,6 +5085,20 @@ STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Can't co STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... too far from previous destination STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... aircraft has not enough range +# Extra messages which go on the third line of errors, explaining why orders failed +STR_ERROR_NO_RAIL_STATION :{WHITE}There is no railway station +STR_ERROR_NO_BUS_STATION :{WHITE}There is no bus station +STR_ERROR_NO_TRUCK_STATION :{WHITE}There is no lorry station +STR_ERROR_NO_DOCK :{WHITE}There is no dock +STR_ERROR_NO_AIRPORT :{WHITE}There is no airport/heliport +STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}There are no stops with a compatible road type +STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE :{WHITE}There are no stops with a compatible tram type +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}There are no stops which are suitable for articulated road vehicles.{}Articulated road vehicles require a drive-through stop, not a bay stop +STR_ERROR_AIRPORT_NO_PLANES :{WHITE}This plane cannot land at this heliport +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}This helicopter cannot land at this airport +STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}There is no railway waypoint +STR_ERROR_NO_BUOY :{WHITE}There is no buoy + # Timetable related errors STR_ERROR_CAN_T_TIMETABLE_VEHICLE :{WHITE}Can't timetable vehicle... STR_ERROR_TIMETABLE_ONLY_WAIT_AT_STATIONS :{WHITE}Vehicles can only wait at stations diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index b0cc185897..d42768a09c 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(New company) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company and join it STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is you STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies} # Matches ConnectionType ###length 5 diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index c28c3c5494..0afe772262 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -2358,7 +2358,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(New company) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company and join it STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is you STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} - {NUM}/{NUM} compan{P y ies} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}The number of currently connected clients, number of companies and maximum number of companies allowed by the server administrator # Matches ConnectionType ###length 5 diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index 1c6d3aaa46..37f5ec9daa 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -2415,7 +2415,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Uus ettevõte) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Loo uus ettevõte ja liitu sellega STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tema oled sina STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Tema on mängu korraldaja -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" i} / {NUM} ettevõt{P e teid} # Matches ConnectionType ###length 5 diff --git a/src/lang/extra/english.txt b/src/lang/extra/english.txt index ef4cbfeada..7ee25fe4a7 100644 --- a/src/lang/extra/english.txt +++ b/src/lang/extra/english.txt @@ -1746,18 +1746,7 @@ STR_ERROR_DEPOT_HAS_WRONG_RAIL_TYPE :{WHITE}Depot ca STR_ERROR_CANNOT_MODIFY_TRACK_TRAIN_APPROACHING :{WHITE}Moving train approaching... -STR_ERROR_NO_RAIL_STATION :{WHITE}There is no railway station... -STR_ERROR_NO_BUS_STATION :{WHITE}There is no bus station... -STR_ERROR_NO_TRUCK_STATION :{WHITE}There is no lorry station... -STR_ERROR_NO_DOCK :{WHITE}There is no dock... -STR_ERROR_NO_AIRPORT :{WHITE}There is no airport/heliport... -STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}There are no stops with a compatible road/tram type... -STR_ERROR_NO_STOP_ARTIC_VEH :{WHITE}There are no stops which are suitable for articulated road vehicles.{}Articulated road vehicles require a drive-through stop, not a bay stop... -STR_ERROR_AIRPORT_NO_PLANES :{WHITE}This plane cannot land at this heliport... -STR_ERROR_AIRPORT_NO_HELIS :{WHITE}This helicopter cannot land at this airport... -STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}There is no railway waypoint... -STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}There is no road waypoint... -STR_ERROR_NO_BUOY :{WHITE}There is no buoy... +STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}There is no road waypoint # Plan related errors STR_ERROR_TOO_MANY_PLANS :{WHITE}... too many plans diff --git a/src/lang/extra/galician.txt b/src/lang/extra/galician.txt index df869b24c1..42fe69fb1b 100644 --- a/src/lang/extra/galician.txt +++ b/src/lang/extra/galician.txt @@ -1705,9 +1705,9 @@ STR_ERROR_NO_TRUCK_STATION :{WHITE}Non hai STR_ERROR_NO_DOCK :{WHITE}Non hai porto... STR_ERROR_NO_AIRPORT :{WHITE}Non hai aeroporto/heliporto... STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}Non hai paradas con un tipo de estrada/tranvía compatible... -STR_ERROR_NO_STOP_ARTIC_VEH :{WHITE}Non hai paradas axeitadas para vehículos articulados de estrada.{}Os vehículos de estrada articulados requiren unha parada de vía, non unha estación terminal/baía. +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}Non hai paradas axeitadas para vehículos articulados de estrada.{}Os vehículos de estrada articulados requiren unha parada de vía, non unha estación terminal/baía. STR_ERROR_AIRPORT_NO_PLANES :{WHITE}Este avión non pode aterrar neste heliporto... -STR_ERROR_AIRPORT_NO_HELIS :{WHITE}Este helicóptero non pode aterrar neste aeroporto... +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}Este helicóptero non pode aterrar neste aeroporto... STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}Non hai punto de ruta de ferrocarril... STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}Non hai punto de ruta de estrada... STR_ERROR_NO_BUOY :{WHITE}Non hai boia... diff --git a/src/lang/extra/german.txt b/src/lang/extra/german.txt index 9ce61fc43b..5f05eaa405 100644 --- a/src/lang/extra/german.txt +++ b/src/lang/extra/german.txt @@ -1615,9 +1615,9 @@ STR_ERROR_NO_TRUCK_STATION :{WHITE}Da ist k STR_ERROR_NO_DOCK :{WHITE}Da ist kein dock ... STR_ERROR_NO_AIRPORT :{WHITE}Da ist kein Flughafen/Heliport ... STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}Da ist kein Station eines kompatiblen Straßen- oder Straßenbahngleistyps ... -STR_ERROR_NO_STOP_ARTIC_VEH :{WHITE}Da sind keine Stationsfelder, die für Gelenkfahrzeuge geeinget sind.{}Gelenkfahrzeuge benötigen eine Durchfahrtsstation, nicht solche mit einer Haltebucht ... +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}Da sind keine Stationsfelder, die für Gelenkfahrzeuge geeinget sind.{}Gelenkfahrzeuge benötigen eine Durchfahrtsstation, nicht solche mit einer Haltebucht ... STR_ERROR_AIRPORT_NO_PLANES :{WHITE}Das Flugzeug kann auf diesem Heliport nicht landen ... -STR_ERROR_AIRPORT_NO_HELIS :{WHITE}Der Hubschrauber kann auf diesem Flugplatz nicht landen ... +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}Der Hubschrauber kann auf diesem Flugplatz nicht landen ... STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}Da ist kein Wegpunkt ... STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}Da ist kein Wegpunkt ... STR_ERROR_NO_BUOY :{WHITE}Da ist keine Boye ... diff --git a/src/lang/extra/korean.txt b/src/lang/extra/korean.txt index 947c2f80bf..b07721a340 100644 --- a/src/lang/extra/korean.txt +++ b/src/lang/extra/korean.txt @@ -1711,9 +1711,9 @@ STR_ERROR_NO_TRUCK_STATION :{WHITE}트럭 STR_ERROR_NO_DOCK :{WHITE}항구가 없습니다... STR_ERROR_NO_AIRPORT :{WHITE}공항/헬리포트가 없습니다... STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}도로/전차 종류에 맞는 정거장이 없습니다... -STR_ERROR_NO_STOP_ARTIC_VEH :{WHITE}굴절 차량이 들어갈 수 있는 정거장이 없습니다.{}굴절 차량은 터미널식 정류장이 아니라 통과식 정류장을 써야 합니다... +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}굴절 차량이 들어갈 수 있는 정거장이 없습니다.{}굴절 차량은 터미널식 정류장이 아니라 통과식 정류장을 써야 합니다... STR_ERROR_AIRPORT_NO_PLANES :{WHITE}이 항공기는 이 헬리포트에 착륙할 수 없습니다... -STR_ERROR_AIRPORT_NO_HELIS :{WHITE}이 헬리콥터는 이 공항에 착륙할 수 없습니다... +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}이 헬리콥터는 이 공항에 착륙할 수 없습니다... STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}철도 경유지가 없습니다... STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}도로 경유지가 없습니다... STR_ERROR_NO_BUOY :{WHITE}부표가 없습니다... diff --git a/src/lang/extra/simplified_chinese.txt b/src/lang/extra/simplified_chinese.txt index 71451d2df6..3bdf68e873 100644 --- a/src/lang/extra/simplified_chinese.txt +++ b/src/lang/extra/simplified_chinese.txt @@ -1700,9 +1700,9 @@ STR_ERROR_NO_TRUCK_STATION :{WHITE}没有 STR_ERROR_NO_DOCK :{WHITE}没有港口... STR_ERROR_NO_AIRPORT :{WHITE}没有机场或者直升机场... STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE :{WHITE}没有兼容的道路/电车道类型的站点... -STR_ERROR_NO_STOP_ARTIC_VEH :{WHITE}这里没有适用于铰接式的道路车辆的站点。{}铰接式道路车辆需要一个直通式站点而不是港湾式站点... +STR_ERROR_NO_STOP_ARTICULATED_VEHICLE :{WHITE}这里没有适用于铰接式的道路车辆的站点。{}铰接式道路车辆需要一个直通式站点而不是港湾式站点... STR_ERROR_AIRPORT_NO_PLANES :{WHITE}这架飞机不能在这个直升机场着陆... -STR_ERROR_AIRPORT_NO_HELIS :{WHITE}这架直升机不能在这个机场着陆... +STR_ERROR_AIRPORT_NO_HELICOPTERS :{WHITE}这架直升机不能在这个机场着陆... STR_ERROR_NO_RAIL_WAYPOINT :{WHITE}这里没有铁道路点... STR_ERROR_NO_ROAD_WAYPOINT :{WHITE}这里没有公路路点... STR_ERROR_NO_BUOY :{WHITE}这里没有浮漂... diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 534b7e546e..f53b4583e3 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Uusi yhtiö) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Perusta uusi yhtiö ja liity siihen STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tämä olet sinä STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Tämä on pelin ylläpitäjä -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} pelaaja{P "" a} / {NUM} yhtiö{P "" tä} # Matches ConnectionType ###length 5 diff --git a/src/lang/french.txt b/src/lang/french.txt index f8845f85c3..a46201e88d 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nouvelle compa STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Créer une nouvelle compagnie et la rejoindre STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}C'est vous STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}C'est l'hôte du jeu -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compagnie{P "" s} # Matches ConnectionType ###length 5 @@ -3353,6 +3352,8 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED}Attention{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erreur{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Erreur fatale{NBSP}: {SILVER}{STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Le NewGRF "{STRING}" a retourné une erreur fatale{NBSP}:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Le NewGRF "{STRING}" a retourné une erreur{NBSP}:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} ne fonctionnera pas avec la version de TTDPatch rapportée par OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} est conçu pour la version {2:STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} est conçu pour être utilisé avec {2:STRING} @@ -4528,7 +4529,7 @@ STR_TIMETABLE_CLEAR_SPEED :{BLACK}Annuler STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Annuler la vitesse maximale de déplacement de l'ordre sélectionné. Ctrl-clic pour annuler la vitesse de tous les ordres STR_TIMETABLE_RESET_LATENESS :{BLACK}RAZ compteur de retard -STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Remettre à zéro le compteur de retard (le véhicule sera donc à l'heure) +STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Remettre à zéro le compteur de retard, le véhicule sera donc à l'heure. Ctrl-clic pour remettre à zéro le groupe entier, le véhicule le plus en retard sera donc à l'heure et les autres en avance STR_TIMETABLE_AUTOFILL :{BLACK}Autoremplir STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Remplir l'horaire automatiquement avec les valeurs du prochain trajet. Ctrl-clic pour essayer de préserver les temps d'attente diff --git a/src/lang/frisian.txt b/src/lang/frisian.txt index 0c97d4bbf9..e47258ed59 100644 --- a/src/lang/frisian.txt +++ b/src/lang/frisian.txt @@ -2103,7 +2103,6 @@ STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Namme fa STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Sichtberheid STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Dyn namme STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dit bisto sels -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klïïnt{P "" en} / {NUM} bedriuw{P "" en} # Matches ConnectionType ###length 5 diff --git a/src/lang/galician.txt b/src/lang/galician.txt index a7a340030c..bc0b0835cb 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova compañí STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crear unha nova compañía e unirte a ela STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este es ti STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este é o anfitrión da partida -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s} / {NUM} compañía{P "" "s"} # Matches ConnectionType ###length 5 diff --git a/src/lang/german.txt b/src/lang/german.txt index e7229ec163..73feefe433 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -2357,7 +2357,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Neue Firma) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Eine neue Firma gründen und beitreten STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Das sind Sie STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dies ist der Host des Spiels -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} Client{P "" s} / {NUM} Firm{P a en} # Matches ConnectionType ###length 5 diff --git a/src/lang/greek.txt b/src/lang/greek.txt index 11b3a63f64..b9e88f06cb 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -2462,7 +2462,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Νέα ετα STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Δημιουργήστε μία νέα εταιρία και συμμετέχετε σε αυτήν STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Αυτός/η είστε εσείς STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Αυτός/η είναι ο/η οικοδεσπότης του παιχνιδιού -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} πελάτης/ες / {NUM} εταιρία/ες # Matches ConnectionType ###length 5 diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index c1e84eda9a..79d8c390cc 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -2420,7 +2420,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Új vállalat) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Hozz létre egy új vállalatot és csatlakozz STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Ez vagy te STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Ez a játék elindítója -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} kliens / {NUM} vállalat # Matches ConnectionType ###length 5 diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index 6bdcea6e62..9f4e22dcbd 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -2356,7 +2356,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Perusahaan bar STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Ciptakan perusahaan baru dan bergabung STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Ini adalah Anda STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Ini adalah hos permainan -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klien / {NUM} Perusahaan # Matches ConnectionType ###length 5 diff --git a/src/lang/irish.txt b/src/lang/irish.txt index e6e990baa5..3adc714f79 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -2313,7 +2313,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Cuideachta nua STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Cruthaigh cuideachta nua agus téigh isteach ann STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Seo tusa STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Is é seo óstach an chluiche -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} {P ch ch ch gc c}liant / {NUM} {P ch ch ch gc c}uideachta # Matches ConnectionType ###length 5 diff --git a/src/lang/italian.txt b/src/lang/italian.txt index e6adfb495b..4c3c11dc09 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -2393,7 +2393,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nuova compagni STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una nuova compagnia e controllala STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Questo sei tu STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Questo è l'host del gioco -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} / {NUM} compan{P y ies} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} client{P "" s} - {NUM}/{NUM} compagni{P a e} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Il numero di client attualmente connessi, il numero di compagnie e il numero massimo di compagnie consentito dall'amministratore del server. # Matches ConnectionType ###length 5 diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 7b7e754adb..169611e3d4 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -2342,7 +2342,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(新規会社 STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}新しく会社を設立し参画します STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}これはあなたです STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}ゲームのホストです -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} 個のクライアント / {NUM} 個の企業 # Matches ConnectionType ###length 5 diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 319ae89897..db3863a88d 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(새 회사) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}새 회사를 만듭니다 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}당신입니다 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}이 게임을 연 사람입니다 -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}접속자 {NUM}명 / 회사 {NUM}개 # Matches ConnectionType ###length 5 diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 2237f672a0..0001724c0a 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -2362,7 +2362,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Jauna kompāni STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Izveidot jaunu kompāniju un pievienoties tai STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tas esat jūs STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Šis ir spēles īpašnieks -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P s а u} / {NUM} kompānij{P a u as} # Matches ConnectionType ###length 5 diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index 0e5c6e56df..7cedd8e167 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -1591,7 +1591,7 @@ STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE_HELPTEXT :Mécht eng Fens STR_CONFIG_SETTING_AUTOSAVE :Autospäicheren: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Setz den Interval tëschend automateschen Späicherstänn -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Benotz {STRING} Datumsformat fir Späichernimm +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :Datumsformat fir Späichernimm: {STRING} STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :Format vum Datum am Numm vum Späicherstand ###length 3 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :laang (31ten Dez 2008) @@ -1886,7 +1886,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} ###setting-zero-is-special STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :ausgeschalt -STR_CONFIG_SETTING_ZOOM_MIN :Maximalen Ranzoom Level: {STRING} +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 STR_CONFIG_SETTING_ZOOM_MAX :Maximalen Rauszoom Level: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Maximal Rauszoom-Stuf fir Usiichtsfënsteren. Méi grouss Rauszoom-Stufen kënnen Ruckeler verursaachen @@ -2046,7 +2046,7 @@ STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :System NewGRF STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE :net mat dëser Versioun vun OpenTTD kompatibel STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN :onbekannt STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_LEVEL :{WHITE}... Kompressiounslevel '{STRING}' ass net gültëg. -STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... Spillstand format '{STRING}' gëtt et net. Revertéiren zu '{STRING}' +STR_CONFIG_ERROR_INVALID_SAVEGAME_COMPRESSION_ALGORITHM :{WHITE}... Späicherstand format '{STRING}' gëtt et net. Revertéiren zu '{STRING}' STR_CONFIG_ERROR_INVALID_BASE_GRAPHICS_NOT_FOUND :{WHITE}... ignoréiren Basis Grafik Set '{STRING}': net fonnt STR_CONFIG_ERROR_INVALID_BASE_SOUNDS_NOT_FOUND :{WHITE}... ignoréiren Basis Sound Set '{STRING}': net fonnt STR_CONFIG_ERROR_INVALID_BASE_MUSIC_NOT_FOUND :{WHITE}... ignoréiren Basis Musik Set '{STRING}': net fonnt @@ -2114,7 +2114,7 @@ STR_ABANDON_SCENARIO_QUERY :{YELLOW}Bass du # Cheat window STR_CHEATS :{WHITE}Cheater STR_CHEATS_TOOLTIP :{BLACK}Checkboxen weisen un dass du den Cheat schon eng Kéier benotzt hues -STR_CHEATS_NOTE :{BLACK}Notiz: jeglech Benotzung vun dësen Astellungen wäert am Spillstand opgeholl ginn +STR_CHEATS_NOTE :{BLACK}Notiz: jeglech Benotzung vun dësen Astellungen wäert am Späicherstand opgeholl ginn STR_CHEAT_MONEY :{LTBLUE}Suen ëm {CURRENCY_LONG} erhéijen STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Als Firma {ORANGE}{COMMA} spillen STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Magësche Bulldozer (Industrien ofrappen, onzerstéierbar Objeten): {ORANGE}{STRING} @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nei Firma) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Eng nei Firma erstellen an hier bäitrieden STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dat bass du STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dest ass den Host vun der Partie -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} Client{P "" en} / {NUM} Firm{P a en} # Matches ConnectionType ###length 5 @@ -3352,6 +3351,8 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warnung: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Den NewGRF "{STRING}" huet e fatale Fehler gemet:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Den NewGRF "{STRING}" huet e Fehler gemet:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} wärt net mat der TTDPatch Versioun déi vun OpenTTD erkannt gouf funktionéiren STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} ass fir {2:STRING} Versioun vun TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ass designed fir mat {2:STRING} benotzt ze ginn @@ -4527,7 +4528,7 @@ STR_TIMETABLE_CLEAR_SPEED :{BLACK}Geschwin STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Maximal Reesgeschwindegkeet vum gewielten Optrag läschen. Ctrl+Klick läscht d'Geschwindegkeet fir all Opträg STR_TIMETABLE_RESET_LATENESS :{BLACK}Verspeidungszieler zerécksetzen -STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Setzt de Verspéidungszieler zréck, sou dass d'Gefier mat Zäit ukënnt +STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Setzt de Verspéidungszieler zréck, sou dass d'Gefier mat Zäit ukënnt. Ctrl+klick setzt déi ganz Grupp zeréck, sou das dat lescht Gefiert pünktlech ass an all déi aner méi fréi. STR_TIMETABLE_AUTOFILL :{BLACK}Autofëllen STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fëll den Zäitplang automatesch mat de Wäerter vum nächsten Trajet Ctrl+Klick fir Wardzäiten probéiren bäizehalen @@ -4675,7 +4676,7 @@ STR_ERROR_GAME_SAVE_FAILED :{WHITE}Fehler b STR_ERROR_UNABLE_TO_DELETE_FILE :{WHITE}Kann d'Datei net läschen STR_ERROR_GAME_LOAD_FAILED :{WHITE}Fehler beim Lueden{}{STRING} STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR :Interne Fehler: {STRING} -STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Futtissen Spillstand - {STRING} +STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME :Futtissen Späicherstand - {STRING} STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spillstand ass mat enger méi neier Versioun gemaach STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Datei net liesbar STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Datei net beschreiwbar diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index e2679130f6..2b287921ed 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -2330,7 +2330,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nytt firma) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Opprett et nytt firma og bli med i det STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dette er deg STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dette er verten for spillet -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" s} / {NUM} firma{P et er} # Matches ConnectionType ###length 5 diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 2ce044765e..7416412022 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -2679,7 +2679,7 @@ STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Dopuszcz STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Ustaw maksymalną liczbę klientów. Nie wszystkie miejsca muszą być zapełnione. STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} firm{P a y ""} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Maksymalna liczba firm: -STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ogranicz serwer do określonej ilości firm +STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ogranicz serwer do określonej liczby firm STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Wpisz nazwę dla gry sieciowej @@ -2738,7 +2738,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nowa firma) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Utwórz nową firmę i dołącz do niej STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}To jesteś ty STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}To jest gospodarz gry -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" ów ów} / {NUM} firm{P a y ""} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" ów ów} - {NUM}/{NUM} firm{P ę y ""} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Liczba aktualnie podłączonych klientów, liczba firm oraz maksymalna liczba firm dozwolona przez administratora serwera # Matches ConnectionType ###length 5 diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index 75346f169f..74dda44ed8 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -2359,7 +2359,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Criar uma nova empresa e juntar-se a ela STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este é você STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este é o anfitrião do jogo -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s} / {NUM} companhi{P a as} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s} - {NUM}/{NUM} companhi{P a as} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}O número de clientes ligados atualmente, número de empresas e número máximo de empresas permitido pelo administrador do servidor # Matches ConnectionType ###length 5 diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index 1ace894e34..bbe7938fb5 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Companie nouă STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Creează o nouă companie și intră în ea STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Aici ești tu STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Aceasta este gazda jocului -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} {P client clienți "de clienți"} / {NUM}{P companie companii "de companii"} # Matches ConnectionType ###length 5 @@ -4529,7 +4528,7 @@ STR_TIMETABLE_CLEAR_SPEED :{BLACK}Şterge STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Ștergeți viteza maximă de deplasare a comenzii evidențiate. Ctrl+Click șterge viteza pentru toate comenzile STR_TIMETABLE_RESET_LATENESS :{BLACK}Reinitializeaza contorul de intarziere -STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reiniţializează contorul de întârziere, astfel ca vehiculul să ajungă la timp +STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reiniţializează contorul de întârziere, astfel ca vehiculul să ajungă la timp. Ctrl+clic va reseta tot grupul astfel încât cel mai întârziat vehicul va ajunge la timp și toate celelalte vor ajunge mai devreme STR_TIMETABLE_AUTOFILL :{BLACK}Auto-completare STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Completați automat orarul cu valorile din următoarea călătorie. Ctrl+Click pentru a încerca să păstrați timpii de așteptare diff --git a/src/lang/russian.txt b/src/lang/russian.txt index e8185b1da6..cb8c9434b4 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -2509,7 +2509,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Новая к STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Основать новую транспортную компанию и присоединиться к ней STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Это вы! STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Это организатор игры -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} клиент{P "" а ов} / {NUM} компани{P я и й} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}Клиентов: {NUM}; компаний: {NUM}/{NUM} +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Количество подключённых в данный момент клиентов, существующих компаний и максимально допустимое количество компаний # Matches ConnectionType ###length 5 diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index fcc09de47f..24c8352577 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -2551,7 +2551,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(novo preduzeć STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Napravi novo preduzeće i pridruži mu se STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Ovo si ti STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Ovo je domaćin igre -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klijen{P t ata ata} / {NUM} preduzeć{P e a a} # Matches ConnectionType ###length 5 diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index e241e3708b..38ab3b03e9 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(新公司) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}新建并加入公司 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}这是你 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}这里是游戏的主机 -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM}个客户端 / {NUM}个公司 # Matches ConnectionType ###length 5 diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index b7b531ddcd..a154237e0d 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -2426,7 +2426,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nová spoločn STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Založiť novú spoločnosť a pripojiť sa k nej STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Toto ste vy STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Toto je hosť hry -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" "i" "ov"} / {NUM} spoločnos{P "ť" "ti" "tí"} # Matches ConnectionType ###length 5 diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 8e551b3453..653d00d7ea 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva empresa) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una nueva empresa y te une a ella STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Éste eres tú STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Éste es el servidor de la partida -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s} / {NUM} empresa{P "" s} # Matches ConnectionType ###length 5 diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index d0e9bc0f26..cfbfb84c1b 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -2359,7 +2359,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva empresa) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crear nueva empresa y unirse a ella STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este eres tú STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este es el host del juego -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} cliente{P "" s}/{NUM} empresa{P "" s} # Matches ConnectionType ###length 5 @@ -3353,6 +3352,7 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atención: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Error fatal: {SILVER}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ha ocurrido un error en el NewGRF "{STRING}":{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionará con la con la versión de TTDPatch reportada por OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} es la para la versión {2:STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} está diseñado para usarse con {2:STRING} diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 243ebc4bca..319670cd7d 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -2358,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nytt företag) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Skapa ett nytt företag och gå med i det STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Det här är du STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Det här är spelets värd -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} klient{P "" er} / {NUM} företag # Matches ConnectionType ###length 5 diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index 1a710967cb..d56de395a6 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -2098,7 +2098,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(புதி STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}புதிய நிறுவனத்தினை நிறுவி விளையாடு STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :இது நீன்கள் STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}இது விலையாட்டின் வழங்குபவர் -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} வாடிக்கையாளர்{P "" கள்} / {NUM} நிறுவன{P ம் ங்கள்} # Matches ConnectionType ###length 5 diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index 73d9aeb11f..64f841dc00 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -1206,7 +1206,9 @@ STR_CONFIG_SETTING_HORIZONTAL_POS_RIGHT :靠右 STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN :最大貸款額:{STRING} STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_HELPTEXT :公司最多可借多少錢(此設定的值排除了通貨膨脹因素)。 +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_VALUE :{CURRENCY_LONG} ###setting-zero-is-special +STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN_DISABLED :無貸款 {RED} 需要有遊戲腳本以提供初始資金 STR_CONFIG_SETTING_INTEREST_RATE :息率:{STRING} STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :設定貸款息率。如啟用了通貨膨脹的設定,則此設定同時決定通脹率。 @@ -2356,7 +2358,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(新公司) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}創立並加入一個新公司 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}這是你 STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}這是遊戲的主持端 -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM}個用戶端 / {NUM}所公司 # Matches ConnectionType ###length 5 @@ -3350,6 +3351,8 @@ STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING STR_NEWGRF_ERROR_MSG_WARNING :{RED}警告:{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_ERROR :{RED}錯誤:{SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}嚴重錯誤:{SILVER}{STRING} +STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}發生嚴重 NewGRF "{STRING}" 錯誤的處理方式:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}發生NewGRF "{STRING}" 錯誤:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} 跟由 OpenTTD 回報的 TTDPatch 版本不合 STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} 只適合用於 TTD 版本 {2:STRING}。 STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} 必須跟 {2:STRING} 一起使用 @@ -4620,7 +4623,9 @@ STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}高度 STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}小地圖截圖 # Script Parameters -STR_AI_SETTINGS_CAPTION_AI :{WHITE}AI參數 +STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} 參數 +STR_AI_SETTINGS_CAPTION_AI :AI 參數 +STR_AI_SETTINGS_CAPTION_GAMESCRIPT :遊戲腳本 STR_AI_SETTINGS_CLOSE :{BLACK}關閉 STR_AI_SETTINGS_RESET :{BLACK}重設 STR_AI_SETTINGS_SETTING :{STRING}:{ORANGE}{STRING} diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index 2e081c3e9b..007c60a238 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -2359,7 +2359,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Yeni şirket) STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Yeni bir şirket oluştur ve ona katıl STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Bu sensin STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Bu, oyunun ev sahibi -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} oyuncu / {NUM} şirket +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} oyuncu - {NUM}/{NUM} şirket +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Şu anda bağlı olan istemci sayısı, şirket sayısı ve sunucu sahibi tarafından izin verilen maksimum şirket sayısı # Matches ConnectionType ###length 5 @@ -4626,7 +4627,7 @@ STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Küçük # Script Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametreler -STR_AI_SETTINGS_CAPTION_AI :{WHITE}YZ Parametreleri +STR_AI_SETTINGS_CAPTION_AI :YZ STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Oyun Betiği STR_AI_SETTINGS_CLOSE :{BLACK}Kapat STR_AI_SETTINGS_RESET :{BLACK}Yeniden başlat diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index ead9afb663..e82fca0b27 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -2484,7 +2484,6 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Нова ко STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Створити нову компанію і приєднатись до неї STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Це ти STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Організатор гри -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} клієнт{P "" и ів} / {NUM} компан{P ія ії ій} # Matches ConnectionType ###length 5 diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index c74363d550..81fb0e7fdb 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -2358,7 +2358,8 @@ STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Công ty mới STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Khai sinh một công ty và gia nhập STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Đây là bạn STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Đây là người tổ chức ván chơi -STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} người chơi / {NUM} công ty +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT :{BLACK}{NUM} nguời chơi - {NUM}/{NUM} công ty +STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP :{BLACK}Số lượng máy trạm, số lượng công ty và số lượng công ty tối đa mà quản lý máy chủ cho phép # Matches ConnectionType ###length 5 diff --git a/src/league_base.h b/src/league_base.h index 8a70db4ca2..6195d2c3ee 100644 --- a/src/league_base.h +++ b/src/league_base.h @@ -30,7 +30,7 @@ extern LeagueTablePool _league_table_pool; **/ struct LeagueTableElement : LeagueTableElementPool::PoolItem<&_league_table_element_pool> { LeagueTableID table; ///< Id of the table which this element belongs to - uint64 rating; ///< Value that determines ordering of elements in the table (higher=better) + int64 rating; ///< Value that determines ordering of elements in the table (higher=better) CompanyID company; ///< Company Id to show the color blob for or INVALID_COMPANY std::string text; ///< Text of the element std::string score; ///< String representation of the score associated with the element diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 9f3612475d..d76828c5d2 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -1294,6 +1294,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CONFIG_UPDATE(P _network_server_max_companies = p->Recv_uint8(); _network_server_name = p->Recv_string(NETWORK_NAME_LENGTH); + SetWindowClassesDirty(WC_CLIENT_LIST); return NETWORK_RECV_STATUS_OKAY; } @@ -1553,11 +1554,20 @@ bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio) return false; } +/** + * Get the maximum number of companies that are allowed by the server. + * @return The number of companies allowed. + */ +uint NetworkMaxCompaniesAllowed() +{ + return _network_server ? _settings_client.network.max_companies : _network_server_max_companies; +} + /** * Check if max_companies has been reached on the server (local check only). * @return true if the max value has been reached or exceeded, false otherwise. */ bool NetworkMaxCompaniesReached() { - return Company::GetNumItems() >= (_network_server ? _settings_client.network.max_companies : _network_server_max_companies); + return Company::GetNumItems() >= NetworkMaxCompaniesAllowed(); } diff --git a/src/network/network_func.h b/src/network/network_func.h index 3d7bcabe5c..90fb5a16ca 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -65,6 +65,7 @@ void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const void NetworkClientSendDesyncMsg(const char *msg); bool NetworkClientPreferTeamChat(const NetworkClientInfo *cio); bool NetworkCompanyIsPassworded(CompanyID company_id); +uint NetworkMaxCompaniesAllowed(); bool NetworkMaxCompaniesReached(); void NetworkPrintClients(); void NetworkHandlePauseChange(PauseMode prev_mode, PauseMode changed_mode); diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index d4426ef584..c574c85829 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -1366,7 +1366,7 @@ static const NWidgetPart _nested_client_list_widgets[] = { NWidget(NWID_VERTICAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_CL_MATRIX), SetMinimalSize(180, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_CL_SCROLLBAR), NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_COMPANY_COUNT), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetPadding(2, 1, 2, 1), SetAlignment(SA_CENTER), SetDataTip(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_COMPANY_COUNT), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetPadding(2, 1, 2, 1), SetAlignment(SA_CENTER), SetDataTip(STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT, STR_NETWORK_CLIENT_LIST_CLIENT_COMPANY_COUNT_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), @@ -1811,6 +1811,7 @@ public: case WID_CL_CLIENT_COMPANY_COUNT: SetDParam(0, NetworkClientInfo::GetNumItems()); SetDParam(1, Company::GetNumItems()); + SetDParam(2, NetworkMaxCompaniesAllowed()); break; } } diff --git a/src/newgrf.h b/src/newgrf.h index 12694c9cb9..6e20fb1c86 100644 --- a/src/newgrf.h +++ b/src/newgrf.h @@ -87,12 +87,12 @@ enum GrfSpecFeature : uint8 { GSF_AIRPORTTILES, GSF_ROADTYPES, GSF_TRAMTYPES, - GSF_ROADSTOPS, + GSF_NEWLANDSCAPE, GSF_END, - GSF_REAL_FEATURE_END = GSF_ROADSTOPS, + GSF_REAL_FEATURE_END = GSF_NEWLANDSCAPE, GSF_FAKE_TOWNS = GSF_END, ///< Fake town GrfSpecFeature for NewGRF debugging (parent scope) GSF_FAKE_STATION_STRUCT, ///< Fake station struct GrfSpecFeature for NewGRF debugging diff --git a/src/newgrf_text.cpp b/src/newgrf_text.cpp index 0f38473580..87e0375cc9 100644 --- a/src/newgrf_text.cpp +++ b/src/newgrf_text.cpp @@ -948,6 +948,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const switch (scc) { default: break; + /* These control codes take one string parameter, check there are at least that many available. */ case SCC_NEWGRF_PRINT_DWORD_SIGNED: case SCC_NEWGRF_PRINT_WORD_SIGNED: case SCC_NEWGRF_PRINT_BYTE_SIGNED: @@ -977,6 +978,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const } break; + /* These string code take two string parameters, check there are at least that many available. */ case SCC_NEWGRF_PRINT_WORD_CARGO_LONG: case SCC_NEWGRF_PRINT_WORD_CARGO_SHORT: case SCC_NEWGRF_PRINT_WORD_CARGO_TINY: @@ -988,6 +990,8 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const } if (_newgrf_textrefstack.used && modify_argv) { + /* 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_argv` set to false when the string is finally formatted. */ switch (scc) { default: NOT_REACHED(); case SCC_NEWGRF_PRINT_BYTE_SIGNED: *argv = _newgrf_textrefstack.PopSignedByte(); break; @@ -1015,6 +1019,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const case SCC_NEWGRF_PRINT_DWORD_DATE_SHORT: case SCC_NEWGRF_PRINT_DWORD_HEX: *argv = _newgrf_textrefstack.PopUnsignedDWord(); break; + /* Dates from NewGRFs have 1920-01-01 as their zero point, convert it to OpenTTD's epoch. */ case SCC_NEWGRF_PRINT_WORD_DATE_LONG: case SCC_NEWGRF_PRINT_WORD_DATE_SHORT: *argv = _newgrf_textrefstack.PopUnsignedWord() + DAYS_TILL_ORIGINAL_BASE_YEAR; break; @@ -1042,7 +1047,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const } } } else { - /* Consume additional parameter characters */ + /* Consume additional parameter characters that follow the NewGRF string code. */ switch (scc) { default: break; @@ -1053,6 +1058,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const } } + /* Emit OpenTTD's internal string code for the different NewGRF variants. */ switch (scc) { default: NOT_REACHED(); case SCC_NEWGRF_PRINT_DWORD_SIGNED: @@ -1115,6 +1121,7 @@ uint RemapNewGRFStringControlCode(uint scc, char *buf_start, char **buff, const case SCC_NEWGRF_PRINT_WORD_STATION_NAME: return SCC_STATION_NAME; + /* These NewGRF string codes modify the NewGRF stack or otherwise do not map to OpenTTD string codes. */ case SCC_NEWGRF_DISCARD_WORD: case SCC_NEWGRF_ROTATE_TOP_4_WORDS: case SCC_NEWGRF_PUSH_WORD: diff --git a/src/order_base.h b/src/order_base.h index 17913620e6..2a94cfde61 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -764,7 +764,6 @@ private: friend upstream_sl::SaveLoadTable upstream_sl::GetOrderListDescription(); ///< Saving and loading of order lists. friend void Ptrs_ORDL(); ///< Saving and loading of order lists. - StationID GetBestLoadableNext(const Vehicle *v, const Order *o1, const Order *o2) const; void ReindexOrderList(); Order *GetOrderAtFromList(int index) const; diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp index b5e54290ca..85b75a9d1f 100644 --- a/src/order_cmd.cpp +++ b/src/order_cmd.cpp @@ -2420,7 +2420,7 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 * are temporarily invalid due to reconstruction. */ const Station *st = Station::Get(order->GetDestination()); if (CanVehicleUseStation(src, st) && !CanVehicleUseStation(dst, st)) { - return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER); + return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st)); } } if (OrderGoesToRoadDepot(dst, order)) { @@ -2501,9 +2501,9 @@ CommandCost CmdCloneOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Trucks can't copy all the orders from busses (and visa versa), * and neither can helicopters and aircraft. */ for (const Order *order : src->Orders()) { - if (OrderGoesToStation(dst, order) && - !CanVehicleUseStation(dst, Station::Get(order->GetDestination()))) { - return_cmd_error(STR_ERROR_CAN_T_COPY_SHARE_ORDER); + Station *st = Station::Get(order->GetDestination()); + if (OrderGoesToStation(dst, order) && !CanVehicleUseStation(dst, st)) { + return CommandCost::DualErrorMessage(STR_ERROR_CAN_T_COPY_SHARE_ORDER, GetVehicleCannotUseStationReason(dst, st)); } if (OrderGoesToRoadDepot(dst, order)) { const Depot *dp = Depot::GetIfValid(order->GetDestination()); diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 55df43b403..679b22e62e 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -847,9 +847,11 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SpriteID sprite = rtl ? SPR_ARROW_LEFT : SPR_ARROW_RIGHT; Dimension sprite_size = GetSpriteSize(sprite); if (v->cur_real_order_index == order_index) { + /* Draw two arrows before the next real order. */ DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); DrawSprite(sprite, PAL_NONE, rtl ? right - 2 * sprite_size.width : left + sprite_size.width, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); } else if (v->cur_implicit_order_index == order_index) { + /* Draw one arrow before the next implicit order; the next real order will still get two arrows. */ DrawSprite(sprite, PAL_NONE, rtl ? right - sprite_size.width : left, y + ((int)FONT_HEIGHT_NORMAL - (int)sprite_size.height) / 2); } @@ -897,6 +899,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(2, order->GetDestination()); if (timetable) { + /* Show only wait time in the timetable window. */ SetDParam(3, STR_EMPTY); if (order->GetWaitTime() > 0 || order->IsWaitTimetabled()) { @@ -905,6 +908,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int } timetable_wait_time_valid = true; } else { + /* Show non-stop, refit and stop location only in the order window. */ SetDParam(3, (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) ? STR_EMPTY : _station_load_types[order->IsRefit()][unload][load]); if (order->IsRefit()) { SetDParam(4, order->IsAutoRefit() ? STR_ORDER_AUTO_REFIT_ANY : CargoSpec::Get(order->GetRefitCargo())->name); @@ -921,6 +925,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int case OT_GOTO_DEPOT: if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) { + /* Going to the nearest depot. */ SetDParam(0, STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT); if (v->type == VEH_AIRCRAFT) { SetDParam(2, STR_ORDER_NEAREST_HANGAR); @@ -930,6 +935,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int SetDParam(3, STR_ORDER_TRAIN_DEPOT + v->type); } } else { + /* Going to a specific depot. */ SetDParam(0, STR_ORDER_GO_TO_DEPOT_FORMAT); SetDParam(2, v->type); SetDParam(3, order->GetDestination()); @@ -944,10 +950,12 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int if (!timetable && (order->GetDepotActionType() & ODATFB_SELL)) { SetDParam(7, STR_ORDER_SELL_ORDER); } else { + /* Do not show stopping in the depot in the timetable window. */ if (!timetable && (order->GetDepotActionType() & ODATFB_HALT)) { SetDParam(7, STR_ORDER_STOP_ORDER); } + /* Do not show refitting in the depot in the timetable window. */ if (!timetable && order->IsRefit()) { SetDParam(7, (order->GetDepotActionType() & ODATFB_HALT) ? STR_ORDER_REFIT_STOP_ORDER : STR_ORDER_REFIT_ORDER); SetDParam(8, CargoSpec::Get(order->GetRefitCargo())->name); diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 86a8bea6b1..06218f4531 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -2697,8 +2697,7 @@ bool AfterLoadGame() if (IsTileType(t, MP_TREES)) { uint density = GB(_m[t].m2, 6, 2); uint ground = GB(_m[t].m2, 4, 2); - uint counter = GB(_m[t].m2, 0, 4); - _m[t].m2 = ground << 6 | density << 4 | counter; + _m[t].m2 = ground << 6 | density << 4; } } } diff --git a/src/saveload/saveload_common.h b/src/saveload/saveload_common.h index 2dda4d96e4..f4f7a41544 100644 --- a/src/saveload/saveload_common.h +++ b/src/saveload/saveload_common.h @@ -352,6 +352,8 @@ enum SaveLoadVersion : uint16 { SLV_U64_TICK_COUNTER, ///< 300 PR#10035 Make _tick_counter 64bit to avoid wrapping. SLV_LAST_LOADING_TICK, ///< 301 PR#9693 Store tick of last loading for vehicles. SLV_MULTITRACK_LEVEL_CROSSINGS, ///< 302 PR#9931 v13.0 Multi-track level crossings. + SLV_NEWGRF_ROAD_STOPS, ///< 303 PR#10144 NewGRF road stops. + SLV_LINKGRAPH_EDGES, ///< 304 PR#10314 Explicitly store link graph edges destination. SL_MAX_VERSION, ///< Highest possible saveload version diff --git a/src/saveload/upstream/compat/station_sl_compat.h b/src/saveload/upstream/compat/station_sl_compat.h index d596e8bd45..33d37c432e 100644 --- a/src/saveload/upstream/compat/station_sl_compat.h +++ b/src/saveload/upstream/compat/station_sl_compat.h @@ -34,6 +34,12 @@ const SaveLoadCompat _station_spec_list_sl_compat[] = { SLC_VAR("localidx"), }; +/** Nominal field order for SlRoadStopSpecList. */ +const SaveLoadCompat _station_road_stop_spec_list_sl_compat[] = { + SLC_VAR("grfid"), + SLC_VAR("localidx"), +}; + /** Original field order for SlStationCargo. */ const SaveLoadCompat _station_cargo_sl_compat[] = { SLC_VAR("first"), diff --git a/src/saveload/upstream/league_sl.cpp b/src/saveload/upstream/league_sl.cpp index 4d00509e7e..d15e7aab01 100644 --- a/src/saveload/upstream/league_sl.cpp +++ b/src/saveload/upstream/league_sl.cpp @@ -18,13 +18,14 @@ namespace upstream_sl { static const SaveLoad _league_table_elements_desc[] = { - SLE_VAR(LeagueTableElement, table, SLE_UINT8), - SLE_VAR(LeagueTableElement, rating, SLE_UINT64), - SLE_VAR(LeagueTableElement, company, SLE_UINT8), - SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL), - SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL), - SLE_VAR(LeagueTableElement, link.type, SLE_UINT8), - SLE_VAR(LeagueTableElement, link.target, SLE_UINT32), + SLE_VAR(LeagueTableElement, table, SLE_UINT8), + SLE_CONDVAR(LeagueTableElement, rating, SLE_FILE_U64 | SLE_VAR_I64, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES), + SLE_CONDVAR(LeagueTableElement, rating, SLE_INT64, SLV_LINKGRAPH_EDGES, SL_MAX_VERSION), + SLE_VAR(LeagueTableElement, company, SLE_UINT8), + SLE_SSTR(LeagueTableElement, text, SLE_STR | SLF_ALLOW_CONTROL), + SLE_SSTR(LeagueTableElement, score, SLE_STR | SLF_ALLOW_CONTROL), + SLE_VAR(LeagueTableElement, link.type, SLE_UINT8), + SLE_VAR(LeagueTableElement, link.target, SLE_UINT32), }; struct LEAEChunkHandler : ChunkHandler { diff --git a/src/saveload/upstream/linkgraph_sl.cpp b/src/saveload/upstream/linkgraph_sl.cpp index 34369f0a1b..28d4637842 100644 --- a/src/saveload/upstream/linkgraph_sl.cpp +++ b/src/saveload/upstream/linkgraph_sl.cpp @@ -27,6 +27,7 @@ typedef LinkGraph::BaseEdge Edge; static uint16 _num_nodes; static LinkGraph *_linkgraph; ///< Contains the current linkgraph being saved/loaded. static NodeID _linkgraph_from; ///< Contains the current "from" node being saved/loaded. +static NodeID _edge_dest_node; static NodeID _edge_next_edge; class SlLinkgraphEdge : public DefaultSaveLoadHandler { @@ -37,7 +38,8 @@ public: SLE_CONDVAR(Edge, travel_time_sum, SLE_UINT64, SLV_LINKGRAPH_TRAVEL_TIME, SL_MAX_VERSION), SLE_VAR(Edge, last_unrestricted_update, SLE_INT32), SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION), - SLEG_VAR("next_edge", _edge_next_edge, SLE_UINT16), + SLEG_VAR("dest_node", _edge_dest_node, SLE_UINT16), + SLEG_CONDVAR("next_edge", _edge_next_edge, SLE_UINT16, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES), }; inline const static SaveLoadCompatTable compat_description = _linkgraph_edge_sl_compat; @@ -54,18 +56,29 @@ public: NOT_REACHED(); } - size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX); + if (IsSavegameVersionBefore(SLV_LINKGRAPH_EDGES)) { + size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX); - /* ... but as that wasted a lot of space we save a sparse matrix now. */ - for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _edge_next_edge) { - if (used_size == 0) SlErrorCorrupt("Link graph structure overflow"); - used_size--; + /* ... but as that wasted a lot of space we save a sparse matrix now. */ + for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = _edge_next_edge) { + if (used_size == 0) SlErrorCorrupt("Link graph structure overflow"); + used_size--; - if (to >= max_size) SlErrorCorrupt("Link graph structure overflow"); - SlObject(&_linkgraph->edges[std::make_pair(_linkgraph_from, to)], this->GetLoadDescription()); - } + if (to >= max_size) SlErrorCorrupt("Link graph structure overflow"); + SlObject(&_linkgraph->edges[std::make_pair(_linkgraph_from, to)], this->GetLoadDescription()); + } - if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph"); + if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph"); + } else { + /* Edge data is now a simple vector and not any kind of matrix. */ + size_t size = SlGetStructListLength(UINT16_MAX); + for (size_t i = 0; i < size; i++) { + Edge edge; + SlObject(&edge, this->GetLoadDescription()); + if (_edge_dest_node >= max_size) SlErrorCorrupt("Link graph structure overflow"); + _linkgraph->edges[std::make_pair(_linkgraph_from, _edge_dest_node)] = edge; + } + } } }; diff --git a/src/saveload/upstream/saveload.h b/src/saveload/upstream/saveload.h index da427d96f8..d8f10689d7 100644 --- a/src/saveload/upstream/saveload.h +++ b/src/saveload/upstream/saveload.h @@ -319,6 +319,7 @@ struct SaveLoadCompat { /** * Storage of simple variables, references (pointers), and arrays. * @param cmd Load/save type. @see SaveLoadType + * @param name Field name for table chunks. * @param base Name of the class or struct containing the variable. * @param variable Name of the variable in the class or struct referenced by \a base. * @param type Storage of the data in memory and in the savegame. @@ -327,8 +328,20 @@ struct SaveLoadCompat { * @param extra Extra data to pass to the address callback function. * @note In general, it is better to use one of the SLE_* macros below. */ -#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) SaveLoad {#variable, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast(static_cast(std::addressof(static_cast(b)->variable))); }, extra, nullptr} -#define SLE_GENERAL2(cmd, base, name, variable, type, length, from, to, extra) SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast(static_cast(std::addressof(static_cast(b)->variable))); }, extra, nullptr} +#define SLE_GENERAL_NAME(cmd, name, base, variable, type, length, from, to, extra) SaveLoad {name, cmd, type, length, from, to, cpp_sizeof(base, variable), [] (void *b, size_t) -> void * { assert(b != nullptr); return const_cast(static_cast(std::addressof(static_cast(b)->variable))); }, extra, nullptr} + +/** + * Storage of simple variables, references (pointers), and arrays with a custom name. + * @param cmd Load/save type. @see SaveLoadType + * @param base Name of the class or struct containing the variable. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + * @param extra Extra data to pass to the address callback function. + * @note In general, it is better to use one of the SLE_* macros below. + */ +#define SLE_GENERAL(cmd, base, variable, type, length, from, to, extra) SLE_GENERAL_NAME(cmd, #variable, base, variable, type, length, from, to, extra) /** * Storage of a variable in some savegame versions. @@ -339,7 +352,17 @@ struct SaveLoadCompat { * @param to Last savegame version that has the field. */ #define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to, 0) -#define SLE_CONDVAR2(base, name, variable, type, from, to) SLE_GENERAL2(SL_VAR, base, name, variable, type, 0, from, to, 0) + +/** + * Storage of a variable in some savegame versions. + * @param base Name of the class or struct containing the variable. + * @param variable Name of the variable in the class or struct referenced by \a base. + * @param name Field name for table chunks. + * @param type Storage of the data in memory and in the savegame. + * @param from First savegame version that has the field. + * @param to Last savegame version that has the field. + */ +#define SLE_CONDVARNAME(base, variable, name, type, from, to) SLE_GENERAL_NAME(SL_VAR, name, base, variable, type, 0, from, to, 0) /** * Storage of a reference in some savegame versions. @@ -430,7 +453,7 @@ struct SaveLoadCompat { * @param type Storage of the data in memory and in the savegame. */ #define SLE_VAR(base, variable, type) SLE_CONDVAR(base, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) -#define SLE_VAR2(base, name, variable, type) SLE_CONDVAR2(base, name, variable, type, SL_MIN_VERSION, SL_MAX_VERSION) +#define SLE_VAR2(base, name, variable, type) SLE_CONDVARNAME(base, variable, name, type, SL_MIN_VERSION, SL_MAX_VERSION) /** * Storage of a reference in every version of a savegame. diff --git a/src/saveload/upstream/station_sl.cpp b/src/saveload/upstream/station_sl.cpp index c215adb2e8..52966be04e 100644 --- a/src/saveload/upstream/station_sl.cpp +++ b/src/saveload/upstream/station_sl.cpp @@ -17,6 +17,7 @@ #include "../../roadstop_base.h" #include "../../vehicle_base.h" #include "../../newgrf_station.h" +#include "../../newgrf_roadstop.h" #include "table/strings.h" @@ -102,6 +103,33 @@ public: } }; +class SlRoadStopSpecList : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(RoadStopSpecList, grfid, SLE_UINT32), + SLE_VAR(RoadStopSpecList, localidx, SLE_FILE_U8 | SLE_VAR_U16), + }; + inline const static SaveLoadCompatTable compat_description = _station_road_stop_spec_list_sl_compat; + + void Save(BaseStation *bst) const override + { + SlSetStructListLength(bst->roadstop_speclist.size()); + for (uint i = 0; i < bst->roadstop_speclist.size(); i++) { + SlObject(&bst->roadstop_speclist[i], this->GetDescription()); + } + } + + void Load(BaseStation *bst) const override + { + uint8 num_specs = (uint8)SlGetStructListLength(UINT8_MAX); + + bst->roadstop_speclist.resize(num_specs); + for (uint i = 0; i < num_specs; i++) { + SlObject(&bst->roadstop_speclist[i], this->GetLoadDescription()); + } + } +}; + class SlStationCargo : public DefaultSaveLoadHandler { public: inline static const SaveLoad description[] = { @@ -295,6 +323,35 @@ public: } }; +class SlRoadStopTileData : public DefaultSaveLoadHandler { +public: + inline static const SaveLoad description[] = { + SLE_VAR(RoadStopTileData, tile, SLE_UINT32), + SLE_VAR(RoadStopTileData, random_bits, SLE_UINT8), + SLE_VAR(RoadStopTileData, animation_frame, SLE_UINT8), + }; + inline const static SaveLoadCompatTable compat_description = {}; + + static uint8 last_num_specs; ///< Number of specs of the last loaded station. + + void Save(BaseStation *bst) const override + { + SlSetStructListLength(bst->custom_roadstop_tile_data.size()); + for (uint i = 0; i < bst->custom_roadstop_tile_data.size(); i++) { + SlObject(&bst->custom_roadstop_tile_data[i], this->GetDescription()); + } + } + + void Load(BaseStation *bst) const override + { + uint32 num_tiles = (uint32)SlGetStructListLength(UINT32_MAX); + bst->custom_roadstop_tile_data.resize(num_tiles); + for (uint i = 0; i < num_tiles; i++) { + SlObject(&bst->custom_roadstop_tile_data[i], this->GetLoadDescription()); + } + } +}; + /** * SaveLoad handler for the BaseStation, which all other stations / waypoints * make use of. @@ -371,6 +428,7 @@ public: SLE_REFVEC(Station, loading_vehicles, REF_VEHICLE), SLE_CONDVAR(Station, always_accepted, SLE_FILE_U32 | SLE_VAR_U64, SLV_127, SLV_EXTEND_CARGOTYPES), SLE_CONDVAR(Station, always_accepted, SLE_UINT64, SLV_EXTEND_CARGOTYPES, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("speclist", SlRoadStopTileData, SLV_NEWGRF_ROAD_STOPS, SL_MAX_VERSION), SLEG_STRUCTLIST("goods", SlStationGoods), }; inline const static SaveLoadCompatTable compat_description = _station_normal_sl_compat; @@ -434,6 +492,7 @@ static const SaveLoad _station_desc[] = { SLEG_STRUCT("normal", SlStationNormal), SLEG_STRUCT("waypoint", SlStationWaypoint), SLEG_CONDSTRUCTLIST("speclist", SlStationSpecList, SLV_27, SL_MAX_VERSION), + SLEG_CONDSTRUCTLIST("roadstopspeclist", SlRoadStopSpecList, SLV_NEWGRF_ROAD_STOPS, SL_MAX_VERSION), }; struct STNNChunkHandler : ChunkHandler { diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp index 8fdad1b0c3..70526c118c 100644 --- a/src/script/api/script_object.hpp +++ b/src/script/api/script_object.hpp @@ -19,6 +19,8 @@ #include "../script_suspend.hpp" #include "../squirrel.hpp" +#include + struct CommandAuxiliaryBase; /** @@ -342,4 +344,68 @@ private: static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY) }; +/** + * Internally used class to automate the ScriptObject reference counting. + * @api -all + */ +template +class ScriptObjectRef { +private: + T *data; ///< The reference counted object. +public: + /** + * Create the reference counter for the given ScriptObject instance. + * @param data The underlying object. + */ + ScriptObjectRef(T *data) : data(data) + { + this->data->AddRef(); + } + + /* No copy constructor. */ + ScriptObjectRef(const ScriptObjectRef &ref) = delete; + + /* Move constructor. */ + ScriptObjectRef(ScriptObjectRef &&ref) noexcept : data(std::exchange(ref.data, nullptr)) + { + } + + /* No copy assignment. */ + ScriptObjectRef& operator=(const ScriptObjectRef &other) = delete; + + /* Move assignment. */ + ScriptObjectRef& operator=(ScriptObjectRef &&other) noexcept + { + std::swap(this->data, other.data); + return *this; + } + + /** + * Release the reference counted object. + */ + ~ScriptObjectRef() + { + if (this->data != nullptr) this->data->Release(); + } + + /** + * Dereferencing this reference returns a reference to the reference + * counted object + * @return Reference to the underlying object. + */ + T &operator*() + { + return *this->data; + } + + /** + * The arrow operator on this reference returns the reference counted object. + * @return Pointer to the underlying object. + */ + T *operator->() + { + return this->data; + } +}; + #endif /* SCRIPT_OBJECT_HPP */ diff --git a/src/script/api/script_priorityqueue.cpp b/src/script/api/script_priorityqueue.cpp index fda452096a..96f36e10ee 100644 --- a/src/script/api/script_priorityqueue.cpp +++ b/src/script/api/script_priorityqueue.cpp @@ -45,7 +45,7 @@ SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm) this->queue.emplace_back(priority, item); std::push_heap(this->queue.begin(), this->queue.end(), this->comp); - return SQConvert::Return(vm, true); + return SQConvert::Return::Set(vm, true); } SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm) @@ -61,7 +61,7 @@ SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm) this->queue.pop_back(); /* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */ - auto ret = SQConvert::Return(vm, item); + auto ret = SQConvert::Return::Set(vm, item); sq_release(vm, &item); return ret; } @@ -74,7 +74,7 @@ SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm) return 1; } - return SQConvert::Return(vm, this->queue.front().second); + return SQConvert::Return::Set(vm, this->queue.front().second); } SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm) @@ -83,7 +83,7 @@ SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm) sq_resetobject(&item); sq_getstackobj(vm, 2, &item); - return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend()); + return SQConvert::Return::Set(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend()); } SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm) diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp index 240d13722d..b961f2c81b 100644 --- a/src/script/api/script_road.cpp +++ b/src/script/api/script_road.cpp @@ -162,9 +162,9 @@ * @param end The part that will be build second. * @return True if and only if the road bits can be build. */ -static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end) +static bool CheckAutoExpandedRoadBits(const Array<> &existing, int32 start, int32 end) { - return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end); + return (start + end == 0) && (existing.empty() || existing[0] == start || existing[0] == end); } /** @@ -177,7 +177,7 @@ static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 * they are build or 2 when building the first part automatically * builds the second part. */ -static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end) +static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array<> &existing, int32 start, int32 end) { switch (slope) { /* Flat slopes can always be build. */ @@ -189,9 +189,9 @@ static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, in * in the game have been changed. */ case SLOPE_NE: case SLOPE_SW: - return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0; + return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing.empty() ? 2 : 1) : 0; case SLOPE_SE: case SLOPE_NW: - return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0; + return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing.empty() ? 2 : 1) : 0; /* Any other tile cannot be built on. */ default: @@ -241,7 +241,7 @@ static RoadBits NeighbourToRoadBits(int32 neighbour) * they are build or 2 when building the first part automatically * builds the second part. */ -static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end) +static int32 LookupWithBuildOnSlopes(::Slope slope, const Array<> &existing, int32 start, int32 end) { /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(slope)) { @@ -291,9 +291,6 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start /* Now perform the actual rotation. */ for (int j = 0; j < base_rotate; j++) { - for (size_t i = 0; i < existing->size; i++) { - existing->array[i] = RotateNeighbour(existing->array[i]); - } start = RotateNeighbour(start); end = RotateNeighbour(end); } @@ -302,8 +299,11 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start RoadBits start_roadbits = NeighbourToRoadBits(start); RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end); RoadBits existing_roadbits = ROAD_NONE; - for (size_t i = 0; i < existing->size; i++) { - existing_roadbits |= NeighbourToRoadBits(existing->array[i]); + for (int32 neighbour : existing) { + for (int j = 0; j < base_rotate; j++) { + neighbour = RotateNeighbour(neighbour); + } + existing_roadbits |= NeighbourToRoadBits(neighbour); } switch (slope) { @@ -391,7 +391,7 @@ static bool NormaliseTileOffset(int32 *tile) return false; } -/* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_) +/* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> existing, TileIndex start_, TileIndex end_) { ::Slope slope = (::Slope)slope_; int32 start = start_; @@ -400,8 +400,8 @@ static bool NormaliseTileOffset(int32 *tile) /* The start tile and end tile cannot be the same tile either. */ if (start == end) return -1; - for (size_t i = 0; i < existing->size; i++) { - if (!NormaliseTileOffset(&existing->array[i])) return -1; + for (size_t i = 0; i < existing.size(); i++) { + if (!NormaliseTileOffset(&existing[i])) return -1; } if (!NormaliseTileOffset(&start)) return -1; @@ -419,8 +419,6 @@ static bool NormaliseTileOffset(int32 *tile) /* ROAD_NW ROAD_SW ROAD_SE ROAD_NE */ const TileIndexDiff neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)}; - Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32)); - existing->size = 0; ::RoadBits rb = ::ROAD_NONE; if (::IsNormalRoadTile(tile)) { @@ -428,8 +426,10 @@ static bool NormaliseTileOffset(int32 *tile) } else { rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM); } + + Array<> existing; for (uint i = 0; i < lengthof(neighbours); i++) { - if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i]; + if (HasBit(rb, i)) existing.emplace_back(neighbours[i]); } return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile); diff --git a/src/script/api/script_road.hpp b/src/script/api/script_road.hpp index 4050be32c7..9aca035d1c 100644 --- a/src/script/api/script_road.hpp +++ b/src/script/api/script_road.hpp @@ -11,6 +11,7 @@ #define SCRIPT_ROAD_HPP #include "script_tile.hpp" +#include "../squirrel_helper_type.hpp" #include "../../../road.h" /** @@ -264,7 +265,7 @@ public: * they are build or 2 when building the first part automatically * builds the second part. -1 means the preconditions are not met. */ - static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, struct Array *existing, TileIndex start, TileIndex end); + static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> existing, TileIndex start, TileIndex end); /** * Lookup function for building road parts independent of whether the diff --git a/src/script/api/script_text.cpp b/src/script/api/script_text.cpp index e9bf26e73e..ba09edda70 100644 --- a/src/script/api/script_text.cpp +++ b/src/script/api/script_text.cpp @@ -10,6 +10,7 @@ #include "../../stdafx.h" #include "../../string_func.h" #include "../../strings_func.h" +#include "../../game/game_text.hpp" #include "script_text.hpp" #include "../script_fatalerror.hpp" #include "../../table/control_codes.h" @@ -24,7 +25,7 @@ RawText::RawText(const char *text) : text(text) ScriptText::ScriptText(HSQUIRRELVM vm) : - string(STR_NULL), params(), parami(), paramt(), paramc(0) + string(STR_NULL), param(), paramc(0) { int nparam = sq_gettop(vm) - 1; if (nparam < 1) { @@ -53,32 +54,16 @@ ScriptText::ScriptText(HSQUIRRELVM vm) : } } -ScriptText::~ScriptText() -{ - for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) { - free(this->params[i]); - if (this->paramt[i] != nullptr) this->paramt[i]->Release(); - } -} - SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) { if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR; - free(this->params[parameter]); - if (this->paramt[parameter] != nullptr) this->paramt[parameter]->Release(); - - this->parami[parameter] = 0; - this->params[parameter] = nullptr; - this->paramt[parameter] = nullptr; - switch (sq_gettype(vm, -1)) { case OT_STRING: { const SQChar *value; sq_getstring(vm, -1, &value); - this->params[parameter] = stredup(value); - StrMakeValidInPlace(this->params[parameter]); + this->param[parameter] = StrMakeValid(value); break; } @@ -86,7 +71,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) SQInteger value; sq_getinteger(vm, -1, &value); - this->parami[parameter] = value; + this->param[parameter] = value; break; } @@ -109,8 +94,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm) if (real_instance == nullptr) return SQ_ERROR; ScriptText *value = static_cast(real_instance); - value->AddRef(); - this->paramt[parameter] = value; + this->param[parameter] = ScriptTextRef(value); break; } @@ -185,19 +169,37 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count) { p += Utf8Encode(p, SCC_ENCODED); p += seprintf(p, lastofp, "%X", this->string); - for (int i = 0; i < this->paramc; i++) { - if (this->params[i] != nullptr) { - p += seprintf(p, lastofp, ":\"%s\"", this->params[i]); - param_count++; - continue; - } - if (this->paramt[i] != nullptr) { - p += seprintf(p, lastofp, ":"); - p = this->paramt[i]->_GetEncodedText(p, lastofp, param_count); - continue; + + const StringParams ¶ms = GetGameStringParams(this->string); + int cur_idx = 0; + + for (const StringParam &cur_param : params) { + if (cur_idx >= this->paramc) throw Script_FatalError("Not enough string parameters"); + + switch (cur_param.type) { + case StringParam::RAW_STRING: + if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type"); + p += seprintf(p, lastofp, ":\"%s\"", std::get(this->param[cur_idx++]).c_str()); + break; + + case StringParam::STRING: { + if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type"); + int count = 1; // 1 because the string id is included in consumed parameters + p += seprintf(p, lastofp, ":"); + p = std::get(this->param[cur_idx++])->_GetEncodedText(p, lastofp, count); + if (count != cur_param.consumes) throw Script_FatalError("Substring doesn't consume the expected amount of parameters."); + break; + } + + default: + if (cur_idx + cur_param.consumes > this->paramc) throw Script_FatalError("Not enough string parameters"); + for (int i = 0; i < cur_param.consumes; i++) { + if (!std::holds_alternative(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type"); + p += seprintf(p, lastofp,":" OTTD_PRINTFHEX64, std::get(this->param[cur_idx++])); + } } - p += seprintf(p, lastofp,":" OTTD_PRINTFHEX64, this->parami[i]); - param_count++; + + param_count += cur_param.consumes; } return p; diff --git a/src/script/api/script_text.hpp b/src/script/api/script_text.hpp index ebacd70dd7..82f0c716c1 100644 --- a/src/script/api/script_text.hpp +++ b/src/script/api/script_text.hpp @@ -13,6 +13,8 @@ #include "script_object.hpp" #include "../../core/alloc_type.hpp" +#include + /** * Internal parent object of all Text-like objects. * @api -all @@ -88,7 +90,6 @@ public: */ ScriptText(StringID string, ...); #endif /* DOXYGEN_API */ - ~ScriptText(); #ifndef DOXYGEN_API /** @@ -127,10 +128,10 @@ public: virtual const std::string GetEncodedText(); private: + using ScriptTextRef = ScriptObjectRef; + StringID string; - char *params[SCRIPT_TEXT_MAX_PARAMETERS]; - int64 parami[SCRIPT_TEXT_MAX_PARAMETERS]; - ScriptText *paramt[SCRIPT_TEXT_MAX_PARAMETERS]; + std::variant param[SCRIPT_TEXT_MAX_PARAMETERS]; int paramc; /** diff --git a/src/script/squirrel_helper.hpp b/src/script/squirrel_helper.hpp index d5db92c74e..bfa55bfa1a 100644 --- a/src/script/squirrel_helper.hpp +++ b/src/script/squirrel_helper.hpp @@ -14,6 +14,7 @@ #include "../core/smallvec_type.hpp" #include "../economy_type.h" #include "../string_func.h" +#include "../tile_type.h" #include "squirrel_helper_type.hpp" template const char *GetClassName(); @@ -34,1110 +35,161 @@ namespace SQConvert { } }; - template struct YesT { - static const bool Yes = Y; - static const bool No = !Y; - }; - - /** - * Helper class to recognize if the given type is void. Usage: 'IsVoidT::Yes' - */ - template struct IsVoidT : YesT {}; - template <> struct IsVoidT : YesT {}; - - /** - * Helper class to recognize if the function/method return type is void. - */ - template struct HasVoidReturnT; - /* functions */ - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - /* methods */ - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - template struct HasVoidReturnT : IsVoidT {}; - - - /** - * Special class to make it possible for the compiler to pick the correct GetParam(). - */ - template class ForceType { }; - - /** - * To return a value to squirrel, we call this function. It converts to the right format. - */ - template static int Return(HSQUIRRELVM vm, T t); - - template <> inline int Return (HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, int64 res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } - template <> inline int Return(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } - template <> inline int Return (HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } - template <> inline int Return (HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } - - /** - * To get a param from squirrel, we call this function. It converts to the right format. - */ - template static T GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr); - - template <> inline uint8 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline uint16 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline uint32 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int8 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int16 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int32 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline int64 GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline Money GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } - template <> inline bool GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } - template <> inline void *GetParam(ForceType , HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } - template <> inline const char *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) - { - /* Convert what-ever there is as parameter to a string */ - sq_tostring(vm, index); - - const SQChar *tmp; - sq_getstring(vm, -1, &tmp); - char *tmp_str = stredup(tmp); - sq_poptop(vm); - ptr->push_back((void *)tmp_str); - StrMakeValidInPlace(tmp_str); - return tmp_str; - } - - template <> inline Array *GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) - { - /* Sanity check of the size. */ - if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large"); - - SQObject obj; - sq_getstackobj(vm, index, &obj); - sq_pushobject(vm, obj); - sq_pushnull(vm); - - std::vector data; - - while (SQ_SUCCEEDED(sq_next(vm, -2))) { - SQInteger tmp; - if (SQ_SUCCEEDED(sq_getinteger(vm, -1, &tmp))) { - data.push_back((int32)tmp); - } else { - sq_pop(vm, 4); - throw sq_throwerror(vm, "a member of an array used as parameter to a function is not numeric"); - } - - sq_pop(vm, 2); - } - sq_pop(vm, 2); - - Array *arr = (Array*)MallocT(sizeof(Array) + sizeof(int32) * data.size()); - arr->size = data.size(); - memcpy(arr->array, data.data(), sizeof(int32) * data.size()); - - ptr->push_back(arr); - return arr; - } /** - * Helper class to recognize the function type (retval type, args) and use the proper specialization - * for SQ callback. The partial specializations for the second arg (Tis_void_retval) are not possible - * on the function. Therefore the class is used instead. + * To return a value to squirrel, we use this helper class. It converts to the right format. + * We use a class instead of a plain function to allow us to use partial template specializations. */ - template ::Yes> struct HelperT; - - /** - * The real C++ caller for function with return value and 0 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(), HSQUIRRELVM vm) - { - return Return(vm, (*func)()); - } - }; - - /** - * The real C++ caller for function with no return value and 0 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(), HSQUIRRELVM vm) - { - (*func)(); - return 0; - } - }; + template struct Return; - /** - * The real C++ caller for method with return value and 0 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(), HSQUIRRELVM vm) - { - return Return(vm, (instance->*func)()); - } - }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint8 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint16 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, uint32 res) { sq_pushinteger(vm, (int32)res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int8 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int16 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int32 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, int64 res) { sq_pushinteger(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } }; + //template <> struct Return { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32)res.value); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } }; + template <> struct Return { static inline int Set(HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } }; /** - * The real C++ caller for method with no return value and 0 params. + * To get a param from squirrel, we use this helper class. It converts to the right format. + * We use a class instead of a plain function to allow us to use partial template specializations. */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(), HSQUIRRELVM vm) - { - (instance->*func)(); - return 0; - } + template struct Param; - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(), HSQUIRRELVM vm) - { - return new Tcls(); - } - }; + template <> struct Param { static inline uint8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline uint32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline int64 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + //template <> struct Param { static inline TileIndex Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } }; + template <> struct Param { static inline Money Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } }; + template <> struct Param { static inline bool Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } }; + template <> struct Param { static inline void *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } }; - /** - * The real C++ caller for function with return value and 1 param. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 1 param. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1), HSQUIRRELVM vm) + template <> struct Param { + static inline const char *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr) - ); - return 0; - } - }; + /* Convert what-ever there is as parameter to a string */ + sq_tostring(vm, index); - /** - * The real C++ caller for method with return value and 1 param. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr) - ); - return Return(vm, ret); + const SQChar *tmp; + sq_getstring(vm, -1, &tmp); + char *tmp_str = stredup(tmp); + sq_poptop(vm); + ptr->push_back((void *)tmp_str); + StrMakeValidInPlace(tmp_str); + return tmp_str; } }; - /** - * The real C++ caller for method with no return value and 1 param. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1), HSQUIRRELVM vm) + template + struct Param> { + static inline Array Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr) - ); - return 0; - } + /* Sanity check of the size. */ + if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large"); - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr) - ); + SQObject obj; + sq_getstackobj(vm, index, &obj); + sq_pushobject(vm, obj); + sq_pushnull(vm); - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 2 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr) - ); - return Return(vm, ret); - } - }; + Array data; - /** - * The real C++ caller for function with no return value and 2 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 2 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 2 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 3 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 3 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 3 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 3 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 4 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 4 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 4 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 4 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 5 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 5 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 5 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 5 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 6 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 6 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 6 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 6 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 7 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 7 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 7 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 7 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 8 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for function with no return value and 8 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 8 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr) - ); - return Return(vm, ret); - } - }; - - /** - * The real C++ caller for method with no return value and 8 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr) - ); - return 0; - } - - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr) - ); - - return inst; - } - }; + while (SQ_SUCCEEDED(sq_next(vm, -2))) { + data.emplace_back(Param::Get(vm, -1, ptr)); + sq_pop(vm, 2); + } + sq_pop(vm, 2); - /** - * The real C++ caller for function with return value and 9 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr) - ); - return Return(vm, ret); + return data; } }; /** - * The real C++ caller for function with no return value and 9 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr) - ); - return 0; - } - }; - - /** - * The real C++ caller for method with return value and 9 params. + * Helper class to recognize the function type (retval type, args) and use the proper specialization + * for SQ callback. The partial specializations for the second arg (Tis_void_retval) are not possible + * on the function. Therefore the class is used instead. */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr) - ); - return Return(vm, ret); - } - }; + template struct HelperT; /** - * The real C++ caller for method with no return value and 9 params. + * The real C++ caller for functions. */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9), HSQUIRRELVM vm) + template + struct HelperT { + static int SQCall(void *instance, Tretval(*func)(Targs...), HSQUIRRELVM vm) { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr) - ); - return 0; + return SQCall(instance, func, vm, std::index_sequence_for{}); } - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9), HSQUIRRELVM vm) + private: + template + static int SQCall(void *instance, Tretval(*func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - SQAutoFreePointers ptr; - Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr) - ); - - return inst; - } - }; - - /** - * The real C++ caller for function with return value and 10 params. - */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9, Targ10), HSQUIRRELVM vm) - { - SQAutoFreePointers ptr; - Tretval ret = (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr), - GetParam(ForceType(), vm, 11, &ptr) - ); - return Return(vm, ret); + [[maybe_unused]] SQAutoFreePointers ptr; + if constexpr (std::is_void_v) { + (*func)( + Param::Get(vm, 2 + i, &ptr)... + ); + return 0; + } else { + Tretval ret = (*func)( + Param::Get(vm, 2 + i, &ptr)... + ); + return Return::Set(vm, ret); + } } }; /** - * The real C++ caller for function with no return value and 10 params. + * The real C++ caller for methods. */ - template - struct HelperT { - static int SQCall(void *instance, Tretval (*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9, Targ10), HSQUIRRELVM vm) + template + struct HelperT { + static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), HSQUIRRELVM vm) { - SQAutoFreePointers ptr; - (*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr), - GetParam(ForceType(), vm, 11, &ptr) - ); - return 0; + return SQCall(instance, func, vm, std::index_sequence_for{}); } - }; - /** - * The real C++ caller for method with return value and 10 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9, Targ10), HSQUIRRELVM vm) + static Tcls *SQConstruct(Tcls *instance, Tretval(Tcls:: *func)(Targs...), HSQUIRRELVM vm) { - SQAutoFreePointers ptr; - Tretval ret = (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr), - GetParam(ForceType(), vm, 11, &ptr) - ); - return Return(vm, ret); + return SQConstruct(instance, func, vm, std::index_sequence_for{}); } - }; - /** - * The real C++ caller for method with no return value and 10 params. - */ - template - struct HelperT { - static int SQCall(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9, Targ10), HSQUIRRELVM vm) + private: + template + static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - SQAutoFreePointers ptr; - (instance->*func)( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr), - GetParam(ForceType(), vm, 11, &ptr) - ); - return 0; + [[maybe_unused]] SQAutoFreePointers ptr; + if constexpr (std::is_void_v) { + (instance->*func)( + Param::Get(vm, 2 + i, &ptr)... + ); + return 0; + } else { + Tretval ret = (instance->*func)( + Param::Get(vm, 2 + i, &ptr)... + ); + return Return::Set(vm, ret); + } } - static Tcls *SQConstruct(Tcls *instance, Tretval (Tcls::*func)(Targ1, Targ2, Targ3, Targ4, Targ5, Targ6, Targ7, Targ8, Targ9, Targ10), HSQUIRRELVM vm) + template + static Tcls *SQConstruct(Tcls *, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence) { - SQAutoFreePointers ptr; + [[maybe_unused]] SQAutoFreePointers ptr; Tcls *inst = new Tcls( - GetParam(ForceType(), vm, 2, &ptr), - GetParam(ForceType(), vm, 3, &ptr), - GetParam(ForceType(), vm, 4, &ptr), - GetParam(ForceType(), vm, 5, &ptr), - GetParam(ForceType(), vm, 6, &ptr), - GetParam(ForceType(), vm, 7, &ptr), - GetParam(ForceType(), vm, 8, &ptr), - GetParam(ForceType(), vm, 9, &ptr), - GetParam(ForceType(), vm, 10, &ptr), - GetParam(ForceType(), vm, 11, &ptr) + Param::Get(vm, 2 + i, &ptr)... ); return inst; diff --git a/src/script/squirrel_helper_type.hpp b/src/script/squirrel_helper_type.hpp index c20655ca19..05f3824fd9 100644 --- a/src/script/squirrel_helper_type.hpp +++ b/src/script/squirrel_helper_type.hpp @@ -10,10 +10,10 @@ #ifndef SQUIRREL_HELPER_TYPE_HPP #define SQUIRREL_HELPER_TYPE_HPP +#include + /** Definition of a simple array. */ -struct Array { - size_t size; ///< The size of the array. - int32 array[]; ///< The data of the array. -}; +template +using Array = std::vector; #endif /* SQUIRREL_HELPER_TYPE_HPP */ diff --git a/src/settings.cpp b/src/settings.cpp index 8a97fa7ecc..28b0fe7f39 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1801,7 +1801,10 @@ static void ParseCompanyPasswordStorageSecret(const std::string &value) static void UpdateClientConfigValues() { NetworkServerUpdateGameInfo(); - if (_network_server) NetworkServerSendConfigUpdate(); + if (_network_server) { + NetworkServerSendConfigUpdate(); + SetWindowClassesDirty(WC_CLIENT_LIST); + } } /* End - Callback Functions */ diff --git a/src/spritecache.cpp b/src/spritecache.cpp index a7ba2bc5a1..fd7f215d0e 100644 --- a/src/spritecache.cpp +++ b/src/spritecache.cpp @@ -120,7 +120,7 @@ static inline SpriteCache *GetSpriteCache(uint index) static inline bool IsMapgenSpriteID(SpriteID sprite) { - return IsInsideMM(sprite, 4845, 4882); + return IsInsideMM(sprite, SPR_MAPGEN_BEGIN, SPR_MAPGEN_END); } static SpriteCache *AllocateSpriteCache(uint index) diff --git a/src/station.cpp b/src/station.cpp index 7bccab4387..ef853c605f 100644 --- a/src/station.cpp +++ b/src/station.cpp @@ -479,6 +479,7 @@ bool Station::CatchmentCoversTown(TownID t) const /** * Recompute tiles covered in our catchment area. * This will additionally recompute nearby towns and industries. + * @param no_clear_nearby_lists If Station::RemoveFromAllNearbyLists does not need to be called. */ void Station::RecomputeCatchment(bool no_clear_nearby_lists) { diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index fb7d9ed2ee..7483d21362 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3663,83 +3663,89 @@ static Foundation GetFoundation_Station(TileIndex tile, Slope tileh) return FlatteningFoundation(tileh); } -static void GetTileDesc_Station(TileIndex tile, TileDesc *td) -{ - td->owner[0] = GetTileOwner(tile); - - if (IsAnyRoadStopTile(tile)) { - RoadType road_rt = GetRoadTypeRoad(tile); - RoadType tram_rt = GetRoadTypeTram(tile); - Owner road_owner = INVALID_OWNER; - Owner tram_owner = INVALID_OWNER; - if (road_rt != INVALID_ROADTYPE) { - const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); - td->roadtype = rti->strings.name; - td->road_speed = rti->max_speed / 2; - road_owner = GetRoadOwner(tile, RTT_ROAD); - } - - if (tram_rt != INVALID_ROADTYPE) { - const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); - td->tramtype = rti->strings.name; - td->tram_speed = rti->max_speed / 2; - tram_owner = GetRoadOwner(tile, RTT_TRAM); - } - - if (IsDriveThroughStopTile(tile)) { - /* Is there a mix of owners? */ - if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || - (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { - uint i = 1; - if (road_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; - td->owner[i] = road_owner; - i++; - } - if (tram_owner != INVALID_OWNER) { - td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; - td->owner[i] = tram_owner; - } +static void FillTileDescRoadStop(TileIndex tile, TileDesc *td) +{ + RoadType road_rt = GetRoadTypeRoad(tile); + RoadType tram_rt = GetRoadTypeTram(tile); + Owner road_owner = INVALID_OWNER; + Owner tram_owner = INVALID_OWNER; + if (road_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(road_rt); + td->roadtype = rti->strings.name; + td->road_speed = rti->max_speed / 2; + road_owner = GetRoadOwner(tile, RTT_ROAD); + } + + if (tram_rt != INVALID_ROADTYPE) { + const RoadTypeInfo *rti = GetRoadTypeInfo(tram_rt); + td->tramtype = rti->strings.name; + td->tram_speed = rti->max_speed / 2; + tram_owner = GetRoadOwner(tile, RTT_TRAM); + } + + if (IsDriveThroughStopTile(tile)) { + /* Is there a mix of owners? */ + if ((tram_owner != INVALID_OWNER && tram_owner != td->owner[0]) || + (road_owner != INVALID_OWNER && road_owner != td->owner[0])) { + uint i = 1; + if (road_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_ROAD_OWNER; + td->owner[i] = road_owner; + i++; + } + if (tram_owner != INVALID_OWNER) { + td->owner_type[i] = STR_LAND_AREA_INFORMATION_TRAM_OWNER; + td->owner[i] = tram_owner; } } } +} - td->build_date = BaseStation::GetByTile(tile)->build_date; - - if (HasStationTileRail(tile)) { - const StationSpec *spec = GetStationSpec(tile); +void FillTileDescRailStation(TileIndex tile, TileDesc *td) +{ + const StationSpec *spec = GetStationSpec(tile); - if (spec != nullptr) { - td->station_class = StationClass::Get(spec->cls_id)->name; - td->station_name = spec->name; + if (spec != nullptr) { + td->station_class = StationClass::Get(spec->cls_id)->name; + td->station_name = spec->name; - if (spec->grf_prop.grffile != nullptr) { - const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid); - td->grf = gc->GetName(); - } + if (spec->grf_prop.grffile != nullptr) { + const GRFConfig *gc = GetGRFConfig(spec->grf_prop.grffile->grfid); + td->grf = gc->GetName(); } - - const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); - td->rail_speed = rti->max_speed; - td->railtype = rti->strings.name; } - if (IsAirport(tile)) { - const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec(); - td->airport_class = AirportClass::Get(as->cls_id)->name; - td->airport_name = as->name; + const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(tile)); + td->rail_speed = rti->max_speed; + td->railtype = rti->strings.name; +} - const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); - td->airport_tile_name = ats->name; +void FillTileDescAirport(TileIndex tile, TileDesc *td) +{ + const AirportSpec *as = Station::GetByTile(tile)->airport.GetSpec(); + td->airport_class = AirportClass::Get(as->cls_id)->name; + td->airport_name = as->name; - if (as->grf_prop.grffile != nullptr) { - const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid); - td->grf = gc->GetName(); - } else if (ats->grf_prop.grffile != nullptr) { - const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid); - td->grf = gc->GetName(); - } + const AirportTileSpec *ats = AirportTileSpec::GetByTile(tile); + td->airport_tile_name = ats->name; + + if (as->grf_prop.grffile != nullptr) { + const GRFConfig *gc = GetGRFConfig(as->grf_prop.grffile->grfid); + td->grf = gc->GetName(); + } else if (ats->grf_prop.grffile != nullptr) { + const GRFConfig *gc = GetGRFConfig(ats->grf_prop.grffile->grfid); + td->grf = gc->GetName(); } +} + +static void GetTileDesc_Station(TileIndex tile, TileDesc *td) +{ + td->owner[0] = GetTileOwner(tile); + td->build_date = BaseStation::GetByTile(tile)->build_date; + + if (IsAnyRoadStopTile(tile)) FillTileDescRoadStop(tile, td); + if (HasStationRail(tile)) FillTileDescRailStation(tile, td); + if (IsAirport(tile)) FillTileDescAirport(tile, td); StringID str; switch (GetStationType(tile)) { diff --git a/src/strgen/strgen.h b/src/strgen/strgen.h index 4c7a58e8d0..bba76eb188 100644 --- a/src/strgen/strgen.h +++ b/src/strgen/strgen.h @@ -152,6 +152,22 @@ struct LanguageWriter { virtual void WriteLang(const StringData &data); }; +struct CmdStruct; + +struct CmdPair { + const CmdStruct *a; + const char *v; +}; + +struct ParsedCommandStruct { + uint np; + CmdPair pairs[32]; + const CmdStruct *cmd[32]; // ordered by param # +}; + +const CmdStruct *TranslateCmdForCompare(const CmdStruct *a); +void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings); + void CDECL strgen_warning(const char *s, ...) WARN_FORMAT(1, 2); void CDECL strgen_error(const char *s, ...) WARN_FORMAT(1, 2); void NORETURN CDECL strgen_fatal(const char *s, ...) WARN_FORMAT(1, 2); diff --git a/src/strgen/strgen_base.cpp b/src/strgen/strgen_base.cpp index e47d6bebd0..9ca1eb5f75 100644 --- a/src/strgen/strgen_base.cpp +++ b/src/strgen/strgen_base.cpp @@ -222,17 +222,6 @@ uint StringData::CountInUse(uint tab) const static const char *_cur_ident; -struct CmdPair { - const CmdStruct *a; - const char *v; -}; - -struct ParsedCommandStruct { - uint np; - CmdPair pairs[32]; - const CmdStruct *cmd[32]; // ordered by param # -}; - /* Used when generating some advanced commands. */ static ParsedCommandStruct _cur_pcs; static int _cur_argidx; @@ -598,7 +587,7 @@ StringReader::~StringReader() { } -static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings) +void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool warnings) { char param[MAX_COMMAND_PARAM_SIZE]; int argno; @@ -632,7 +621,7 @@ static void ExtractCommandString(ParsedCommandStruct *p, const char *s, bool war } -static const CmdStruct *TranslateCmdForCompare(const CmdStruct *a) +const CmdStruct *TranslateCmdForCompare(const CmdStruct *a) { if (a == nullptr) return nullptr; diff --git a/src/strings.cpp b/src/strings.cpp index ab373f7acb..fc51e1051e 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1177,8 +1177,9 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg sub_args.SetParam(i++, param); } else { + s++; // skip the leading \" char *g = stredup(s); - g[p - s] = '\0'; + g[p - s - 1] = '\0'; // skip the trailing \" sub_args_need_free[i] = true; sub_args.SetParam(i++, (uint64)(size_t)g); @@ -1295,7 +1296,6 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg break; case SCC_RAW_STRING_POINTER: { // {RAW_STRING} - if (game_script) break; const char *raw_string = (const char *)(size_t)args->GetInt64(SCC_RAW_STRING_POINTER); buff = FormatString(buff, raw_string, args, last); break; diff --git a/src/table/sprites.h b/src/table/sprites.h index 83d442bd10..a6d1165a4e 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -1179,6 +1179,10 @@ static const SpriteID SPR_OTTD_N = 4839; static const SpriteID SPR_OTTD_T = 4836; /* Letters not used: R,A,S,Y,C (4837, 4838, 4840, 4843, 4844) */ +/* Range of "special" sprites that are used by the old map generation algorithm. */ +static const SpriteID SPR_MAPGEN_BEGIN = 4845; +static const SpriteID SPR_MAPGEN_END = 4882; + static const SpriteID SPR_HIGHSCORE_CHART_BEGIN = 4804; static const SpriteID SPR_TYCOON_IMG1_BEGIN = 4814; static const SpriteID SPR_TYCOON_IMG2_BEGIN = 4824; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index e7502ebf0a..b7acf02ea3 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -4397,10 +4397,10 @@ bool CanVehicleUseStation(const Vehicle *v, const Station *st) } /** - * Get reason string why this station can't be used by the given vehicle - * @param v the vehicle to test - * @param st the station to test for - * @return true if and only if the vehicle can use this station. + * Get reason string why this station can't be used by the given vehicle. + * @param v The vehicle to test. + * @param st The station to test for. + * @return The string explaining why the vehicle cannot use the station. */ StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st) { @@ -4415,15 +4415,18 @@ StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st) StringID err = rv->IsBus() ? STR_ERROR_NO_BUS_STATION : STR_ERROR_NO_TRUCK_STATION; for (; rs != nullptr; rs = rs->next) { - /* The vehicle is articulated and can therefore not go to a standard road stop. */ - if (IsStandardRoadStopTile(rs->xy) && rv->HasArticulatedPart()) { - err = STR_ERROR_NO_STOP_ARTIC_VEH; + /* Articulated vehicles cannot use bay road stops, only drive-through. Make sure the vehicle can actually use this bay stop */ + if (HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && IsStandardRoadStopTile(rs->xy) && rv->HasArticulatedPart()) { + err = STR_ERROR_NO_STOP_ARTICULATED_VEHICLE; continue; } - /* The vehicle cannot go to this roadstop (different roadtype) */ - if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes)) return STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE; - return INVALID_STRING_ID; + /* Bay stop errors take precedence, but otherwise the vehicle may not be compatible with the roadtype/tramtype of this station tile. + * We give bay stop errors precedence because they are usually a bus sent to a tram station or vice versa. */ + if (!HasTileAnyRoadType(rs->xy, rv->compatible_roadtypes) && err != STR_ERROR_NO_STOP_ARTICULATED_VEHICLE) { + err = RoadTypeIsRoad(rv->roadtype) ? STR_ERROR_NO_STOP_COMPATIBLE_ROAD_TYPE : STR_ERROR_NO_STOP_COMPATIBLE_TRAM_TYPE; + continue; + } } return err; @@ -4437,7 +4440,7 @@ StringID GetVehicleCannotUseStationReason(const Vehicle *v, const Station *st) if (v->GetEngine()->u.air.subtype & AIR_CTOL) { return STR_ERROR_AIRPORT_NO_PLANES; } else { - return STR_ERROR_AIRPORT_NO_HELIS; + return STR_ERROR_AIRPORT_NO_HELICOPTERS; } default: diff --git a/src/widgets/industry_widget.h b/src/widgets/industry_widget.h index 5e3a656c1f..9f5762a534 100644 --- a/src/widgets/industry_widget.h +++ b/src/widgets/industry_widget.h @@ -37,6 +37,7 @@ enum IndustryDirectoryWidgets { WID_ID_DROPDOWN_CRITERIA, ///< Dropdown for the criteria of the sort. WID_ID_FILTER_BY_ACC_CARGO, ///< Accepted cargo filter dropdown list. WID_ID_FILTER_BY_PROD_CARGO, ///< Produced cargo filter dropdown list. + WID_ID_FILTER, ///< Textbox to filter industry name. WID_ID_INDUSTRY_LIST, ///< Industry list. WID_ID_SCROLLBAR, ///< Scrollbar of the list. };