diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 78542a2942..7ad6eb54d4 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -94,7 +94,6 @@ jobs: liblzo2-dev \ libsdl1.2-dev \ libsdl2-dev \ - libxdg-basedir-dev \ zlib1g-dev \ # EOF echo "::endgroup::" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 965fe1bf61..275a994d99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -479,8 +479,7 @@ jobs: useVcpkgToolchainFile: false buildDirectory: '${{ github.workspace }}/build-host' buildWithCMakeArgs: '--target tools' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DOPTION_TOOLS_ONLY=ON' + cmakeAppendedArgs: ' -GNinja -DOPTION_TOOLS_ONLY=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Install MSVC problem matcher uses: ammaraskar/msvc-problem-matcher@master @@ -492,8 +491,7 @@ jobs: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced useVcpkgToolchainFile: true buildDirectory: '${{ github.workspace }}/build' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DOPTION_USE_NSIS=ON -DHOST_BINARY_DIR=${{ github.workspace }}/build-host' + cmakeAppendedArgs: ' -GNinja -DOPTION_USE_NSIS=ON -DHOST_BINARY_DIR=${{ github.workspace }}/build-host -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Build (without installer) if: needs.source.outputs.is_tag != 'true' || matrix.arch == 'arm64' @@ -502,8 +500,7 @@ jobs: cmakeListsOrSettingsJson: CMakeListsTxtAdvanced useVcpkgToolchainFile: true buildDirectory: '${{ github.workspace }}/build' - cmakeBuildType: RelWithDebInfo - cmakeAppendedArgs: ' -GNinja -DHOST_BINARY_DIR=${{ github.workspace }}/build-host' + cmakeAppendedArgs: ' -GNinja -DHOST_BINARY_DIR=${{ github.workspace }}/build-host -DCMAKE_BUILD_TYPE=RelWithDebInfo' - name: Create bundles shell: bash diff --git a/CMakeLists.txt b/CMakeLists.txt index 51f3bfa476..6164310b8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,7 +107,6 @@ if(NOT WIN32) find_package(Fluidsynth) find_package(Fontconfig) find_package(ICU OPTIONAL_COMPONENTS i18n lx) - find_package(XDG_basedir) else() find_package(Iconv) @@ -264,7 +263,6 @@ link_package(PNG TARGET PNG::PNG ENCOURAGED) link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED) link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED) link_package(LZO) -link_package(XDG_basedir) if(NOT OPTION_DEDICATED) link_package(Fluidsynth) @@ -291,7 +289,6 @@ if(APPLE) add_definitions( -DWITH_COCOA - -DENABLE_COCOA_QUARTZ ) endif() @@ -301,6 +298,8 @@ if(EMSCRIPTEN) # Allow heap-growth, and start with a bigger memory size. target_link_libraries(WASM::WASM INTERFACE "-s ALLOW_MEMORY_GROWTH=1") target_link_libraries(WASM::WASM INTERFACE "-s INITIAL_MEMORY=33554432") + target_link_libraries(WASM::WASM INTERFACE "-s DISABLE_EXCEPTION_CATCHING=0") + add_definitions(-s DISABLE_EXCEPTION_CATCHING=0) # Export functions to Javascript. target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'") diff --git a/COMPILING.md b/COMPILING.md index 759dd2e9c4..145b244753 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -81,6 +81,9 @@ cmake .. make ``` +For more information on how to use CMake (including how to make Release builds), +we urge you to read [their excellent manual](https://cmake.org/cmake/help/latest/guide/user-interaction/index.html). + ## Supported compilers Every compiler that is supported by CMake and supports C++17, should be diff --git a/cmake/CompileFlags.cmake b/cmake/CompileFlags.cmake index 672e88a4e7..b7db3de538 100644 --- a/cmake/CompileFlags.cmake +++ b/cmake/CompileFlags.cmake @@ -133,10 +133,20 @@ macro(compile_flags) ) endif() - if(APPLE) + if(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") add_compile_options( -fno-stack-check ) + + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-mno-sse4" NO_SSE4_FOUND) + + if(NO_SSE4_FOUND) + add_compile_options( + # Don't use SSE4 for general sources to increase compatibility. + -mno-sse4 + ) + endif() endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") add_compile_options( diff --git a/cmake/FindXDG_basedir.cmake b/cmake/FindXDG_basedir.cmake deleted file mode 100644 index a33e9760dc..0000000000 --- a/cmake/FindXDG_basedir.cmake +++ /dev/null @@ -1,65 +0,0 @@ -#[=======================================================================[.rst: -FindXDG_basedir -------- - -Finds the xdg-basedir library. - -Result Variables -^^^^^^^^^^^^^^^^ - -This will define the following variables: - -``XDG_basedir_FOUND`` - True if the system has the xdg-basedir library. -``XDG_basedir_INCLUDE_DIRS`` - Include directories needed to use xdg-basedir. -``XDG_basedir_LIBRARIES`` - Libraries needed to link to xdg-basedir. -``XDG_basedir_VERSION`` - The version of the xdg-basedir library which was found. - -Cache Variables -^^^^^^^^^^^^^^^ - -The following cache variables may also be set: - -``XDG_basedir_INCLUDE_DIR`` - The directory containing ``xdg-basedir.h``. -``XDG_basedir_LIBRARY`` - The path to the xdg-basedir library. - -#]=======================================================================] - -find_package(PkgConfig QUIET) -pkg_check_modules(PC_XDG_basedir QUIET libxdg-basedir) - -find_path(XDG_basedir_INCLUDE_DIR - NAMES basedir.h - PATHS ${PC_XDG_basedir_INCLUDE_DIRS} -) - -find_library(XDG_basedir_LIBRARY - NAMES xdg-basedir - PATHS ${PC_XDG_basedir_LIBRARY_DIRS} -) - -set(XDG_basedir_VERSION ${PC_XDG_basedir_VERSION}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(XDG_basedir - FOUND_VAR XDG_basedir_FOUND - REQUIRED_VARS - XDG_basedir_LIBRARY - XDG_basedir_INCLUDE_DIR - VERSION_VAR XDG_basedir_VERSION -) - -if(XDG_basedir_FOUND) - set(XDG_basedir_LIBRARIES ${XDG_basedir_LIBRARY}) - set(XDG_basedir_INCLUDE_DIRS ${XDG_basedir_INCLUDE_DIR}) -endif() - -mark_as_advanced( - XDG_basedir_INCLUDE_DIR - XDG_basedir_LIBRARY -) diff --git a/cmake/InstallAndPackage.cmake b/cmake/InstallAndPackage.cmake index baea3981ce..925739fde7 100644 --- a/cmake/InstallAndPackage.cmake +++ b/cmake/InstallAndPackage.cmake @@ -123,25 +123,37 @@ elseif(UNIX) OUTPUT_VARIABLE LSB_RELEASE_ID OUTPUT_STRIP_TRAILING_WHITESPACE ) - if(NOT LSB_RELEASE_ID) + if(LSB_RELEASE_ID) + if(LSB_RELEASE_ID STREQUAL "Ubuntu" OR LSB_RELEASE_ID STREQUAL "Debian") + execute_process(COMMAND ${LSB_RELEASE_EXEC} -cs + OUTPUT_VARIABLE LSB_RELEASE_CODENAME + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(TOLOWER "${LSB_RELEASE_ID}-${LSB_RELEASE_CODENAME}" PLATFORM) + + set(CPACK_GENERATOR "DEB") + include(PackageDeb) + else() + set(UNSUPPORTED_PLATFORM_NAME "LSB-based Linux distribution '${LSB_RELEASE_ID}'") + endif() + elseif(EXISTS "/etc/os-release") + file(STRINGS "/etc/os-release" OS_RELEASE_CONTENTS REGEX "^ID=") + string(REGEX MATCH "ID=(.*)" _ ${OS_RELEASE_CONTENTS}) + set(DISTRO_ID ${CMAKE_MATCH_1}) + if(DISTRO_ID STREQUAL "arch") + set(PLATFORM "generic") + set(CPACK_GENERATOR "TXZ") + else() + set(UNSUPPORTED_PLATFORM_NAME "Linux distribution '${DISTRO_ID}' from /etc/os-release") + endif() + else() + set(UNSUPPORTED_PLATFORM_NAME "Linux distribution") + endif() + + if(NOT PLATFORM) set(PLATFORM "generic") set(CPACK_GENERATOR "TXZ") - - message(WARNING "Unknown Linux distribution found for packaging; can only pack to a txz. Please consider creating a Pull Request to add support for this distribution.") - elseif(LSB_RELEASE_ID STREQUAL "Ubuntu" OR LSB_RELEASE_ID STREQUAL "Debian") - execute_process(COMMAND ${LSB_RELEASE_EXEC} -cs - OUTPUT_VARIABLE LSB_RELEASE_CODENAME - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(TOLOWER "${LSB_RELEASE_ID}-${LSB_RELEASE_CODENAME}" PLATFORM) - - set(CPACK_GENERATOR "DEB") - include(PackageDeb) - else() - set(PLATFORM "unknown") - set(CPACK_GENERATOR "TXZ") - - message(WARNING "Unknown LSB-based Linux distribution '${LSB_RELEASE_ID}' found for packaging; can only pack to a txz. Please consider creating a Pull Request to add support for this distribution.") + message(WARNING "Unknown ${UNSUPPORTED_PLATFORM_NAME} found for packaging; can only pack to a txz. Please consider creating a Pull Request to add support for this distribution.") endif() set(CPACK_PACKAGE_FILE_NAME "openttd-#CPACK_PACKAGE_VERSION#-linux-${PLATFORM}-${CPACK_SYSTEM_NAME}") diff --git a/cmake/MSVCFilters.cmake b/cmake/MSVCFilters.cmake index 14c7b2c351..df576a98a9 100644 --- a/cmake/MSVCFilters.cmake +++ b/cmake/MSVCFilters.cmake @@ -8,6 +8,7 @@ source_group("MD5" REGULAR_EXPRESSION "src/3rdparty/md5/") source_group("Misc" REGULAR_EXPRESSION "src/misc/") source_group("Music" REGULAR_EXPRESSION "src/music/") source_group("Network Core" REGULAR_EXPRESSION "src/network/core/") +source_group("OSX" REGULAR_EXPRESSION "src/os/macosx/") source_group("Pathfinder" REGULAR_EXPRESSION "src/pathfinder/") source_group("Save/Load handlers" REGULAR_EXPRESSION "src/saveload/") source_group("Sound" REGULAR_EXPRESSION "src/sound/") diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 7d418a96a6..fb6e6f2282 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -97,6 +97,8 @@ struct AIListWindow : public Window { this->selected = i; break; } + + i++; } } } @@ -324,8 +326,6 @@ struct AISettingsWindow : public Window { this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR); this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect. - this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode != GM_MENU && Company::IsValidID(this->slot)); - this->RebuildVisibleSettings(); } @@ -533,10 +533,8 @@ struct AISettingsWindow : public Window { break; case WID_AIS_RESET: - if (_game_mode == GM_MENU || !Company::IsValidID(this->slot)) { - this->ai_config->ResetSettings(); - this->SetDirty(); - } + this->ai_config->ResetEditableSettings(_game_mode == GM_MENU || ((this->slot != OWNER_DEITY) && !Company::IsValidID(this->slot))); + this->SetDirty(); break; } } diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp index 1431a2820b..9b3613712d 100644 --- a/src/ai/ai_scanner.cpp +++ b/src/ai/ai_scanner.cpp @@ -32,8 +32,7 @@ void AIScannerInfo::Initialize() ScriptAllocatorScope alloc_scope(this->engine); /* Create the dummy AI */ - free(this->main_script); - this->main_script = stredup("%_dummy"); + this->main_script = "%_dummy"; extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir); Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai"); } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index a0dfd086f0..05dad908cf 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -180,9 +180,8 @@ static bool VerifyAutoreplaceRefitForOrders(const Vehicle *v, EngineID engine_ty CargoTypes union_refit_mask_a = GetUnionOfArticulatedRefitMasks(v->engine_type, false); CargoTypes union_refit_mask_b = GetUnionOfArticulatedRefitMasks(engine_type, false); - const Order *o; const Vehicle *u = (v->type == VEH_TRAIN) ? v->First() : v; - FOR_VEHICLE_ORDERS(u, o) { + for (const Order *o : u->Orders()) { if (!o->IsRefit() || o->IsAutoRefit()) continue; CargoID cargo_type = o->GetRefitCargo(); diff --git a/src/base_media_base.h b/src/base_media_base.h index 881fdc3f38..790bb9d38c 100644 --- a/src/base_media_base.h +++ b/src/base_media_base.h @@ -167,7 +167,7 @@ protected: static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded. static const Tbase_set *used_set; ///< The currently used set - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; /** * Get the extension that is used to identify this set. diff --git a/src/base_media_func.h b/src/base_media_func.h index c5e2a6da23..8491f0e510 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -150,24 +150,24 @@ bool BaseSet::FillSetDetails(IniFile *ini, const } template -bool BaseMedia::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool BaseMedia::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { bool ret = false; - DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename); + DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename.c_str()); Tbase_set *set = new Tbase_set(); IniFile *ini = new IniFile(); - char *path = stredup(filename + basepath_length); + std::string path{ filename, basepath_length }; ini->LoadFromDisk(path, BASESET_DIR); - char *psep = strrchr(path, PATHSEPCHAR); - if (psep != nullptr) { - psep[1] = '\0'; + auto psep = path.rfind(PATHSEPCHAR); + if (psep != std::string::npos) { + path.erase(psep + 1); } else { - *path = '\0'; + path.clear(); } - if (set->FillSetDetails(ini, path, filename)) { + if (set->FillSetDetails(ini, path.c_str(), filename.c_str())) { Tbase_set *duplicate = nullptr; for (Tbase_set *c = BaseMedia::available_sets; c != nullptr; c = c->next) { if (c->name == set->name || c->shortname == set->shortname) { @@ -214,7 +214,6 @@ bool BaseMedia::AddFile(const char *filename, size_t basepath_length, } else { delete set; } - free(path); delete ini; return ret; @@ -378,7 +377,7 @@ template #define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \ template std::string repl_type::ini_set; \ template const char *repl_type::GetExtension(); \ - template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \ + template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \ template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \ template bool repl_type::SetSet(const std::string &name); \ template char *repl_type::GetSetsList(char *p, const char *last); \ diff --git a/src/blitter/32bpp_sse2.hpp b/src/blitter/32bpp_sse2.hpp index 7802c2b0ac..45af1f542a 100644 --- a/src/blitter/32bpp_sse2.hpp +++ b/src/blitter/32bpp_sse2.hpp @@ -31,7 +31,7 @@ public: uint8 m; uint8 v; }; - assert_compile(sizeof(MapValue) == 2); + static_assert(sizeof(MapValue) == 2); /** Helper for creating specialised functions for specific optimisations. */ enum ReadMode { diff --git a/src/cargomonitor.h b/src/cargomonitor.h index 252b5b49fa..30cc50ab5c 100644 --- a/src/cargomonitor.h +++ b/src/cargomonitor.h @@ -47,8 +47,8 @@ enum CargoCompanyBits { CCB_COMPANY_LENGTH = 4, ///< Number of bits of the company field. }; -assert_compile(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH)); -assert_compile(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH)); +static_assert(NUM_CARGO <= (1 << CCB_CARGO_TYPE_LENGTH)); +static_assert(MAX_COMPANIES <= (1 << CCB_COMPANY_LENGTH)); /** diff --git a/src/cargopacket.cpp b/src/cargopacket.cpp index af5e1a0c77..8a07f04712 100644 --- a/src/cargopacket.cpp +++ b/src/cargopacket.cpp @@ -740,8 +740,8 @@ void VehicleCargoList::InvalidateCache() template uint VehicleCargoList::Reassign(uint max_move, TileOrStationID) { - assert_tcompile(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); - assert_tcompile(Tfrom - Tto == 1 || Tto - Tfrom == 1); + static_assert(Tfrom != MTA_TRANSFER && Tto != MTA_TRANSFER); + static_assert(Tfrom - Tto == 1 || Tto - Tfrom == 1); max_move = min(this->action_counts[Tfrom], max_move); this->action_counts[Tfrom] -= max_move; this->action_counts[Tto] += max_move; diff --git a/src/cheat_gui.cpp b/src/cheat_gui.cpp index 266457fdc3..061be02a5c 100644 --- a/src/cheat_gui.cpp +++ b/src/cheat_gui.cpp @@ -205,7 +205,7 @@ static bool IsCheatAllowed(CheatNetworkMode mode) return false; } -assert_compile(CHT_NUM_CHEATS == lengthof(_cheats_ui)); +static_assert(CHT_NUM_CHEATS == lengthof(_cheats_ui)); /** Widget definitions of the cheat GUI. */ static const NWidgetPart _nested_cheat_widgets[] = { diff --git a/src/cmd_helper.h b/src/cmd_helper.h index ee5d445c28..ceb4d4bd9b 100644 --- a/src/cmd_helper.h +++ b/src/cmd_helper.h @@ -24,9 +24,9 @@ template static inline T Extract(U v) { /* Check if there are enough bits in v */ - assert_tcompile(N == EnumPropsT::num_bits); - assert_tcompile(S + N <= sizeof(U) * 8); - assert_tcompile(EnumPropsT::end <= (1 << N)); + static_assert(N == EnumPropsT::num_bits); + static_assert(S + N <= sizeof(U) * 8); + static_assert(EnumPropsT::end <= (1 << N)); U masked = GB(v, S, N); return IsInsideMM(masked, EnumPropsT::begin, EnumPropsT::end) ? (T)masked : EnumPropsT::invalid; } diff --git a/src/command.cpp b/src/command.cpp index 1b2fb09018..bc523fbd7e 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -672,7 +672,7 @@ bool IsCommandAllowedWhilePaused(uint32 cmd) CMDPL_NO_ACTIONS, ///< CMDT_SERVER_SETTING CMDPL_NO_ACTIONS, ///< CMDT_CHEAT }; - assert_compile(lengthof(command_type_lookup) == CMDT_END); + static_assert(lengthof(command_type_lookup) == CMDT_END); assert(IsValidCommand(cmd)); return _game_mode == GM_EDITOR || command_type_lookup[_command_proc_table[cmd & CMD_ID_MASK].type] <= _settings_game.construction.command_pause_level; diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 2b92920261..c99324b98a 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -2469,7 +2469,7 @@ struct CompanyWindow : Window if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) { DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE); } else { - assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); + static_assert(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings)); for (uint i = 0; i < lengthof(amounts); i++) { if (amounts[i] != 0) { diff --git a/src/company_manager_face.h b/src/company_manager_face.h index 2f16656d56..fe6365a121 100644 --- a/src/company_manager_face.h +++ b/src/company_manager_face.h @@ -83,7 +83,7 @@ static const CompanyManagerFaceBitsInfo _cmf_info[] = { /* CMFV_GLASSES */ { 31, 1, { 2, 2, 2, 2 }, { 0x347, 0x347, 0x3AE, 0x3AE } } ///< Depends on CMFV_HAS_GLASSES }; /** Make sure the table's size is right. */ -assert_compile(lengthof(_cmf_info) == CMFV_END); +static_assert(lengthof(_cmf_info) == CMFV_END); /** * Gets the company manager's face bits for the given company manager's face variable diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index ee6e661287..2679198316 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -1903,7 +1903,7 @@ struct ConsoleContentCallback : public ContentCallback { static void OutputContentState(const ContentInfo *const ci) { static const char * const types[] = { "Base graphics", "NewGRF", "AI", "AI library", "Scenario", "Heightmap", "Base sound", "Base music", "Game script", "GS library" }; - assert_compile(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN); + static_assert(lengthof(types) == CONTENT_TYPE_END - CONTENT_TYPE_BEGIN); static const char * const states[] = { "Not selected", "Selected", "Dep Selected", "Installed", "Unknown" }; static const TextColour state_to_colour[] = { CC_COMMAND, CC_INFO, CC_INFO, CC_WHITE, CC_ERROR }; diff --git a/src/core/math_func.hpp b/src/core/math_func.hpp index 1723fa47e5..1617a6ce3d 100644 --- a/src/core/math_func.hpp +++ b/src/core/math_func.hpp @@ -112,7 +112,7 @@ static inline T Align(const T x, uint n) template static inline T *AlignPtr(T *x, uint n) { - assert_compile(sizeof(size_t) == sizeof(void *)); + static_assert(sizeof(size_t) == sizeof(void *)); return reinterpret_cast(Align((size_t)x, n)); } diff --git a/src/core/pool_type.hpp b/src/core/pool_type.hpp index 0cbc982197..582239155f 100644 --- a/src/core/pool_type.hpp +++ b/src/core/pool_type.hpp @@ -80,7 +80,7 @@ private: template struct Pool : PoolBase { /* Ensure Tmax_size is within the bounds of Tindex. */ - assert_compile((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0); + static_assert((uint64)(Tmax_size - 1) >> 8 * sizeof(Tindex) == 0); static const size_t MAX_SIZE = Tmax_size; ///< Make template parameter accessible from outside diff --git a/src/cpu.cpp b/src/cpu.cpp index 87aa841324..bafa0f7352 100644 --- a/src/cpu.cpp +++ b/src/cpu.cpp @@ -66,6 +66,12 @@ uint64 ottd_rdtsc() # define RDTSC_AVAILABLE #endif +#if defined(__EMSCRIPTEN__) && !defined(RDTSC_AVAILABLE) +/* On emscripten doing TIC/TOC would be ill-advised */ +uint64 ottd_rdtsc() {return 0;} +# define RDTSC_AVAILABLE +#endif + /* In all other cases we have no support for rdtsc. No major issue, * you just won't be able to profile your code with TIC()/TOC() */ #if !defined(RDTSC_AVAILABLE) diff --git a/src/crashlog.cpp b/src/crashlog.cpp index 476be47ca0..b73c956003 100644 --- a/src/crashlog.cpp +++ b/src/crashlog.cpp @@ -548,7 +548,7 @@ char *CrashLog::FillVersionInfoLog(char *buffer, const char *last) const */ bool CrashLog::WriteCrashLog(const char *buffer, char *filename, const char *filename_last, const char *name, FILE **crashlog_file) const { - seprintf(filename, filename_last, "%s%s.log", _personal_dir, name); + seprintf(filename, filename_last, "%s%s.log", _personal_dir.c_str(), name); FILE *file = FioFOpenFile(filename, "w", NO_DIRECTORY); if (file == nullptr) return false; @@ -587,7 +587,7 @@ bool CrashLog::WriteSavegame(char *filename, const char *filename_last, const ch try { GamelogEmergency(); - seprintf(filename, filename_last, "%s%s.sav", _personal_dir, name); + seprintf(filename, filename_last, "%s%s.sav", _personal_dir.c_str(), name); /* Don't do a threaded saveload. */ return SaveOrLoad(filename, SLO_SAVE, DFT_GAME_FILE, NO_DIRECTORY, false) == SL_OK; diff --git a/src/departures_gui.cpp b/src/departures_gui.cpp index 43ab1360c1..1f0fcb29c1 100644 --- a/src/departures_gui.cpp +++ b/src/departures_gui.cpp @@ -148,9 +148,7 @@ protected: for (const Vehicle *v : Vehicle::Iterate()) { if (v->type < 4 && this->show_types[v->type] && v->IsPrimaryVehicle()) { - const Order *order; - - FOR_VEHICLE_ORDERS(v, order) { + for(const Order *order : v->Orders()) { if ((order->IsType(OT_GOTO_STATION) || order->IsType(OT_GOTO_WAYPOINT) || order->IsType(OT_IMPLICIT)) && order->GetDestination() == this->station) { this->vehicles.push_back(v); diff --git a/src/economy.cpp b/src/economy.cpp index 9f66afd29b..4c28297ae3 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1342,7 +1342,7 @@ void PrepareUnload(Vehicle *front_v) assert(front_v->cargo_payment == nullptr); /* One CargoPayment per vehicle and the vehicle limit equals the * limit in number of CargoPayments. Can't go wrong. */ - assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); + static_assert(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); assert(CargoPayment::CanAllocateItem()); front_v->cargo_payment = new CargoPayment(front_v); diff --git a/src/economy_type.h b/src/economy_type.h index 0fc2abcfd1..4ffe054dd6 100644 --- a/src/economy_type.h +++ b/src/economy_type.h @@ -224,6 +224,10 @@ static const int INVALID_PRICE_MODIFIER = MIN_PRICE_MODIFIER - 1; static const uint TUNNELBRIDGE_TRACKBIT_FACTOR = 4; /** Multiplier for how many regular track bits a level crossing counts. */ static const uint LEVELCROSSING_TRACKBIT_FACTOR = 2; +/** Multiplier for how many regular track bits a road depot counts. */ +static const uint ROAD_DEPOT_TRACKBIT_FACTOR = 2; +/** Multiplier for how many regular track bits a bay stop counts. */ +static const uint ROAD_STOP_TRACKBIT_FACTOR = 2; /** Multiplier for how many regular tiles a lock counts. */ static const uint LOCK_DEPOT_TILE_FACTOR = 2; diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 111aa27d59..d65560c433 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -572,7 +572,7 @@ static EffectInitProc * const _effect_init_procs[] = { SmokeInit, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeInit, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_init_procs) == EV_END); +static_assert(lengthof(_effect_init_procs) == EV_END); /** Functions for controlling effect vehicles at each tick. */ static EffectTickProc * const _effect_tick_procs[] = { @@ -589,7 +589,7 @@ static EffectTickProc * const _effect_tick_procs[] = { SmokeTick, // EV_BREAKDOWN_SMOKE_AIRCRAFT SmokeTick, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_tick_procs) == EV_END); +static_assert(lengthof(_effect_tick_procs) == EV_END); /** Transparency options affecting the effects. */ static const TransparencyOption _effect_transparency_options[] = { @@ -606,7 +606,7 @@ static const TransparencyOption _effect_transparency_options[] = { TO_INVALID, // EV_BREAKDOWN_SMOKE_AIRCRAFT TO_INDUSTRIES, // EV_COPPER_MINE_SMOKE }; -assert_compile(lengthof(_effect_transparency_options) == EV_END); +static_assert(lengthof(_effect_transparency_options) == EV_END); /** diff --git a/src/engine.cpp b/src/engine.cpp index ec4fab77aa..1d063c7af1 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -63,7 +63,7 @@ const uint8 _engine_offsets[4] = { lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info), }; -assert_compile(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info)); +static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_info) + lengthof(_orig_ship_vehicle_info) + lengthof(_orig_aircraft_vehicle_info) == lengthof(_orig_engine_info)); const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; @@ -663,9 +663,8 @@ void StartupOneEngine(Engine *e, Date aging_date) e->company_avail = 0; e->company_hidden = 0; - /* Don't randomise the start-date in the first two years after gamestart to ensure availability - * of engines in early starting games. - * Note: TTDP uses fixed 1922 */ + /* Vehicles with the same base_intro date shall be introduced at the same time. + * Make sure they use the same randomisation of the date. */ SavedRandomSeeds saved_seeds; SaveRandomSeeds(&saved_seeds); SetRandomSeed(_settings_game.game_creation.generation_seed ^ @@ -674,6 +673,9 @@ void StartupOneEngine(Engine *e, Date aging_date) e->GetGRFID()); uint32 r = Random(); + /* Don't randomise the start-date in the first two years after gamestart to ensure availability + * of engines in early starting games. + * Note: TTDP uses fixed 1922 */ e->intro_date = ei->base_intro <= ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (Date)GB(r, 0, 9) + ei->base_intro; if (e->intro_date <= _date) { e->age = (aging_date - e->intro_date) >> 5; @@ -681,19 +683,20 @@ void StartupOneEngine(Engine *e, Date aging_date) e->flags |= ENGINE_AVAILABLE; } - e->reliability_start = GB(r, 16, 14) + 0x7AE0; - r = Random(); - e->reliability_max = GB(r, 0, 14) + 0xBFFF; - e->reliability_final = GB(r, 16, 14) + 0x3FFF; + RestoreRandomSeeds(saved_seeds); r = Random(); + e->reliability_start = GB(r, 16, 14) + 0x7AE0; + e->reliability_max = GB(r, 0, 14) + 0xBFFF; + + r = Random(); + e->reliability_final = GB(r, 16, 14) + 0x3FFF; e->duration_phase_1 = GB(r, 0, 5) + 7; e->duration_phase_2 = GB(r, 5, 4) + ei->base_life * 12 - 96; e->duration_phase_3 = GB(r, 9, 7) + 120; e->reliability_spd_dec = ei->decay_speed << 2; - RestoreRandomSeeds(saved_seeds); CalcEngineReliability(e); /* prevent certain engines from ever appearing. */ diff --git a/src/fileio.cpp b/src/fileio.cpp index 1e94004cf9..ab34f3a763 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -25,12 +25,9 @@ #endif #include #include +#include #include -#ifdef WITH_XDG_BASEDIR -#include -#endif - #include "safeguards.h" /** Size of the #Fio data buffer. */ @@ -38,14 +35,14 @@ /** Structure for keeping several open files with just one data buffer. */ struct Fio { - byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer + byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file size_t pos; ///< current (system) position in file FILE *cur_fh; ///< current file handle - const char *filename; ///< current filename - FILE *handles[MAX_FILE_SLOTS]; ///< array of file handles we can have open - const char *filenames[MAX_FILE_SLOTS]; ///< array of filenames we (should) have open - char *shortnames[MAX_FILE_SLOTS]; ///< array of short names for spriteloader's use + std::string filename; ///< current filename + std::array handles; ///< array of file handles we can have open + std::array filenames; ///< array of filenames we (should) have open + std::array shortnames;///< array of short names for spriteloader's use }; static Fio _fio; ///< #Fio instance. @@ -53,8 +50,8 @@ static Fio _fio; ///< #Fio instance. /** Whether the working directory should be scanned. */ static bool _do_scan_working_directory = true; -extern char *_config_file; -extern char *_highscore_file; +extern std::string _config_file; +extern std::string _highscore_file; /** * Get position in the current file. @@ -72,7 +69,7 @@ size_t FioGetPos() */ const char *FioGetFilename(uint slot) { - return _fio.shortnames[slot]; + return _fio.shortnames[slot].c_str(); } /** @@ -86,7 +83,7 @@ void FioSeekTo(size_t pos, int mode) _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE; _fio.pos = pos; if (fseek(_fio.cur_fh, _fio.pos, SEEK_SET) < 0) { - DEBUG(misc, 0, "Seeking in %s failed", _fio.filename); + DEBUG(misc, 0, "Seeking in %s failed", _fio.filename.c_str()); } } @@ -177,8 +174,7 @@ static inline void FioCloseFile(int slot) if (_fio.handles[slot] != nullptr) { fclose(_fio.handles[slot]); - free(_fio.shortnames[slot]); - _fio.shortnames[slot] = nullptr; + _fio.shortnames[slot].clear(); _fio.handles[slot] = nullptr; } @@ -198,27 +194,26 @@ void FioCloseAll() * @param filename Name of the file at the disk. * @param subdir The sub directory to search this file in. */ -void FioOpenFile(uint slot, const char *filename, Subdirectory subdir, char **output_filename) +void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir, std::string *output_filename) { FILE *f; f = FioFOpenFile(filename, "rb", subdir, nullptr, output_filename); - if (f == nullptr) usererror("Cannot open file '%s'", filename); + if (f == nullptr) usererror("Cannot open file '%s'", filename.c_str()); long pos = ftell(f); - if (pos < 0) usererror("Cannot read file '%s'", filename); + if (pos < 0) usererror("Cannot read file '%s'", filename.c_str()); FioCloseFile(slot); // if file was opened before, close it _fio.handles[slot] = f; _fio.filenames[slot] = filename; /* Store the filename without path and extension */ - const char *t = strrchr(filename, PATHSEPCHAR); - _fio.shortnames[slot] = stredup(t == nullptr ? filename : t); - char *t2 = strrchr(_fio.shortnames[slot], '.'); - if (t2 != nullptr) *t2 = '\0'; + auto t = filename.rfind(PATHSEPCHAR); + std::string sn = filename.substr(t != std::string::npos ? t + 1 : 0); + _fio.shortnames[slot] = sn.substr(0, sn.rfind('.')); strtolower(_fio.shortnames[slot]); - FioSeekToFile(slot, (uint32)pos); + FioSeekToFile(slot, (size_t)pos); } static const char * const _subdirs[] = { @@ -238,22 +233,38 @@ static const char * const _subdirs[] = { "game" PATHSEP "library" PATHSEP, "screenshot" PATHSEP, }; -assert_compile(lengthof(_subdirs) == NUM_SUBDIRS); +static_assert(lengthof(_subdirs) == NUM_SUBDIRS); -const char *_searchpaths[NUM_SEARCHPATHS]; -TarList _tar_list[NUM_SUBDIRS]; +/** + * The search paths OpenTTD could search through. + * At least one of the slots has to be filled with a path. + * An empty string tells that there is no such path for the + * current operating system. + */ +std::array _searchpaths; +std::array _tar_list; TarFileList _tar_filelist[NUM_SUBDIRS]; typedef std::map TarLinkList; static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links +/** + * Checks whether the given search path is a valid search path + * @param sp the search path to check + * @return true if the search path is valid + */ +bool IsValidSearchPath(Searchpath sp) +{ + return sp < _searchpaths.size() && !_searchpaths[sp].empty(); +} + /** * Check whether the given file exists * @param filename the file to try for existence. * @param subdir the subdirectory to look in * @return true if and only if the file can be opened */ -bool FioCheckFileExists(const char *filename, Subdirectory subdir) +bool FioCheckFileExists(const std::string &filename, Subdirectory subdir) { FILE *f = FioFOpenFile(filename, "rb", subdir); if (f == nullptr) return false; @@ -267,9 +278,9 @@ bool FioCheckFileExists(const char *filename, Subdirectory subdir) * @param filename the file to test. * @return true if and only if the file exists. */ -bool FileExists(const char *filename) +bool FileExists(const std::string &filename) { - return access(OTTD2FS(filename), 0) == 0; + return access(OTTD2FS(filename.c_str()), 0) == 0; } /** @@ -280,68 +291,55 @@ void FioFCloseFile(FILE *f) fclose(f); } -char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename) -{ - assert(subdir < NUM_SUBDIRS); - assert(sp < NUM_SEARCHPATHS); - - seprintf(buf, last, "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); - return buf; -} - /** * Find a path to the filename in one of the search directories. - * @param[out] buf Destination buffer for the path. - * @param last End of the destination buffer. * @param subdir Subdirectory to try. * @param filename Filename to look for. - * @return \a buf containing the path if the path was found, else \c nullptr. + * @return String containing the path if the path was found, else an empty string. */ -char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename) +std::string FioFindFullPath(Subdirectory subdir, const char *filename) { Searchpath sp; assert(subdir < NUM_SUBDIRS); FOR_ALL_SEARCHPATHS(sp) { - FioGetFullPath(buf, last, sp, subdir, filename); + std::string buf = FioGetDirectory(sp, subdir); + buf += filename; if (FileExists(buf)) return buf; #if !defined(_WIN32) /* Be, as opening files, aware that sometimes the filename * might be in uppercase when it is in lowercase on the * disk. Of course Windows doesn't care about casing. */ - if (strtolower(buf + strlen(_searchpaths[sp]) - 1) && FileExists(buf)) return buf; + if (strtolower(buf, _searchpaths[sp].size() - 1) && FileExists(buf)) return buf; #endif } - return nullptr; + return {}; } -char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir) +std::string FioGetDirectory(Searchpath sp, Subdirectory subdir) { assert(subdir < NUM_SUBDIRS); assert(sp < NUM_SEARCHPATHS); - seprintf(buf, last, "%s%s", _searchpaths[sp], _subdirs[subdir]); - return buf; + return _searchpaths[sp] + _subdirs[subdir]; } -char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir) +std::string FioFindDirectory(Subdirectory subdir) { Searchpath sp; /* Find and return the first valid directory */ FOR_ALL_SEARCHPATHS(sp) { - char *ret = FioAppendDirectory(buf, last, sp, subdir); - if (FileExists(buf)) return ret; + std::string ret = FioGetDirectory(sp, subdir); + if (FileExists(ret)) return ret; } /* Could not find the directory, fall back to a base path */ - strecpy(buf, _personal_dir, last); - - return buf; + return _personal_dir; } -static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize, char **output_filename) +static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize, std::string *output_filename) { #if defined(_WIN32) && defined(UNICODE) /* fopen is implemented as a define with ellipses for @@ -352,22 +350,22 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode)); #endif FILE *f = nullptr; - char buf[MAX_PATH]; + std::string buf; if (subdir == NO_DIRECTORY) { - strecpy(buf, filename, lastof(buf)); + buf = filename; } else { - seprintf(buf, lastof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename); + buf = _searchpaths[sp] + _subdirs[subdir] + filename; } #if defined(_WIN32) - if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return nullptr; + if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf.c_str())) == INVALID_FILE_ATTRIBUTES) return nullptr; #endif - f = fopen(buf, mode); + f = fopen(buf.c_str(), mode); #if !defined(_WIN32) - if (f == nullptr && strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1))) { - f = fopen(buf, mode); + if (f == nullptr && strtolower(buf, subdir == NO_DIRECTORY ? 0 : _searchpaths[sp].size() - 1) ) { + f = fopen(buf.c_str(), mode); } #endif if (f != nullptr && filesize != nullptr) { @@ -377,7 +375,7 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s fseek(f, 0, SEEK_SET); } if (output_filename != nullptr) { - *output_filename = (f != nullptr) ? stredup(buf, lastof(buf)) : nullptr; + *output_filename = (f != nullptr) ? std::move(buf) : ""; } return f; } @@ -389,17 +387,17 @@ static FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath s * @return File handle of the opened file, or \c nullptr if the file is not available. * @note The file is read from within the tar file, and may not return \c EOF after reading the whole file. */ -FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) +FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize) { - FILE *f = fopen(entry->tar_filename, "rb"); + FILE *f = fopen(entry.tar_filename.c_str(), "rb"); if (f == nullptr) return f; - if (fseek(f, entry->position, SEEK_SET) < 0) { + if (fseek(f, entry.position, SEEK_SET) < 0) { fclose(f); return nullptr; } - if (filesize != nullptr) *filesize = entry->size; + if (filesize != nullptr) *filesize = entry.size; return f; } @@ -409,7 +407,7 @@ FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize) * @param subdir Subdirectory to open. * @return File handle of the opened file, or \c nullptr if the file is not available. */ -FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize, char **output_filename) +FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize, std::string *output_filename) { FILE *f = nullptr; Searchpath sp; @@ -423,11 +421,8 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, /* We can only use .tar in case of data-dir, and read-mode */ if (f == nullptr && mode[0] == 'r' && subdir != NO_DIRECTORY) { - static const uint MAX_RESOLVED_LENGTH = 2 * (100 + 100 + 155) + 1; // Enough space to hold two filenames plus link. See 'TarHeader'. - char resolved_name[MAX_RESOLVED_LENGTH]; - /* Filenames in tars are always forced to be lowercase */ - strecpy(resolved_name, filename, lastof(resolved_name)); + std::string resolved_name = filename; strtolower(resolved_name); /* Resolve ".." */ @@ -442,38 +437,33 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, tokens.push_back(token); } } - resolved_name[0] = '\0'; + + resolved_name.clear(); bool first = true; for (const std::string &token : tokens) { if (!first) { - strecat(resolved_name, PATHSEP, lastof(resolved_name)); + resolved_name += PATHSEP; } - strecat(resolved_name, token.c_str(), lastof(resolved_name)); + resolved_name += token; first = false; } - size_t resolved_len = strlen(resolved_name); - /* Resolve ONE directory link */ for (TarLinkList::iterator link = _tar_linklist[subdir].begin(); link != _tar_linklist[subdir].end(); link++) { const std::string &src = link->first; size_t len = src.length(); - if (resolved_len >= len && resolved_name[len - 1] == PATHSEPCHAR && strncmp(src.c_str(), resolved_name, len) == 0) { + if (resolved_name.length() >= len && resolved_name[len - 1] == PATHSEPCHAR && src.compare(0, len, resolved_name, 0, len) == 0) { /* Apply link */ - char resolved_name2[MAX_RESOLVED_LENGTH]; - const std::string &dest = link->second; - strecpy(resolved_name2, &(resolved_name[len]), lastof(resolved_name2)); - strecpy(resolved_name, dest.c_str(), lastof(resolved_name)); - strecpy(&(resolved_name[dest.length()]), resolved_name2, lastof(resolved_name)); + resolved_name.replace(0, len, link->second); break; // Only resolve one level } } TarFileList::iterator it = _tar_filelist[subdir].find(resolved_name); if (it != _tar_filelist[subdir].end()) { - f = FioFOpenFileTar(&((*it).second), filesize); + f = FioFOpenFileTar(it->second, filesize); if (output_filename != nullptr && f != nullptr) { - *output_filename = str_fmt("%s" PATHSEP "%s", ((*it).second).tar_filename, filename); + *output_filename = stdstr_fmt("%s" PATHSEP "%s", ((*it).second).tar_filename.c_str(), filename.c_str()); } } } @@ -504,14 +494,12 @@ FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, * If the parent directory does not exist, it will try to create that as well. * @param name the new name of the directory */ -void FioCreateDirectory(const char *name) +void FioCreateDirectory(const std::string &name) { - char dirname[MAX_PATH]; - strecpy(dirname, name, lastof(dirname)); - char *p = strrchr(dirname, PATHSEPCHAR); - if (p != nullptr) { - *p = '\0'; - DIR *dir = ttd_opendir(dirname); + auto p = name.find_last_of(PATHSEPCHAR); + if (p != std::string::npos) { + std::string dirname = name.substr(0, p); + DIR *dir = ttd_opendir(dirname.c_str()); if (dir == nullptr) { FioCreateDirectory(dirname); // Try creating the parent directory, if we couldn't open it } else { @@ -522,11 +510,11 @@ void FioCreateDirectory(const char *name) /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(_WIN32) - CreateDirectory(OTTD2FS(name), nullptr); + CreateDirectory(OTTD2FS(name.c_str()), nullptr); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) - mkdir(OTTD2FS(name)); + mkdir(OTTD2FS(name.c_str())); #else - mkdir(OTTD2FS(name), 0755); + mkdir(OTTD2FS(name.c_str()), 0755); #endif } @@ -534,21 +522,13 @@ void FioCreateDirectory(const char *name) * Appends, if necessary, the path separator character to the end of the string. * It does not add the path separator to zero-sized strings. * @param buf string to append the separator to - * @param last the last element of \a buf. * @return true iff the operation succeeded */ -bool AppendPathSeparator(char *buf, const char *last) +void AppendPathSeparator(std::string &buf) { - size_t s = strlen(buf); + if (buf.empty()) return; - /* Length of string + path separator + '\0' */ - if (s != 0 && buf[s - 1] != PATHSEPCHAR) { - if (&buf[s] >= last) return false; - - seprintf(buf + s, last, "%c", PATHSEPCHAR); - } - - return true; + if (buf.back() != PATHSEPCHAR) buf.push_back(PATHSEPCHAR); } static void TarAddLink(const std::string &srcParam, const std::string &destParam, Subdirectory subdir) @@ -635,16 +615,16 @@ uint TarScanner::DoScan(Subdirectory sd) * @param filename The name of the file to add. * @return True if the additions went correctly. */ -bool TarScanner::AddFile(Subdirectory sd, const char *filename) +bool TarScanner::AddFile(Subdirectory sd, const std::string &filename) { this->subdir = sd; return this->AddFile(filename, 0); } -bool TarScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { /* No tar within tar. */ - assert(tar_filename == nullptr); + assert(tar_filename.empty()); /* The TAR-header, repeated for every file */ struct TarHeader { @@ -672,16 +652,14 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha TarList::iterator it = _tar_list[this->subdir].find(filename); if (it != _tar_list[this->subdir].end()) return false; - FILE *f = fopen(filename, "rb"); + FILE *f = fopen(filename.c_str(), "rb"); /* Although the file has been found there can be * a number of reasons we cannot open the file. * Most common case is when we simply have not * been given read access. */ if (f == nullptr) return false; - const char *dupped_filename = stredup(filename); - _tar_list[this->subdir][filename].filename = dupped_filename; - _tar_list[this->subdir][filename].dirname = nullptr; + _tar_list[this->subdir][filename] = std::string{}; TarLinkList links; ///< Temporary list to collect links @@ -706,7 +684,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* If we have only zeros in the block, it can be an end-of-file indicator */ if (memcmp(&th, &empty[0], 512) == 0) continue; - DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename); + DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename.c_str()); fclose(f); return false; } @@ -736,7 +714,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Store this entry in the list */ TarFileListEntry entry; - entry.tar_filename = dupped_filename; + entry.tar_filename = filename; entry.size = skip; entry.position = pos; @@ -804,7 +782,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha } if (destpos >= lastof(dest)) { - DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename); + DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename.c_str()); fclose(f); return false; } @@ -825,7 +803,7 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Store the first directory name we detect */ DEBUG(misc, 6, "Found dir in tar: %s", name); - if (_tar_list[this->subdir][filename].dirname == nullptr) _tar_list[this->subdir][filename].dirname = stredup(name); + if (_tar_list[this->subdir][filename].empty()) _tar_list[this->subdir][filename] = name; break; default: @@ -836,14 +814,14 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha /* Skip to the next block.. */ skip = Align(skip, 512); if (fseek(f, skip, SEEK_CUR) < 0) { - DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename); + DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename.c_str()); fclose(f); return false; } pos += skip; } - DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename, num); + DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename.c_str(), num); fclose(f); /* Resolve file links and store directory links. @@ -871,51 +849,48 @@ bool TarScanner::AddFile(const char *filename, size_t basepath_length, const cha * @param subdir The sub directory the tar is in. * @return false on failure. */ -bool ExtractTar(const char *tar_filename, Subdirectory subdir) +bool ExtractTar(const std::string &tar_filename, Subdirectory subdir) { TarList::iterator it = _tar_list[subdir].find(tar_filename); /* We don't know the file. */ if (it == _tar_list[subdir].end()) return false; - const char *dirname = (*it).second.dirname; + const auto &dirname = (*it).second; /* The file doesn't have a sub directory! */ - if (dirname == nullptr) { - DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename); + if (dirname.empty()) { + DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename.c_str()); return false; } - char filename[MAX_PATH]; - strecpy(filename, tar_filename, lastof(filename)); - char *p = strrchr(filename, PATHSEPCHAR); + std::string filename = tar_filename; + auto p = filename.find_last_of(PATHSEPCHAR); /* The file's path does not have a separator? */ - if (p == nullptr) return false; + if (p == std::string::npos) return false; - p++; - strecpy(p, dirname, lastof(filename)); - DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename, filename); + filename.replace(p + 1, std::string::npos, dirname); + DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename.c_str(), filename.c_str()); FioCreateDirectory(filename); for (TarFileList::iterator it2 = _tar_filelist[subdir].begin(); it2 != _tar_filelist[subdir].end(); it2++) { - if (strcmp((*it2).second.tar_filename, tar_filename) != 0) continue; + if (tar_filename != it2->second.tar_filename) continue; - strecpy(p, (*it2).first.c_str(), lastof(filename)); + filename.replace(p + 1, std::string::npos, it2->first); - DEBUG(misc, 9, " extracting %s", filename); + DEBUG(misc, 9, " extracting %s", filename.c_str()); /* First open the file in the .tar. */ size_t to_copy = 0; - FILE *in = FioFOpenFileTar(&(*it2).second, &to_copy); - if (in == nullptr) { - DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, tar_filename); + std::unique_ptr in(FioFOpenFileTar(it2->second, &to_copy)); + if (!in) { + DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), tar_filename.c_str()); return false; } /* Now open the 'output' file. */ - FILE *out = fopen(filename, "wb"); - if (out == nullptr) { - DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename, filename); - fclose(in); + std::unique_ptr out(fopen(filename.c_str(), "wb")); + if (!out) { + DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), filename.c_str()); return false; } @@ -923,16 +898,12 @@ bool ExtractTar(const char *tar_filename, Subdirectory subdir) char buffer[4096]; size_t read; for (; to_copy != 0; to_copy -= read) { - read = fread(buffer, 1, min(to_copy, lengthof(buffer)), in); - if (read <= 0 || fwrite(buffer, 1, read, out) != read) break; + read = fread(buffer, 1, min(to_copy, lengthof(buffer)), in.get()); + if (read <= 0 || fwrite(buffer, 1, read, out.get()) != read) break; } - /* Close everything up. */ - fclose(in); - fclose(out); - if (to_copy != 0) { - DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename, (int)to_copy); + DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename.c_str(), (int)to_copy); return false; } } @@ -994,18 +965,39 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe) bool DoScanWorkingDirectory() { /* No working directory, so nothing to do. */ - if (_searchpaths[SP_WORKING_DIR] == nullptr) return false; + if (_searchpaths[SP_WORKING_DIR].empty()) return false; /* Working directory is root, so do nothing. */ - if (strcmp(_searchpaths[SP_WORKING_DIR], PATHSEP) == 0) return false; + if (_searchpaths[SP_WORKING_DIR] == PATHSEP) return false; /* No personal/home directory, so the working directory won't be that. */ - if (_searchpaths[SP_PERSONAL_DIR] == nullptr) return true; + if (_searchpaths[SP_PERSONAL_DIR].empty()) return true; - char tmp[MAX_PATH]; - seprintf(tmp, lastof(tmp), "%s%s", _searchpaths[SP_WORKING_DIR], PERSONAL_DIR); - AppendPathSeparator(tmp, lastof(tmp)); - return strcmp(tmp, _searchpaths[SP_PERSONAL_DIR]) != 0; + std::string tmp = _searchpaths[SP_WORKING_DIR] + PERSONAL_DIR; + AppendPathSeparator(tmp); + + return _searchpaths[SP_PERSONAL_DIR] != tmp; +} + +/** + * Gets the home directory of the user. + * May return an empty string in the unlikely scenario that the home directory cannot be found. + * @return User's home directory + */ +static std::string GetHomeDir() +{ +#ifdef __HAIKU__ + BPath path; + find_directory(B_USER_SETTINGS_DIRECTORY, &path); + return std::string(path.Path()); +#else + const char *home_env = getenv("HOME"); // Stack var, shouldn't be freed + if (home_env != nullptr) return std::string(home_env); + + const struct passwd *pw = getpwuid(getuid()); + if (pw != nullptr) return std::string(pw->pw_dir); +#endif + return {}; } /** @@ -1014,93 +1006,98 @@ bool DoScanWorkingDirectory() */ void DetermineBasePaths(const char *exe) { - char tmp[MAX_PATH]; -#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) - const char *xdg_data_home = xdgDataHome(nullptr); - seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", xdg_data_home, - PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); - free(xdg_data_home); + std::string tmp; + const std::string homedir = GetHomeDir(); +#ifdef USE_XDG + const char *xdg_data_home = getenv("XDG_DATA_HOME"); + if (xdg_data_home != nullptr) { + tmp = xdg_data_home; + tmp += PATHSEP; + tmp += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; + AppendPathSeparator(tmp); + _searchpaths[SP_PERSONAL_DIR_XDG] = tmp; - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_PERSONAL_DIR_XDG] = stredup(tmp); -#endif -#if defined(OS2) || !defined(WITH_PERSONAL_DIR) - _searchpaths[SP_PERSONAL_DIR] = nullptr; -#else -#ifdef __HAIKU__ - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - const char *homedir = stredup(path.Path()); -#else - /* getenv is highly unsafe; duplicate it as soon as possible, - * or at least before something else touches the environment - * variables in any way. It can also contain all kinds of - * unvalidated data we rather not want internally. */ - const char *homedir = getenv("HOME"); - if (homedir != nullptr) { - homedir = stredup(homedir); - } + tmp += "content_download"; + AppendPathSeparator(tmp); + _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR_XDG] = tmp; + } else if (!homedir.empty()) { + tmp = homedir; + tmp += PATHSEP ".local" PATHSEP "share" PATHSEP; + tmp += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; + AppendPathSeparator(tmp); + _searchpaths[SP_PERSONAL_DIR_XDG] = tmp; - if (homedir == nullptr) { - const struct passwd *pw = getpwuid(getuid()); - homedir = (pw == nullptr) ? nullptr : stredup(pw->pw_dir); - } -#endif - - if (homedir != nullptr) { - ValidateString(homedir); - seprintf(tmp, lastof(tmp), "%s" PATHSEP "%s", homedir, PERSONAL_DIR); - AppendPathSeparator(tmp, lastof(tmp)); - - _searchpaths[SP_PERSONAL_DIR] = stredup(tmp); - free(homedir); + tmp += "content_download"; + AppendPathSeparator(tmp); + _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR_XDG] = tmp; } else { - _searchpaths[SP_PERSONAL_DIR] = nullptr; + _searchpaths[SP_PERSONAL_DIR_XDG].clear(); + _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR_XDG].clear(); + } +#endif + +#if defined(OS2) || !defined(WITH_PERSONAL_DIR) + _searchpaths[SP_PERSONAL_DIR].clear(); +#else + if (!homedir.empty()) { + tmp = homedir; + tmp += PATHSEP; + tmp += PERSONAL_DIR; + AppendPathSeparator(tmp); + _searchpaths[SP_PERSONAL_DIR] = tmp; + + tmp += "content_download"; + AppendPathSeparator(tmp); + _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR] = tmp; + } else { + _searchpaths[SP_PERSONAL_DIR].clear(); + _searchpaths[SP_AUTODOWNLOAD_PERSONAL_DIR].clear(); } #endif #if defined(WITH_SHARED_DIR) - seprintf(tmp, lastof(tmp), "%s", SHARED_DIR); - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_SHARED_DIR] = stredup(tmp); + tmp = SHARED_DIR; + AppendPathSeparator(tmp); + _searchpaths[SP_SHARED_DIR] = tmp; #else - _searchpaths[SP_SHARED_DIR] = nullptr; + _searchpaths[SP_SHARED_DIR].clear(); #endif char cwd[MAX_PATH]; if (getcwd(cwd, MAX_PATH) == nullptr) *cwd = '\0'; - if (_config_file == nullptr) { + if (_config_file.empty()) { /* Get the path to working directory of OpenTTD. */ - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + tmp = cwd; + AppendPathSeparator(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; _do_scan_working_directory = DoScanWorkingDirectory(); } else { /* Use the folder of the config file as working directory. */ - char *config_dir = stredup(_config_file); - char *end = strrchr(config_dir, PATHSEPCHAR); - if (end == nullptr) { - free(config_dir); - + size_t end = _config_file.find_last_of(PATHSEPCHAR); + if (end == std::string::npos) { /* _config_file is not in a folder, so use current directory. */ - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_WORKING_DIR] = stredup(tmp); + tmp = cwd; + AppendPathSeparator(tmp); + _searchpaths[SP_WORKING_DIR] = tmp; } else { - end[1] = '\0'; - _searchpaths[SP_WORKING_DIR] = config_dir; + _searchpaths[SP_WORKING_DIR] = _config_file.substr(0, end + 1); } } /* Change the working directory to that one of the executable */ if (ChangeWorkingDirectoryToExecutable(exe)) { - if (getcwd(tmp, MAX_PATH) == nullptr) *tmp = '\0'; - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_BINARY_DIR] = stredup(tmp); + char buf[MAX_PATH]; + if (getcwd(buf, lengthof(buf)) == nullptr) { + tmp.clear(); + } else { + tmp = buf; + } + AppendPathSeparator(tmp); + _searchpaths[SP_BINARY_DIR] = tmp; } else { - _searchpaths[SP_BINARY_DIR] = nullptr; + _searchpaths[SP_BINARY_DIR].clear(); } if (cwd[0] != '\0') { @@ -1111,22 +1108,22 @@ void DetermineBasePaths(const char *exe) } #if !defined(GLOBAL_DATA_DIR) - _searchpaths[SP_INSTALLATION_DIR] = nullptr; + _searchpaths[SP_INSTALLATION_DIR].clear(); #else - seprintf(tmp, lastof(tmp), "%s", GLOBAL_DATA_DIR); - AppendPathSeparator(tmp, lastof(tmp)); - _searchpaths[SP_INSTALLATION_DIR] = stredup(tmp); + tmp = GLOBAL_DATA_DIR; + AppendPathSeparator(tmp); + _searchpaths[SP_INSTALLATION_DIR] = tmp; #endif #ifdef WITH_COCOA -extern void cocoaSetApplicationBundleDir(); - cocoaSetApplicationBundleDir(); +extern void CocoaSetApplicationBundleDir(); + CocoaSetApplicationBundleDir(); #else - _searchpaths[SP_APPLICATION_BUNDLE_DIR] = nullptr; + _searchpaths[SP_APPLICATION_BUNDLE_DIR].clear(); #endif } #endif /* defined(_WIN32) */ -const char *_personal_dir; +std::string _personal_dir; /** * Acquire the base paths (personal dir and game data dir), @@ -1138,35 +1135,40 @@ void DeterminePaths(const char *exe) { DetermineBasePaths(exe); -#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) - char config_home[MAX_PATH]; - - const char *xdg_config_home = xdgConfigHome(nullptr); - seprintf(config_home, lastof(config_home), "%s" PATHSEP "%s", xdg_config_home, - PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR); - free(xdg_config_home); - - AppendPathSeparator(config_home, lastof(config_home)); +#ifdef USE_XDG + std::string config_home; + const std::string homedir = GetHomeDir(); + const char *xdg_config_home = getenv("XDG_CONFIG_HOME"); + if (xdg_config_home != nullptr) { + config_home = xdg_config_home; + config_home += PATHSEP; + config_home += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; + } else if (!homedir.empty()) { + /* Defaults to ~/.config */ + config_home = homedir; + config_home += PATHSEP ".config" PATHSEP; + config_home += PERSONAL_DIR[0] == '.' ? &PERSONAL_DIR[1] : PERSONAL_DIR; + } + AppendPathSeparator(config_home); #endif Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; - DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]); + DEBUG(misc, 4, "%s added as search path", _searchpaths[sp].c_str()); } - const char *config_dir; - if (_config_file != nullptr) { + std::string config_dir; + if (!_config_file.empty()) { config_dir = _searchpaths[SP_WORKING_DIR]; } else { - char personal_dir[MAX_PATH]; - if (FioFindFullPath(personal_dir, lastof(personal_dir), BASE_DIR, "openttd.cfg") != nullptr) { - char *end = strrchr(personal_dir, PATHSEPCHAR); - if (end != nullptr) end[1] = '\0'; - config_dir = stredup(personal_dir); - _config_file = str_fmt("%sopenttd.cfg", config_dir); + std::string personal_dir = FioFindFullPath(BASE_DIR, "openttd.cfg"); + if (!personal_dir.empty()) { + auto end = personal_dir.find_last_of(PATHSEPCHAR); + if (end != std::string::npos) personal_dir.erase(end + 1); + config_dir = personal_dir; } else { -#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) +#ifdef USE_XDG /* No previous configuration file found. Use the configuration folder from XDG. */ config_dir = config_home; #else @@ -1174,28 +1176,27 @@ void DeterminePaths(const char *exe) SP_PERSONAL_DIR, SP_BINARY_DIR, SP_WORKING_DIR, SP_SHARED_DIR, SP_INSTALLATION_DIR }; - config_dir = nullptr; + config_dir.clear(); for (uint i = 0; i < lengthof(new_openttd_cfg_order); i++) { if (IsValidSearchPath(new_openttd_cfg_order[i])) { - config_dir = stredup(_searchpaths[new_openttd_cfg_order[i]]); + config_dir = _searchpaths[new_openttd_cfg_order[i]]; break; } } - assert(config_dir != nullptr); #endif - _config_file = str_fmt("%sopenttd.cfg", config_dir); } + _config_file = config_dir + "openttd.cfg"; } - DEBUG(misc, 3, "%s found as config directory", config_dir); + DEBUG(misc, 3, "%s found as config directory", config_dir.c_str()); - _highscore_file = str_fmt("%shs.dat", config_dir); - extern char *_hotkeys_file; - _hotkeys_file = str_fmt("%shotkeys.cfg", config_dir); - extern char *_windows_file; - _windows_file = str_fmt("%swindows.cfg", config_dir); + _highscore_file = config_dir + "hs.dat"; + extern std::string _hotkeys_file; + _hotkeys_file = config_dir + "hotkeys.cfg"; + extern std::string _windows_file; + _windows_file = config_dir + "windows.cfg"; -#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) +#ifdef USE_XDG if (config_dir == config_home) { /* We are using the XDG configuration home for the config file, * then store the rest in the XDG data home folder. */ @@ -1212,33 +1213,28 @@ void DeterminePaths(const char *exe) FioCreateDirectory(_personal_dir); #endif - DEBUG(misc, 3, "%s found as personal directory", _personal_dir); + DEBUG(misc, 3, "%s found as personal directory", _personal_dir.c_str()); static const Subdirectory default_subdirs[] = { SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR }; for (uint i = 0; i < lengthof(default_subdirs); i++) { - char *dir = str_fmt("%s%s", _personal_dir, _subdirs[default_subdirs[i]]); - FioCreateDirectory(dir); - free(dir); + FioCreateDirectory(_personal_dir + _subdirs[default_subdirs[i]]); } /* If we have network we make a directory for the autodownloading of content */ - _searchpaths[SP_AUTODOWNLOAD_DIR] = str_fmt("%s%s", _personal_dir, "content_download" PATHSEP); + _searchpaths[SP_AUTODOWNLOAD_DIR] = _personal_dir + "content_download" PATHSEP; FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]); /* Create the directory for each of the types of content */ const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR }; for (uint i = 0; i < lengthof(dirs); i++) { - char *tmp = str_fmt("%s%s", _searchpaths[SP_AUTODOWNLOAD_DIR], _subdirs[dirs[i]]); - FioCreateDirectory(tmp); - free(tmp); + FioCreateDirectory(FioGetDirectory(SP_AUTODOWNLOAD_DIR, dirs[i])); } extern std::string _log_file; - _log_file = _personal_dir; - _log_file += "openttd.log"; + _log_file = _personal_dir + "openttd.log"; } /** @@ -1267,28 +1263,27 @@ void SanitizeFilename(char *filename) * @return Pointer to new memory containing the loaded data, or \c nullptr if loading failed. * @note If \a maxsize less than the length of the file, loading fails. */ -void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize) +std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize) { - FILE *in = fopen(filename, "rb"); + FILE *in = fopen(filename.c_str(), "rb"); if (in == nullptr) return nullptr; + FileCloser fc(in); + fseek(in, 0, SEEK_END); size_t len = ftell(in); fseek(in, 0, SEEK_SET); - if (len > maxsize) { - fclose(in); - return nullptr; - } - byte *mem = MallocT(len + 1); - mem[len] = 0; - if (fread(mem, len, 1, in) != 1) { - fclose(in); - free(mem); - return nullptr; - } - fclose(in); + if (len > maxsize) return nullptr; - *lenp = len; + /* std::unique_ptr assumes new/delete unless a custom deleter is supplied. + * As we don't want to have to carry that deleter all over the place, use + * new directly to allocate the memory instead of malloc. */ + std::unique_ptr mem(static_cast(::operator new(len + 1))); + + mem.get()[len] = 0; + if (fread(mem.get(), len, 1, in) != 1) return nullptr; + + lenp = len; return mem; } @@ -1328,21 +1323,21 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s while ((dirent = readdir(dir)) != nullptr) { const char *d_name = FS2OTTD(dirent->d_name); - char filename[MAX_PATH]; if (!FiosIsValidFile(path, dirent, &sb)) continue; - seprintf(filename, lastof(filename), "%s%s", path, d_name); + std::string filename(path); + filename += d_name; if (S_ISDIR(sb.st_mode)) { /* Directory */ if (!recursive) continue; if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; - if (!AppendPathSeparator(filename, lastof(filename))) continue; - num += ScanPath(fs, extension, filename, basepath_length, recursive); + AppendPathSeparator(filename); + num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { /* File */ - if (MatchesExtension(extension, filename) && fs->AddFile(filename, basepath_length, nullptr)) num++; + if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, basepath_length, {})) num++; } } @@ -1360,9 +1355,9 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s static uint ScanTar(FileScanner *fs, const char *extension, TarFileList::iterator tar) { uint num = 0; - const char *filename = (*tar).first.c_str(); + const auto &filename = (*tar).first; - if (MatchesExtension(extension, filename) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++; + if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++; return num; } @@ -1381,7 +1376,6 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r this->subdir = sd; Searchpath sp; - char path[MAX_PATH]; TarFileList::iterator tar; uint num = 0; @@ -1389,8 +1383,8 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r /* Don't search in the working directory */ if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue; - FioAppendDirectory(path, lastof(path), sp, sd); - num += ScanPath(this, extension, path, strlen(path), recursive); + std::string path = FioGetDirectory(sp, sd); + num += ScanPath(this, extension, path.c_str(), path.size(), recursive); } if (tars && sd != NO_DIRECTORY) { @@ -1423,8 +1417,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r */ uint FileScanner::Scan(const char *extension, const char *directory, bool recursive) { - char path[MAX_PATH]; - strecpy(path, directory, lastof(path)); - if (!AppendPathSeparator(path, lastof(path))) return 0; - return ScanPath(this, extension, path, strlen(path), recursive); + std::string path(directory); + AppendPathSeparator(path); + return ScanPath(this, extension, path.c_str(), path.size(), recursive); } diff --git a/src/fileio_func.h b/src/fileio_func.h index 92f7cd3026..2c2a7e842b 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -12,6 +12,7 @@ #include "core/enum_type.hpp" #include "fileio_type.h" +#include void FioSeekTo(size_t pos, int mode); void FioSeekToFile(uint slot, size_t pos); @@ -21,50 +22,38 @@ byte FioReadByte(); uint16 FioReadWord(); uint32 FioReadDword(); void FioCloseAll(); -void FioOpenFile(uint slot, const char *filename, Subdirectory subdir, char **output_filename = nullptr); +void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir, std::string *output_filename = nullptr); void FioReadBlock(void *ptr, size_t size); void FioSkipBytes(int n); -/** - * The search paths OpenTTD could search through. - * At least one of the slots has to be filled with a path. - * nullptr paths tell that there is no such path for the - * current operating system. - */ -extern const char *_searchpaths[NUM_SEARCHPATHS]; - /** * Checks whether the given search path is a valid search path * @param sp the search path to check * @return true if the search path is valid */ -static inline bool IsValidSearchPath(Searchpath sp) -{ - return sp < NUM_SEARCHPATHS && _searchpaths[sp] != nullptr; -} +bool IsValidSearchPath(Searchpath sp); /** Iterator for all the search paths */ #define FOR_ALL_SEARCHPATHS(sp) for (sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) if (IsValidSearchPath(sp)) void FioFCloseFile(FILE *f); -FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr, char **output_filename = nullptr); -bool FioCheckFileExists(const char *filename, Subdirectory subdir); -char *FioGetFullPath(char *buf, const char *last, Searchpath sp, Subdirectory subdir, const char *filename); -char *FioFindFullPath(char *buf, const char *last, Subdirectory subdir, const char *filename); -char *FioAppendDirectory(char *buf, const char *last, Searchpath sp, Subdirectory subdir); -char *FioGetDirectory(char *buf, const char *last, Subdirectory subdir); -void FioCreateDirectory(const char *name); +FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr, std::string *output_filename = nullptr); +bool FioCheckFileExists(const std::string &filename, Subdirectory subdir); +std::string FioFindFullPath(Subdirectory subdir, const char *filename); +std::string FioGetDirectory(Searchpath sp, Subdirectory subdir); +std::string FioFindDirectory(Subdirectory subdir); +void FioCreateDirectory(const std::string &name); const char *FiosGetScreenshotDir(); void SanitizeFilename(char *filename); -bool AppendPathSeparator(char *buf, const char *last); +void AppendPathSeparator(std::string &buf); void DeterminePaths(const char *exe); -void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); -bool FileExists(const char *filename); -bool ExtractTar(const char *tar_filename, Subdirectory subdir); +std::unique_ptr ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize); +bool FileExists(const std::string &filename); +bool ExtractTar(const std::string &tar_filename, Subdirectory subdir); -extern const char *_personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. +extern std::string _personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. /** Helper for scanning for files with a given name */ class FileScanner { @@ -85,7 +74,7 @@ public: * @param tar_filename the name of the tar file the file is read from. * @return true if the file is added. */ - virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) = 0; + virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) = 0; }; /** Helper for scanning for files with tar as extension */ @@ -103,9 +92,9 @@ public: ALL = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything. }; - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = nullptr) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename = {}) override; - bool AddFile(Subdirectory sd, const char *filename); + bool AddFile(Subdirectory sd, const std::string &filename); /** Do the scan for Tars. */ static uint DoScan(TarScanner::Mode mode); diff --git a/src/fileio_type.h b/src/fileio_type.h index 15f886d050..14acf07971 100644 --- a/src/fileio_type.h +++ b/src/fileio_type.h @@ -128,10 +128,10 @@ enum Subdirectory { /** * Types of searchpaths OpenTTD might use */ -enum Searchpath { +enum Searchpath : unsigned { SP_FIRST_DIR, SP_WORKING_DIR = SP_FIRST_DIR, ///< Search in the working directory -#if defined(WITH_XDG_BASEDIR) && defined(WITH_PERSONAL_DIR) +#ifdef USE_XDG SP_PERSONAL_DIR_XDG, ///< Search in the personal directory from the XDG specification #endif SP_PERSONAL_DIR, ///< Search in the personal directory @@ -140,6 +140,8 @@ enum Searchpath { SP_INSTALLATION_DIR, ///< Search in the installation directory SP_APPLICATION_BUNDLE_DIR, ///< Search within the application bundle SP_AUTODOWNLOAD_DIR, ///< Search within the autodownload directory + SP_AUTODOWNLOAD_PERSONAL_DIR, ///< Search within the autodownload directory located in the personal directory + SP_AUTODOWNLOAD_PERSONAL_DIR_XDG, ///< Search within the autodownload directory located in the personal directory (XDG variant) NUM_SEARCHPATHS }; diff --git a/src/fios.cpp b/src/fios.cpp index 61f08d93a9..4586f86b33 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -19,6 +19,8 @@ #include "string_func.h" #include "tar_type.h" #include +#include +#include #ifndef _WIN32 # include @@ -29,8 +31,7 @@ #include "safeguards.h" /* Variables to display file lists */ -static char *_fios_path; -static const char *_fios_path_last; +static std::string *_fios_path = nullptr; SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */ @@ -41,7 +42,7 @@ extern void FiosGetDrives(FileList &file_list); extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot); /* get the name of an oldstyle savegame */ -extern void GetOldSaveGameName(const char *file, char *title, const char *last); +extern void GetOldSaveGameName(const std::string &file, char *title, const char *last); /** * Compare two FiosItem's. Used with sort when sorting the file list. @@ -138,7 +139,7 @@ const FiosItem *FileList::FindItem(const char *file) */ StringID FiosGetDescText(const char **path, uint64 *total_free) { - *path = _fios_path; + *path = _fios_path->c_str(); return FiosGetDiskFreeSpace(*path, total_free) ? STR_SAVELOAD_BYTES_FREE : STR_ERROR_UNABLE_TO_READ_DRIVE; } @@ -152,7 +153,8 @@ const char *FiosBrowseTo(const FiosItem *item) switch (item->type) { case FIOS_TYPE_DRIVE: #if defined(_WIN32) || defined(__OS2__) - seprintf(_fios_path, _fios_path_last, "%c:" PATHSEP, item->title[0]); + assert(_fios_path != nullptr); + *_fios_path = std::string{ item->title[0] } + ":" PATHSEP; #endif break; @@ -160,25 +162,28 @@ const char *FiosBrowseTo(const FiosItem *item) break; case FIOS_TYPE_PARENT: { - /* Check for possible nullptr ptr */ - char *s = strrchr(_fios_path, PATHSEPCHAR); - if (s != nullptr && s != _fios_path) { - s[0] = '\0'; // Remove last path separator character, so we can go up one level. + assert(_fios_path != nullptr); + auto s = _fios_path->find_last_of(PATHSEPCHAR); + if (s != std::string::npos && s != 0) { + _fios_path->erase(s); // Remove last path separator character, so we can go up one level. } - s = strrchr(_fios_path, PATHSEPCHAR); - if (s != nullptr) { - s[1] = '\0'; // go up a directory + + s = _fios_path->find_last_of(PATHSEPCHAR); + if (s != std::string::npos) { + _fios_path->erase(s + 1); // go up a directory } break; } case FIOS_TYPE_DIR: - strecat(_fios_path, item->name, _fios_path_last); - strecat(_fios_path, PATHSEP, _fios_path_last); + assert(_fios_path != nullptr); + *_fios_path += item->name; + *_fios_path += PATHSEP; break; case FIOS_TYPE_DIRECT: - seprintf(_fios_path, _fios_path_last, "%s", item->name); + assert(_fios_path != nullptr); + *_fios_path = item->name; break; case FIOS_TYPE_FILE: @@ -195,26 +200,26 @@ const char *FiosBrowseTo(const FiosItem *item) /** * Construct a filename from its components in destination buffer \a buf. - * @param buf Destination buffer. * @param path Directory path, may be \c nullptr. * @param name Filename. * @param ext Filename extension (use \c "" for no extension). - * @param last Last element of buffer \a buf. + * @return The completed filename. */ -static void FiosMakeFilename(char *buf, const char *path, const char *name, const char *ext, const char *last) +static std::string FiosMakeFilename(const std::string *path, const char *name, const char *ext) { + std::string buf; + if (path != nullptr) { - const char *buf_start = buf; - buf = strecpy(buf, path, last); + buf = *path; /* Remove trailing path separator, if present */ - if (buf > buf_start && buf[-1] == PATHSEPCHAR) buf--; + if (!buf.empty() && buf.back() == PATHSEPCHAR) buf.pop_back(); } /* Don't append the extension if it is already there */ const char *period = strrchr(name, '.'); if (period != nullptr && strcasecmp(period, ext) == 0) ext = ""; - seprintf(buf, last, PATHSEP "%s%s", name, ext); + return buf + PATHSEP + name + ext; } /** @@ -222,27 +227,26 @@ static void FiosMakeFilename(char *buf, const char *path, const char *name, cons * @param buf Destination buffer for saving the filename. * @param name Name of the file. * @param last Last element of buffer \a buf. + * @return The completed filename. */ -void FiosMakeSavegameName(char *buf, const char *name, const char *last) +std::string FiosMakeSavegameName(const char *name) { const char *extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav"; - FiosMakeFilename(buf, _fios_path, name, extension, last); + return FiosMakeFilename(_fios_path, name, extension); } /** * Construct a filename for a height map. - * @param buf Destination buffer. * @param name Filename. - * @param last Last element of buffer \a buf. + * @return The completed filename. */ -void FiosMakeHeightmapName(char *buf, const char *name, const char *last) +std::string FiosMakeHeightmapName(const char *name) { - char ext[5]; - ext[0] = '.'; - strecpy(ext + 1, GetCurrentScreenshotExtension(), lastof(ext)); + std::string ext("."); + ext += GetCurrentScreenshotExtension(); - FiosMakeFilename(buf, _fios_path, name, ext, last); + return FiosMakeFilename(_fios_path, name, ext.c_str()); } /** @@ -252,13 +256,11 @@ void FiosMakeHeightmapName(char *buf, const char *name, const char *last) */ bool FiosDelete(const char *name) { - char filename[512]; - - FiosMakeSavegameName(filename, name, lastof(filename)); - return unlink(filename) == 0; + std::string filename = FiosMakeSavegameName(name); + return unlink(filename.c_str()) == 0; } -typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const char *filename, const char *ext, char *title, const char *last); +typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const std::string &filename, const char *ext, char *title, const char *last); /** * Scanner to scan for a particular type of FIOS file. @@ -278,7 +280,7 @@ public: fop(fop), callback_proc(callback_proc), file_list(file_list) {} - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override; + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override; }; /** @@ -287,25 +289,26 @@ public: * @param basepath_length amount of characters to chop of before to get a relative filename * @return true if the file is added. */ -bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) +bool FiosFileScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) { - const char *ext = strrchr(filename, '.'); - if (ext == nullptr) return false; + auto sep = filename.rfind('.'); + if (sep == std::string::npos) return false; + std::string ext = filename.substr(sep); char fios_title[64]; fios_title[0] = '\0'; // reset the title; - FiosType type = this->callback_proc(this->fop, filename, ext, fios_title, lastof(fios_title)); + FiosType type = this->callback_proc(this->fop, filename, ext.c_str(), fios_title, lastof(fios_title)); if (type == FIOS_TYPE_INVALID) return false; for (const FiosItem *fios = file_list.Begin(); fios != file_list.End(); fios++) { - if (strcmp(fios->name, filename) == 0) return false; + if (filename == fios->name) return false; } FiosItem *fios = file_list.Append(); #ifdef _WIN32 // Retrieve the file modified date using GetFileTime rather than stat to work around an obscure MSVC bug that affects Windows XP - HANDLE fh = CreateFile(OTTD2FS(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + HANDLE fh = CreateFile(OTTD2FS(filename.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (fh != INVALID_HANDLE_VALUE) { FILETIME ft; @@ -324,7 +327,7 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons CloseHandle(fh); #else struct stat sb; - if (stat(filename, &sb) == 0) { + if (stat(filename.c_str(), &sb) == 0) { fios->mtime = sb.st_mtime; #endif } else { @@ -332,13 +335,13 @@ bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, cons } fios->type = type; - strecpy(fios->name, filename, lastof(fios->name)); + strecpy(fios->name, filename.c_str(), lastof(fios->name)); /* If the file doesn't have a title, use its filename */ const char *t = fios_title; if (StrEmpty(fios_title)) { - t = strrchr(filename, PATHSEPCHAR); - t = (t == nullptr) ? filename : (t + 1); + auto ps = filename.rfind(PATHSEPCHAR); + t = filename.c_str() + (ps == std::string::npos ? 0 : ps + 1); } strecpy(fios->title, t, lastof(fios->title)); str_validate(fios->title, lastof(fios->title)); @@ -365,8 +368,10 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c file_list.Clear(); + assert(_fios_path != nullptr); + /* A parent directory link exists if we are not in the root directory */ - if (!FiosIsRoot(_fios_path)) { + if (!FiosIsRoot(_fios_path->c_str())) { fios = file_list.Append(); fios->type = FIOS_TYPE_PARENT; fios->mtime = 0; @@ -375,12 +380,12 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c } /* Show subdirectories */ - if ((dir = ttd_opendir(_fios_path)) != nullptr) { + if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) { while ((dirent = readdir(dir)) != nullptr) { strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ - if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) && + if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) && (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) && strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) { fios = file_list.Append(); @@ -408,7 +413,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); if (subdir == NO_DIRECTORY) { - scanner.Scan(nullptr, _fios_path, false); + scanner.Scan(nullptr, _fios_path->c_str(), false); } else { scanner.Scan(nullptr, subdir, true, true); } @@ -429,11 +434,10 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c * @param last the last element in the title buffer * @param subdir the sub directory to search in */ -static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir) +static void GetFileTitle(const std::string &file, char *title, const char *last, Subdirectory subdir) { - char buf[MAX_PATH]; - strecpy(buf, file, lastof(buf)); - strecat(buf, ".title", lastof(buf)); + std::string buf = file; + buf += ".title"; FILE *f = FioFOpenFile(buf, "r", subdir); if (f == nullptr) return; @@ -456,7 +460,7 @@ static void GetFileTitle(const char *file, char *title, const char *last, Subdir * @see FiosGetFileList * @see FiosGetSavegameList */ -FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show savegame files * .SAV OpenTTD saved game @@ -491,17 +495,11 @@ FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, co */ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_save_path = nullptr; - static char *fios_save_path_last = nullptr; + static std::optional fios_save_path; - if (fios_save_path == nullptr) { - fios_save_path = MallocT(MAX_PATH); - fios_save_path_last = fios_save_path + MAX_PATH - 1; - FioGetDirectory(fios_save_path, fios_save_path_last, SAVE_DIR); - } + if (!fios_save_path) fios_save_path = FioFindDirectory(SAVE_DIR); - _fios_path = fios_save_path; - _fios_path_last = fios_save_path_last; + _fios_path = &(*fios_save_path); FiosGetFileList(fop, &FiosGetSavegameListCallback, NO_DIRECTORY, file_list); } @@ -517,7 +515,7 @@ void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list) * @see FiosGetFileList * @see FiosGetScenarioList */ -static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show scenario files * .SCN OpenTTD style scenario file @@ -546,27 +544,19 @@ static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *f */ void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_scn_path = nullptr; - static char *fios_scn_path_last = nullptr; + static std::optional fios_scn_path; /* Copy the default path on first run or on 'New Game' */ - if (fios_scn_path == nullptr) { - fios_scn_path = MallocT(MAX_PATH); - fios_scn_path_last = fios_scn_path + MAX_PATH - 1; - FioGetDirectory(fios_scn_path, fios_scn_path_last, SCENARIO_DIR); - } + if (!fios_scn_path) fios_scn_path = FioFindDirectory(SCENARIO_DIR); - _fios_path = fios_scn_path; - _fios_path_last = fios_scn_path_last; + _fios_path = &(*fios_scn_path); - char base_path[MAX_PATH]; - FioGetDirectory(base_path, lastof(base_path), SCENARIO_DIR); - - Subdirectory subdir = (fop == SLO_LOAD && strcmp(base_path, _fios_path) == 0) ? SCENARIO_DIR : NO_DIRECTORY; + std::string base_path = FioFindDirectory(SCENARIO_DIR); + Subdirectory subdir = (fop == SLO_LOAD && base_path == *_fios_path) ? SCENARIO_DIR : NO_DIRECTORY; FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list); } -static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last) +static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { /* Show heightmap files * .PNG PNG Based heightmap files @@ -593,10 +583,9 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char * bool match = false; Searchpath sp; FOR_ALL_SEARCHPATHS(sp) { - char buf[MAX_PATH]; - FioAppendDirectory(buf, lastof(buf), sp, HEIGHTMAP_DIR); + std::string buf = FioGetDirectory(sp, HEIGHTMAP_DIR); - if (strncmp(buf, it->second.tar_filename, strlen(buf)) == 0) { + if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) { match = true; break; } @@ -617,22 +606,14 @@ static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char * */ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) { - static char *fios_hmap_path = nullptr; - static char *fios_hmap_path_last = nullptr; + static std::optional fios_hmap_path; - if (fios_hmap_path == nullptr) { - fios_hmap_path = MallocT(MAX_PATH); - fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1; - FioGetDirectory(fios_hmap_path, fios_hmap_path_last, HEIGHTMAP_DIR); - } + if (!fios_hmap_path) fios_hmap_path = FioFindDirectory(HEIGHTMAP_DIR); - _fios_path = fios_hmap_path; - _fios_path_last = fios_hmap_path_last; + _fios_path = &(*fios_hmap_path); - char base_path[MAX_PATH]; - FioGetDirectory(base_path, lastof(base_path), HEIGHTMAP_DIR); - - Subdirectory subdir = strcmp(base_path, _fios_path) == 0 ? HEIGHTMAP_DIR : NO_DIRECTORY; + std::string base_path = FioFindDirectory(HEIGHTMAP_DIR); + Subdirectory subdir = base_path == *_fios_path ? HEIGHTMAP_DIR : NO_DIRECTORY; FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list); } @@ -642,14 +623,11 @@ void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list) */ const char *FiosGetScreenshotDir() { - static char *fios_screenshot_path = nullptr; + static std::optional fios_screenshot_path; - if (fios_screenshot_path == nullptr) { - fios_screenshot_path = MallocT(MAX_PATH); - FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1, SCREENSHOT_DIR); - } + if (!fios_screenshot_path) fios_screenshot_path = FioFindDirectory(SCREENSHOT_DIR); - return fios_screenshot_path; + return fios_screenshot_path->c_str(); } /** Basic data to distinguish a scenario. Used in the server list window */ @@ -691,7 +669,7 @@ public: this->scanned = true; } - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override { FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR); if (f == nullptr) return false; @@ -700,19 +678,16 @@ public: int fret = fscanf(f, "%u", &id.scenid); FioFCloseFile(f); if (fret != 1) return false; - strecpy(id.filename, filename, lastof(id.filename)); + strecpy(id.filename, filename.c_str(), lastof(id.filename)); Md5 checksum; uint8 buffer[1024]; - char basename[MAX_PATH]; ///< \a filename without the extension. size_t len, size; /* open the scenario file, but first get the name. * This is safe as we check on extension which * must always exist. */ - strecpy(basename, filename, lastof(basename)); - *strrchr(basename, '.') = '\0'; - f = FioFOpenFile(basename, "rb", SCENARIO_DIR, &size); + f = FioFOpenFile(filename.substr(0, filename.rfind('.')), "rb", SCENARIO_DIR, &size); if (f == nullptr) return false; /* calculate md5sum */ diff --git a/src/fios.h b/src/fios.h index 9aeaa5b961..39182e6087 100644 --- a/src/fios.h +++ b/src/fios.h @@ -227,9 +227,9 @@ const char *FiosBrowseTo(const FiosItem *item); StringID FiosGetDescText(const char **path, uint64 *total_free); bool FiosDelete(const char *name); -void FiosMakeHeightmapName(char *buf, const char *name, const char *last); -void FiosMakeSavegameName(char *buf, const char *name, const char *last); +std::string FiosMakeHeightmapName(const char *name); +std::string FiosMakeSavegameName(const char *name); -FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last); +FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); #endif /* FIOS_H */ diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 60a465fcde..6d3ebd2a25 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -373,22 +373,24 @@ public: /* Select the initial directory. */ o_dir.type = FIOS_TYPE_DIRECT; + std::string dir; switch (this->abstract_filetype) { case FT_SAVEGAME: - FioGetDirectory(o_dir.name, lastof(o_dir.name), SAVE_DIR); + dir = FioFindDirectory(SAVE_DIR); break; case FT_SCENARIO: - FioGetDirectory(o_dir.name, lastof(o_dir.name), SCENARIO_DIR); + dir = FioFindDirectory(SCENARIO_DIR); break; case FT_HEIGHTMAP: - FioGetDirectory(o_dir.name, lastof(o_dir.name), HEIGHTMAP_DIR); + dir = FioFindDirectory(HEIGHTMAP_DIR); break; default: - strecpy(o_dir.name, _personal_dir, lastof(o_dir.name)); + dir = _personal_dir; } + strecpy(o_dir.name, dir.c_str(), lastof(o_dir.name)); switch (this->fop) { case SLO_SAVE: @@ -785,7 +787,7 @@ public: } } else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked if (this->abstract_filetype == FT_SAVEGAME || this->abstract_filetype == FT_SCENARIO) { - FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); + _file_to_saveload.name = FiosMakeSavegameName(this->filename_editbox.text.buf); const bool known_id = _load_check_data.settings.game_creation.generation_unique_id != 0; const bool different_id = known_id && _load_check_data.settings.game_creation.generation_unique_id != _settings_game.game_creation.generation_unique_id; if (_settings_client.gui.savegame_overwrite_confirm >= 1 && different_id) { @@ -798,7 +800,7 @@ public: _switch_mode = SM_SAVE_GAME; } } else { - FiosMakeHeightmapName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name)); + _file_to_saveload.name = FiosMakeHeightmapName(this->filename_editbox.text.buf); if (_settings_client.gui.savegame_overwrite_confirm >= 1 && FioCheckFileExists(_file_to_saveload.name, Subdirectory::SAVE_DIR)) { ShowQuery(STR_SAVELOAD_OVERWRITE_TITLE, STR_SAVELOAD_OVERWRITE_WARNING, this, SaveLoadWindow::SaveHeightmapConfirmationCallback); } else { diff --git a/src/fontcache.cpp b/src/fontcache.cpp index ea5b255be8..a1acd2a631 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -567,8 +567,27 @@ static void LoadFreeTypeFont(FontSize fs) } FT_Face face = nullptr; + + /* If font is an absolute path to a ttf, try loading that first. */ FT_Error error = FT_New_Face(_library, settings->font, 0, &face); +#if defined(WITH_COCOA) + extern void MacOSRegisterExternalFont(const char *file_path); + if (error == FT_Err_Ok) MacOSRegisterExternalFont(settings->font); +#endif + + if (error != FT_Err_Ok) { + /* Check if font is a relative filename in one of our search-paths. */ + std::string full_font = FioFindFullPath(BASE_DIR, settings->font); + if (!full_font.empty()) { + error = FT_New_Face(_library, full_font.c_str(), 0, &face); +#if defined(WITH_COCOA) + if (error == FT_Err_Ok) MacOSRegisterExternalFont(full_font.c_str()); +#endif + } + } + + /* Try loading based on font face name (OS-wide fonts). */ if (error != FT_Err_Ok) error = GetFontByFaceName(settings->font, &face); if (error == FT_Err_Ok) { @@ -978,42 +997,55 @@ static void LoadWin32Font(FontSize fs) if (settings->os_handle != nullptr) { logfont = *(const LOGFONT *)settings->os_handle; - } else if (strchr(settings->font, '.') != nullptr && FileExists(settings->font)) { + } else if (strchr(settings->font, '.') != nullptr) { /* Might be a font file name, try load it. */ - TCHAR fontPath[MAX_PATH]; - convert_to_fs(settings->font, fontPath, lengthof(fontPath), false); - if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) { - /* Try a nice little undocumented function first for getting the internal font name. - * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */ - typedef BOOL(WINAPI * PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD); + TCHAR fontPath[MAX_PATH] = {}; + + /* See if this is an absolute path. */ + if (FileExists(settings->font)) { + convert_to_fs(settings->font, fontPath, lengthof(fontPath), false); + } else { + /* Scan the search-paths to see if it can be found. */ + std::string full_font = FioFindFullPath(BASE_DIR, settings->font); + if (!full_font.empty()) { + convert_to_fs(full_font.c_str(), fontPath, lengthof(fontPath), false); + } + } + + if (fontPath[0] != 0) { + if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) { + /* Try a nice little undocumented function first for getting the internal font name. + * Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */ + typedef BOOL(WINAPI * PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD); #ifdef UNICODE - static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoW"); + static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoW"); #else - static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoA"); + static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoA"); #endif - if (GetFontResourceInfo != nullptr) { - /* Try to query an array of LOGFONTs that describe the file. */ - DWORD len = 0; - if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) { - LOGFONT *buf = (LOGFONT *)AllocaM(byte, len); - if (GetFontResourceInfo(fontPath, &len, buf, 2)) { - logfont = *buf; // Just use first entry. + if (GetFontResourceInfo != nullptr) { + /* Try to query an array of LOGFONTs that describe the file. */ + DWORD len = 0; + if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) { + LOGFONT *buf = (LOGFONT *)AllocaM(byte, len); + if (GetFontResourceInfo(fontPath, &len, buf, 2)) { + logfont = *buf; // Just use first entry. + } } } - } - /* No dice yet. Use the file name as the font face name, hoping it matches. */ - if (logfont.lfFaceName[0] == 0) { - TCHAR fname[_MAX_FNAME]; - _tsplitpath(fontPath, nullptr, nullptr, fname, nullptr); + /* No dice yet. Use the file name as the font face name, hoping it matches. */ + if (logfont.lfFaceName[0] == 0) { + TCHAR fname[_MAX_FNAME]; + _tsplitpath(fontPath, nullptr, nullptr, fname, nullptr); - _tcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE); - logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr || strcasestr(settings->font, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. + _tcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE); + logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr || strcasestr(settings->font, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. + } + } else { + ShowInfoF("Unable to load file '%s' for %s font, using default windows font selection instead", settings->font, SIZE_TO_NAME[fs]); } - } else { - ShowInfoF("Unable to load file '%s' for %s font, using default windows font selection instead", settings->font, SIZE_TO_NAME[fs]); } } diff --git a/src/fontdetection.cpp b/src/fontdetection.cpp index 9cfc9f5540..1b1f9d689e 100644 --- a/src/fontdetection.cpp +++ b/src/fontdetection.cpp @@ -399,7 +399,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) * We instead query the list of all font descriptors that match the given name which * does not do this stupid name fallback. */ CFAutoRelease name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0)); - CFAutoRelease mandatory_attribs(CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontNameAttribute, 1, &kCFTypeSetCallBacks)); + CFAutoRelease mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast(reinterpret_cast(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks)); CFAutoRelease descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get())); /* Loop over all matches until we can get a path for one of them. */ @@ -441,13 +441,13 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8); lang_codes[1] = CFSTR("en"); CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks); - CFAutoRelease lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, (const void**)&kCTFontLanguagesAttribute, (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); + CFAutoRelease lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast(reinterpret_cast(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); CFAutoRelease lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get())); CFRelease(lang_arr); CFRelease(lang_codes[0]); /* Get array of all font descriptors for the wanted language. */ - CFAutoRelease mandatory_attribs(CFSetCreate(kCFAllocatorDefault, (const void **)&kCTFontLanguagesAttribute, 1, &kCFTypeSetCallBacks)); + CFAutoRelease mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast(reinterpret_cast(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks)); CFAutoRelease descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get())); bool result = false; diff --git a/src/game/game_text.cpp b/src/game/game_text.cpp index 39732f7898..24f41c93ac 100644 --- a/src/game/game_text.cpp +++ b/src/game/game_text.cpp @@ -66,7 +66,7 @@ void NORETURN CDECL strgen_fatal(const char *s, ...) LanguageStrings ReadRawLanguageStrings(const std::string &file) { size_t to_read; - FILE *fh = FioFOpenFile(file.c_str(), "rb", GAME_DIR, &to_read); + FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read); if (fh == nullptr) return LanguageStrings(); FileCloser fhClose(fh); @@ -206,7 +206,7 @@ public: this->FileScanner::Scan(".txt", directory, false); } - bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override + bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override { if (exclude == filename) return true; @@ -244,9 +244,9 @@ GameStrings *LoadTranslations() LanguageScanner scanner(gs, filename); std::string ldir = basename + "lang" PATHSEP; - const char *tar_filename = info->GetTarFile(); + const std::string tar_filename = info->GetTarFile(); TarList::iterator iter; - if (tar_filename != nullptr && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { + if (!tar_filename.empty() && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) { /* The main script is in a tar file, so find all files that * are in the same tar and add them to the langfile scanner. */ TarFileList::iterator tar; @@ -258,7 +258,7 @@ GameStrings *LoadTranslations() if (tar->first.size() <= ldir.size() || tar->first.compare(0, ldir.size(), ldir) != 0) continue; if (tar->first.compare(tar->first.size() - 4, 4, ".txt") != 0) continue; - scanner.AddFile(tar->first.c_str(), 0, tar_filename); + scanner.AddFile(tar->first, 0, tar_filename); } } else { /* Scan filesystem */ diff --git a/src/gamelog.cpp b/src/gamelog.cpp index 0e8d9aad9e..c30f7640fb 100644 --- a/src/gamelog.cpp +++ b/src/gamelog.cpp @@ -144,7 +144,7 @@ static const char * const la_text[] = { "emergency savegame", }; -assert_compile(lengthof(la_text) == GLAT_END); +static_assert(lengthof(la_text) == GLAT_END); /** * Information about the presence of a Grf at a certain point during gamelog history diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index 8fb4b1a7a8..7436be2125 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -330,7 +330,7 @@ static const StringID _num_towns[] = {STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_N static const StringID _num_inds[] = {STR_FUNDING_ONLY, STR_MINIMAL, STR_NUM_VERY_LOW, STR_NUM_LOW, STR_NUM_NORMAL, STR_NUM_HIGH, INVALID_STRING_ID}; static const StringID _variety[] = {STR_VARIETY_NONE, STR_VARIETY_VERY_LOW, STR_VARIETY_LOW, STR_VARIETY_MEDIUM, STR_VARIETY_HIGH, STR_VARIETY_VERY_HIGH, INVALID_STRING_ID}; -assert_compile(lengthof(_num_inds) == ID_END + 1); +static_assert(lengthof(_num_inds) == ID_END + 1); struct GenerateLandscapeWindow : public Window { uint widget_id; @@ -874,7 +874,7 @@ static void _ShowGenerateLandscape(GenerateLandscapeWindowMode mode) if (mode == GLWM_HEIGHTMAP) { /* If the function returns negative, it means there was a problem loading the heightmap */ - if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name, &x, &y)) return; + if (!GetHeightmapDimensions(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str(), &x, &y)) return; } WindowDesc *desc = (mode == GLWM_HEIGHTMAP) ? &_heightmap_load_desc : &_generate_landscape_desc; @@ -1222,7 +1222,7 @@ static const StringID _generation_class_table[] = { STR_GENERATION_PREPARING_SCRIPT, STR_GENERATION_PREPARING_GAME }; -assert_compile(lengthof(_generation_class_table) == GWP_CLASS_COUNT); +static_assert(lengthof(_generation_class_table) == GWP_CLASS_COUNT); static void AbortGeneratingWorldCallback(Window *w, bool confirmed) @@ -1324,7 +1324,7 @@ void ShowGenerateWorldProgress() static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uint total) { static const int percent_table[] = {0, 5, 14, 17, 20, 40, 60, 65, 80, 85, 95, 99, 100 }; - assert_compile(lengthof(percent_table) == GWP_CLASS_COUNT + 1); + static_assert(lengthof(percent_table) == GWP_CLASS_COUNT + 1); assert(cls < GWP_CLASS_COUNT); /* Do not run this function if we aren't in a thread */ diff --git a/src/gfx.cpp b/src/gfx.cpp index 84d165f43c..5712d65876 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1987,7 +1987,7 @@ void UpdateCursorSize() /* Ignore setting any cursor before the sprites are loaded. */ if (GetMaxSpriteID() == 0) return; - assert_compile(lengthof(_cursor.sprite_seq) == lengthof(_cursor.sprite_pos)); + static_assert(lengthof(_cursor.sprite_seq) == lengthof(_cursor.sprite_pos)); assert(_cursor.sprite_count <= lengthof(_cursor.sprite_seq)); for (uint i = 0; i < _cursor.sprite_count; ++i) { const Sprite *p = GetSprite(GB(_cursor.sprite_seq[i].sprite, 0, SPRITE_WIDTH), ST_NORMAL); diff --git a/src/gfx_type.h b/src/gfx_type.h index e07bd9ed53..54b08119cd 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -200,7 +200,7 @@ union Colour { } }; -assert_compile(sizeof(Colour) == sizeof(uint32)); +static_assert(sizeof(Colour) == sizeof(uint32)); /** Available font sizes */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index ed43004000..fa6508f68a 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -162,7 +162,7 @@ void CheckExternalFiles() if (sounds_set->GetNumInvalid() != 0) { add_pos += seprintf(add_pos, last, "Trying to load sound set '%s', but it is incomplete. The game will probably not run correctly until you properly install this set or select another one. See section 4.1 of README.md.\n\nThe following files are corrupted or missing:\n", sounds_set->name.c_str()); - assert_compile(SoundsSet::NUM_FILES == 1); + static_assert(SoundsSet::NUM_FILES == 1); /* No need to loop each file, as long as there is only a single * sound file. */ add_pos += seprintf(add_pos, last, "\t%s is %s (%s)\n", sounds_set->files->filename, SoundsSet::CheckMD5(sounds_set->files, BASESET_DIR) == MD5File::CR_MISMATCH ? "corrupt" : "missing", sounds_set->files->missing_warning); diff --git a/src/goal.cpp b/src/goal.cpp index 02ec85255f..954d2f7bf7 100644 --- a/src/goal.cpp +++ b/src/goal.cpp @@ -248,7 +248,7 @@ CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint CompanyID company = (CompanyID)GB(p1, 16, 8); ClientID client = (ClientID)GB(p1, 16, 16); - assert_compile(GOAL_QUESTION_BUTTON_COUNT < 29); + static_assert(GOAL_QUESTION_BUTTON_COUNT < 29); uint32 button_mask = GB(p2, 0, GOAL_QUESTION_BUTTON_COUNT); byte type = GB(p2, 29, 2); bool is_client = HasBit(p2, 31); diff --git a/src/goal_gui.cpp b/src/goal_gui.cpp index b7e44624fe..554ac56304 100644 --- a/src/goal_gui.cpp +++ b/src/goal_gui.cpp @@ -357,14 +357,13 @@ void ShowGoalsList(CompanyID company) /** Ask a question about a goal. */ struct GoalQuestionWindow : public Window { - char *question; ///< Question to ask (private copy). - int buttons; ///< Number of valid buttons in #button. - int button[3]; ///< Buttons to display. - byte type; ///< Type of question. + char *question; ///< Question to ask (private copy). + int buttons; ///< Number of valid buttons in #button. + int button[3]; ///< Buttons to display. + TextColour colour; ///< Colour of the question text. - GoalQuestionWindow(WindowDesc *desc, WindowNumber window_number, byte type, uint32 button_mask, const char *question) : Window(desc), type(type) + GoalQuestionWindow(WindowDesc *desc, WindowNumber window_number, TextColour colour, uint32 button_mask, const char *question) : Window(desc), colour(colour) { - assert(type < GOAL_QUESTION_TYPE_COUNT); this->question = stredup(question); /* Figure out which buttons we have to enable. */ @@ -391,10 +390,6 @@ struct GoalQuestionWindow : public Window { void SetStringParameters(int widget) const override { switch (widget) { - case WID_GQ_CAPTION: - SetDParam(0, STR_GOAL_QUESTION_CAPTION_QUESTION + this->type); - break; - case WID_GQ_BUTTON_1: SetDParam(0, STR_GOAL_QUESTION_BUTTON_CANCEL + this->button[0]); break; @@ -442,15 +437,15 @@ struct GoalQuestionWindow : public Window { if (widget != WID_GQ_QUESTION) return; SetDParamStr(0, this->question); - DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_HOR_CENTER); + DrawStringMultiLine(r.left, r.right, r.top, UINT16_MAX, STR_JUST_RAW_STRING, this->colour, SA_TOP | SA_HOR_CENTER); } }; /** Widgets of the goal question window. */ -static const NWidgetPart _nested_goal_question_widgets[] = { +static const NWidgetPart _nested_goal_question_widgets_question[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), - NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_GQ_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_GQ_CAPTION), SetDataTip(STR_GOAL_QUESTION_CAPTION_QUESTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE), NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), @@ -472,12 +467,107 @@ static const NWidgetPart _nested_goal_question_widgets[] = { EndContainer(), }; -static WindowDesc _goal_question_list_desc( - WDP_CENTER, nullptr, 0, 0, - WC_GOAL_QUESTION, WC_NONE, - WDF_CONSTRUCTION, - _nested_goal_question_widgets, lengthof(_nested_goal_question_widgets) -); +static const NWidgetPart _nested_goal_question_widgets_info[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE), + NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_GQ_CAPTION), SetDataTip(STR_GOAL_QUESTION_CAPTION_INFORMATION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 8), + EndContainer(), +}; + +static const NWidgetPart _nested_goal_question_widgets_warning[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_YELLOW), + NWidget(WWT_CAPTION, COLOUR_YELLOW, WID_GQ_CAPTION), SetDataTip(STR_GOAL_QUESTION_CAPTION_WARNING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_YELLOW), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 8), + EndContainer(), +}; + +static const NWidgetPart _nested_goal_question_widgets_error[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_RED), + NWidget(WWT_CAPTION, COLOUR_RED, WID_GQ_CAPTION), SetDataTip(STR_GOAL_QUESTION_CAPTION_ERROR, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_RED), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GQ_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_GQ_BUTTONS), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(65, 10, 65), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(25, 10, 25), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_1), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_2), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_GQ_BUTTON_3), SetDataTip(STR_BLACK_STRING, STR_NULL), SetFill(1, 0), + EndContainer(), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 8), + EndContainer(), +}; + +static WindowDesc _goal_question_list_desc[] = { + { + WDP_CENTER, nullptr, 0, 0, + WC_GOAL_QUESTION, WC_NONE, + WDF_CONSTRUCTION, + _nested_goal_question_widgets_question, lengthof(_nested_goal_question_widgets_question), + }, + { + WDP_CENTER, nullptr, 0, 0, + WC_GOAL_QUESTION, WC_NONE, + WDF_CONSTRUCTION, + _nested_goal_question_widgets_info, lengthof(_nested_goal_question_widgets_info), + }, + { + WDP_CENTER, nullptr, 0, 0, + WC_GOAL_QUESTION, WC_NONE, + WDF_CONSTRUCTION, + _nested_goal_question_widgets_warning, lengthof(_nested_goal_question_widgets_warning), + }, + { + WDP_CENTER, nullptr, 0, 0, + WC_GOAL_QUESTION, WC_NONE, + WDF_CONSTRUCTION, + _nested_goal_question_widgets_error, lengthof(_nested_goal_question_widgets_error), + }, +}; /** * Display a goal question. @@ -488,5 +578,6 @@ static WindowDesc _goal_question_list_desc( */ void ShowGoalQuestion(uint16 id, byte type, uint32 button_mask, const char *question) { - new GoalQuestionWindow(&_goal_question_list_desc, id, type, button_mask, question); + assert(type < GOAL_QUESTION_TYPE_COUNT); + new GoalQuestionWindow(&_goal_question_list_desc[type], id, type == 3 ? TC_WHITE : TC_BLACK, button_mask, question); } diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 960c4f69e0..2db7e2f09e 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -289,7 +289,7 @@ protected: /* the colours and cost array of GraphDrawer must accommodate * both values for cargo and companies. So if any are higher, quit */ - assert_compile(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES); + static_assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES); assert(this->num_vert_lines > 0); byte grid_colour = _colour_gradient[COLOUR_GREY][4]; @@ -1527,7 +1527,7 @@ static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index) STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP, }; - assert_compile(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN); + static_assert(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN); NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE); for (int widnum = WID_PRD_SCORE_FIRST; widnum <= WID_PRD_SCORE_LAST; widnum++) { diff --git a/src/ground_vehicle.cpp b/src/ground_vehicle.cpp index 0916f35d4a..d73e682276 100644 --- a/src/ground_vehicle.cpp +++ b/src/ground_vehicle.cpp @@ -301,8 +301,8 @@ bool GroundVehicle::IsChainInDepot() const { const T *v = this->First(); /* Is the front engine stationary in the depot? */ - assert_compile((int)TRANSPORT_RAIL == (int)VEH_TRAIN); - assert_compile((int)TRANSPORT_ROAD == (int)VEH_ROAD); + static_assert((int)TRANSPORT_RAIL == (int)VEH_TRAIN); + static_assert((int)TRANSPORT_ROAD == (int)VEH_ROAD); if (!IsDepotTypeTile(v->tile, (TransportType)Type) || v->cur_speed != 0) return false; /* Check whether the rest is also already trying to enter the depot. */ diff --git a/src/highscore.cpp b/src/highscore.cpp index d8fe348fe0..187df028bd 100644 --- a/src/highscore.cpp +++ b/src/highscore.cpp @@ -20,7 +20,7 @@ #include "safeguards.h" HighScore _highscore_table[SP_HIGHSCORE_END][5]; ///< various difficulty-settings; top 5 -char *_highscore_file; ///< The file to store the highscore data in. +std::string _highscore_file; ///< The file to store the highscore data in. static const StringID _endgame_perf_titles[] = { STR_HIGHSCORE_PERFORMANCE_TITLE_BUSINESSMAN, @@ -123,7 +123,7 @@ int8 SaveHighScoreValueNetwork() /** Save HighScore table to file */ void SaveToHighScore() { - FILE *fp = fopen(_highscore_file, "wb"); + FILE *fp = fopen(_highscore_file.c_str(), "wb"); if (fp != nullptr) { uint i; @@ -151,7 +151,7 @@ void SaveToHighScore() /** Initialize the highscore table to 0 and if any file exists, load in values */ void LoadFromHighScore() { - FILE *fp = fopen(_highscore_file, "rb"); + FILE *fp = fopen(_highscore_file.c_str(), "rb"); memset(_highscore_table, 0, sizeof(_highscore_table)); diff --git a/src/hotkeys.cpp b/src/hotkeys.cpp index 83a0ff9c6c..843e768ef8 100644 --- a/src/hotkeys.cpp +++ b/src/hotkeys.cpp @@ -16,7 +16,7 @@ #include "safeguards.h" -char *_hotkeys_file; +std::string _hotkeys_file; /** * List of all HotkeyLists. diff --git a/src/house.h b/src/house.h index 2b5431ea3c..8745fbb693 100644 --- a/src/house.h +++ b/src/house.h @@ -64,7 +64,7 @@ enum HouseZonesBits { HZB_TOWN_CENTRE, HZB_END, }; -assert_compile(HZB_END == 5); +static_assert(HZB_END == 5); DECLARE_POSTFIX_INCREMENT(HouseZonesBits) diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index c7dcab65cc..a6abcb5d2c 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -2682,8 +2682,7 @@ static int WhoCanServiceIndustry(Industry *ind) * We cannot check the first of shared orders only, since the first vehicle in such a chain * may have a different cargo type. */ - const Order *o; - FOR_VEHICLE_ORDERS(v, o) { + for (const Order *o : v->Orders()) { if (o->IsType(OT_GOTO_STATION) && !(o->GetUnloadType() & OUFB_TRANSFER)) { /* Vehicle visits a station to load or unload */ Station *st = Station::Get(o->GetDestination()); diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index c7abd48702..c84b307624 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -145,7 +145,7 @@ enum CargoSuffixInOut { template static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, const TC &cargoes, TS &suffixes) { - assert_compile(lengthof(cargoes) <= lengthof(suffixes)); + static_assert(lengthof(cargoes) <= lengthof(suffixes)); if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) { /* Reworked behaviour with new many-in-many-out scheme */ @@ -2201,8 +2201,8 @@ private: } }; -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); -assert_compile(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); +static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); +static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); int CargoesField::small_height; ///< Height of the header row. int CargoesField::normal_height; ///< Height of the non-header rows. diff --git a/src/infrastructure.cpp b/src/infrastructure.cpp index 0b048b5338..98bb04a077 100644 --- a/src/infrastructure.cpp +++ b/src/infrastructure.cpp @@ -258,8 +258,7 @@ bool CheckSharingChangePossible(VehicleType type) /* Check order list */ if (v->FirstShared() != v) continue; - Order *o; - FOR_VEHICLE_ORDERS(v, o) { + for(const Order *o : v->Orders()) { if (!OrderDestinationIsAllowed(o, v)) { error_message = STR_CONFIG_SETTING_SHARING_ORDERS_TO_OTHERS; } diff --git a/src/ini.cpp b/src/ini.cpp index fc9b1e8fd2..e70cc268aa 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -43,7 +43,7 @@ IniFile::IniFile(const char * const *list_group_names) : IniLoadFile(list_group_ * @param filename the file to save to. * @return true if saving succeeded. */ -bool IniFile::SaveToDisk(const char *filename) +bool IniFile::SaveToDisk(const std::string &filename) { /* * First write the configuration to a (temporary) file and then rename @@ -96,7 +96,7 @@ bool IniFile::SaveToDisk(const char *filename) # undef strncpy /* Allocate space for one more \0 character. */ TCHAR tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; - _tcsncpy(tfilename, OTTD2FS(filename), MAX_PATH); + _tcsncpy(tfilename, OTTD2FS(filename.c_str()), MAX_PATH); _tcsncpy(tfile_new, OTTD2FS(file_new.c_str()), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; @@ -113,8 +113,8 @@ bool IniFile::SaveToDisk(const char *filename) shfopt.pTo = tfilename; SHFileOperation(&shfopt); #else - if (rename(file_new.c_str(), filename) < 0) { - DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new.c_str(), filename); + if (rename(file_new.c_str(), filename.c_str()) < 0) { + DEBUG(misc, 0, "Renaming %s to %s failed; configuration not saved", file_new.c_str(), filename.c_str()); } #endif @@ -125,7 +125,7 @@ bool IniFile::SaveToDisk(const char *filename) return true; } -/* virtual */ FILE *IniFile::OpenFile(const char *filename, Subdirectory subdir, size_t *size) +/* virtual */ FILE *IniFile::OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) { /* Open the text file in binary mode to prevent end-of-line translations * done by ftell() and friends, as defined by K&R. */ diff --git a/src/ini_load.cpp b/src/ini_load.cpp index 15e947618a..08b2e587ca 100644 --- a/src/ini_load.cpp +++ b/src/ini_load.cpp @@ -192,7 +192,7 @@ void IniLoadFile::RemoveGroup(const char *name) * @param subdir the sub directory to load the file from. * @pre nothing has been loaded yet. */ -void IniLoadFile::LoadFromDisk(const char *filename, Subdirectory subdir, std::string *save) +void IniLoadFile::LoadFromDisk(const std::string &filename, Subdirectory subdir, std::string *save) { assert(this->last_group == &this->group); diff --git a/src/ini_type.h b/src/ini_type.h index 1cfe8e1202..e957a656ba 100644 --- a/src/ini_type.h +++ b/src/ini_type.h @@ -66,7 +66,7 @@ struct IniLoadFile { IniGroup *GetGroup(const std::string &name, bool create_new = true); void RemoveGroup(const char *name); - void LoadFromDisk(const char *filename, Subdirectory subdir, std::string *save = nullptr); + void LoadFromDisk(const std::string &filename, Subdirectory subdir, std::string *save = nullptr); /** * Open the INI file. @@ -75,7 +75,7 @@ struct IniLoadFile { * @param[out] size Size of the opened file. * @return File handle of the opened file, or \c nullptr. */ - virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size) = 0; + virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) = 0; /** * Report an error about the file contents. @@ -90,9 +90,9 @@ struct IniLoadFile { struct IniFile : IniLoadFile { IniFile(const char * const *list_group_names = nullptr); - bool SaveToDisk(const char *filename); + bool SaveToDisk(const std::string &filename); - virtual FILE *OpenFile(const char *filename, Subdirectory subdir, size_t *size); + virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size); virtual void ReportFileError(const char * const pre, const char * const buffer, const char * const post); }; diff --git a/src/landscape.cpp b/src/landscape.cpp index c0927d1b6b..e25bfecc1c 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -823,7 +823,7 @@ void RunTileLoop() 0xD8F, 0x1296, 0x2496, 0x4357, 0x8679, 0x1030E, 0x206CD, 0x403FE, 0x807B8, 0x1004B2, 0x2006A8, 0x4004B2, 0x800B87, 0x10004F3, 0x200072D, 0x40006AE, 0x80009E3, }; - assert_compile(lengthof(feedbacks) == MAX_MAP_TILES_BITS - 2 * MIN_MAP_SIZE_BITS + 1); + static_assert(lengthof(feedbacks) == MAX_MAP_TILES_BITS - 2 * MIN_MAP_SIZE_BITS + 1); const uint32 feedback = feedbacks[MapLogX() + MapLogY() - 2 * MIN_MAP_SIZE_BITS]; /* We update every tile every 256 ticks, so divide the map size by 2^8 = 256 */ @@ -1319,7 +1319,7 @@ void GenerateLandscape(byte mode) if (mode == GWM_HEIGHTMAP) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_HEIGHTMAP); - LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name); + LoadHeightmap(_file_to_saveload.detail_ftype, _file_to_saveload.name.c_str()); IncreaseGeneratingWorldProgress(GWP_LANDSCAPE); } else if (_settings_game.game_creation.land_generator == LG_TERRAGENESIS) { SetGeneratingWorldProgress(GWP_LANDSCAPE, steps + GLS_TERRAGENESIS); diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index ac865bbeca..496868c4a2 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -2504,7 +2504,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grootte: STR_OBJECT_CLASS_LTHS :Vuurtorings STR_OBJECT_CLASS_TRNS :Stuurders -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Boome STR_PLANT_TREE_TOOLTIP :{BLACK}Kies tipe boom om te plant. Indien die teel reeds 'n boom op het sal enige tipe bome by geplant word, ongeag van die gekose tipe STR_TREES_RANDOM_TYPE :{BLACK}Bome van lukraake tipe diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 700767ee7d..3c56a92e8d 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -2101,7 +2101,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}حجم: STR_OBJECT_CLASS_LTHS :مناراة ضوئية STR_OBJECT_CLASS_TRNS :النواقل -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}اشجار STR_PLANT_TREE_TOOLTIP :{BLACK} اختر نوع الشجر لزراعتة, اذا المربع يحتوي على اشجار فهذا الامر يضيف المزيد STR_TREES_RANDOM_TYPE :{BLACK}شجر عشوائي diff --git a/src/lang/basque.txt b/src/lang/basque.txt index 860360bc22..5a81e9c3de 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -2362,7 +2362,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamainua STR_OBJECT_CLASS_LTHS :Itsasargiak STR_OBJECT_CLASS_TRNS :Igorgailuak -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Zuhaitzak STR_PLANT_TREE_TOOLTIP :{BLACK} Aukeratu landatuko diren zuhaitz motak. Laukiak zuhaitza badauka mota ezberdinetako zuhaitz gehio geituko ditu STR_TREES_RANDOM_TYPE :{BLACK}Ausazko zuhaitz motak diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 5e20cf7e85..0f74f1fbf1 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -2830,7 +2830,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Паме STR_OBJECT_CLASS_LTHS :Маякi STR_OBJECT_CLASS_TRNS :Перадатчыкi -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Дрэвы STR_PLANT_TREE_TOOLTIP :{BLACK}Выберыце тып дрэваў для пасадкі. Калі на ўчастку ўжо ёсьць дрэвы, будуць дададзены некалькі дрэваў рознага тыпу, незалежна ад выбранага. STR_TREES_RANDOM_TYPE :{BLACK}Дрэвы розных відаў diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index a773be7164..7184971985 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -2514,7 +2514,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamanho: STR_OBJECT_CLASS_LTHS :Faróis STR_OBJECT_CLASS_TRNS :Transmissores -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Árvores STR_PLANT_TREE_TOOLTIP :{BLACK}Selecionar um tipo de árvore para plantar. Se o local já tiver uma árvore, isso irá adicionar mais árvores do tipo misto indepentendemente do tipo selecionado STR_TREES_RANDOM_TYPE :{BLACK}Árvores de tipo aleatório diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index f5d35267a1..769a480f21 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -2416,7 +2416,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Разм STR_OBJECT_CLASS_LTHS :Фарове STR_OBJECT_CLASS_TRNS :Предаватели -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Дървета STR_PLANT_TREE_TOOLTIP :{BLACK}Избор на вид дърво за засаждане. Ако на полето вече съществува дърво, ще бъдат добавени повече дървета от различни видове, независимо от избора на вид STR_TREES_RANDOM_TYPE :{BLACK}Дървета от произволен тип diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index c936ad106e..ef6543d4f9 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -316,8 +316,15 @@ STR_SORT_BY_CARGO_CAPACITY :Capacitat de c STR_SORT_BY_RANGE :Abast STR_SORT_BY_POPULATION :Població STR_SORT_BY_RATING :Qualificació +STR_SORT_BY_NUM_VEHICLES :Nombre de vehicles +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Benefici total de l'any passat +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Benefici total d'aquest any +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Benefici mitjà de l'any passat +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Benefici mitjà aquest any # Group by options for vehicle list +STR_GROUP_BY_NONE :Cap +STR_GROUP_BY_SHARED_ORDERS :Ordres compartides # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Posa en pausa o reprèn la partida @@ -774,6 +781,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Mostra t STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Mostra el darrer missatge o notícia STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * EN PAUSA * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * EN PAUSA (s'espera que s'actualitzi el graf de distribució) * * STR_STATUSBAR_AUTOSAVE :{RED}DESADA AUTOMÀTICA STR_STATUSBAR_SAVING_GAME :{RED}* * DESANT PARTIDA * * @@ -1613,6 +1621,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineal STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Disposició de nous arbres durant la partida: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Controla l'aparició aleatòria dels arbres durant una partida. Això podria afectar a les indústries que es basen en el creixement dels arbres, per exemple les serradores +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Creixen però no n'apareixen més {RED}(trenca el funcionament de les serradores) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Creixen però només n'apareixen més a la selva tropical +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Creixen i n'apareixen per tot arreu +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :No creixen ni n'apareixen més {RED}(trenca el funcionament les serradores) STR_CONFIG_SETTING_TOOLBAR_POS :Posició de la barra d'eines principal: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Posició horitzontal de la barra principal a la part superior de la pantalla @@ -1976,6 +1988,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Connecta STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Actualitza servidor STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Actualitza la informació del servidor +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Cerca a Internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Cerca servidors públics a Internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Cerca a la LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Cerca servidors a la xarxa local STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Afegeix un servidor STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Afegeix un servidor a la llista que sempre es comprovarà per buscar partides en marxa STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Inicia el servidor @@ -2201,11 +2217,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Partida encara STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Partida encara en pausa ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Partida encara en pausa ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :La partida encara està en pausa ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :La partida encara està en pausa ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Partida represa ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :nombre de jugadors STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connectant clients STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manual STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :script de la partida +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :s'està esperant que s'actualitzi el graf de distribució ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :deixant STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} s'ha unit a la partida @@ -2522,13 +2540,19 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Mida: {G STR_OBJECT_CLASS_LTHS :Fars STR_OBJECT_CLASS_TRNS :Transmissors -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbres STR_PLANT_TREE_TOOLTIP :{BLACK}Selecciona el tipus d'arbre a plantar. Si la casella ja conté un arbre, s'afegiran més arbres d'altres espècies independentment de quin estigui seleccionat STR_TREES_RANDOM_TYPE :{BLACK}Arbres de tipus aleatori STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Situar arbres de tipus aleatori. Shift commuta construeix/mostra el cost estimat STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Arbres Aleatoris STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Planta arbres aleatòriament al paisatge +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Planta un arbre a cada casella arrossegant el ratolí pel paisatge. +STR_TREES_MODE_FOREST_SM_BUTTON :Arbreda +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Planta petits boscos arrossegant el ratolí pel paisatge. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Bosc +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Planta grans boscos arrossegant el ratolí pel paisatge. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Generador de Terreny @@ -3158,10 +3182,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}Objectiu STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Clica sobre l'objectiu per centrar la vista principal sobre la indústria/població/cel·la. Ctrl+clic per obrir una nova vista sobre la indústria/població/cel·la # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Pregunta -STR_GOAL_QUESTION_CAPTION_INFORMATION :Informació -STR_GOAL_QUESTION_CAPTION_WARNING :Alerta -STR_GOAL_QUESTION_CAPTION_ERROR :Error +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}Pregunta +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}Informació +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}Avís +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}Error ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel·la @@ -4240,6 +4264,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :La partida est STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :No es pot llegir l'arxiu STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :No es pot escriure a l'arxiu STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :El test d'integritat de dades ha fallat +STR_GAME_SAVELOAD_ERROR_PATCHPACK :La desada es va fer amb una versió modificada. STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}La partida es va desar amb una versió sense suport de tramvies. S'han eliminat tots els tramvies diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 3cef9c793e..545da39068 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -2609,7 +2609,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Veličin STR_OBJECT_CLASS_LTHS :Svjetionici STR_OBJECT_CLASS_TRNS :Odašiljači -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Drveće STR_PLANT_TREE_TOOLTIP :{BLACK}Odaberi vrstu drveta za sadnju. Ako polje već ima drvo, ovo će dodati još drveća raznih vrsta neovisno o odabranoj vrsti STR_TREES_RANDOM_TYPE :{BLACK}Raznovrsno drveće diff --git a/src/lang/czech.txt b/src/lang/czech.txt index 068bfb40f0..9832b43769 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -3130,7 +3130,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Velikost STR_OBJECT_CLASS_LTHS :Majáky STR_OBJECT_CLASS_TRNS :Vysílače -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Stromy STR_PLANT_TREE_TOOLTIP :{BLACK}Zvol druh stromu na vysazení. Pokud se na políčku už nějaký strom nachází, přidá se k němu několik různých druhů bez ohledu na výběr druhu STR_TREES_RANDOM_TYPE :{BLACK}Různé stromy diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 35b0e2ec44..d3616cd3cf 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -2514,7 +2514,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Størrel STR_OBJECT_CLASS_LTHS :Fyrtårn STR_OBJECT_CLASS_TRNS :Sendere -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Træer STR_PLANT_TREE_TOOLTIP :{BLACK}Vælg typen af træer der skal plantes. Hvis feltet allerede har et træ, vil dette tilføje flere træer i blandede typer, uafhængigt af den valgte type STR_TREES_RANDOM_TYPE :{BLACK}Træer af tilfældig type diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index 6fa514bf80..8f074405e4 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -2513,7 +2513,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grootte: STR_OBJECT_CLASS_LTHS :Vuurtorens STR_OBJECT_CLASS_TRNS :Zendmasten -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Bomen STR_PLANT_TREE_TOOLTIP :{BLACK}Kies een soort boom om te planten. Als de tegel al bomen bevat, komen er meer bomen van verschillende typen bij, onafhankelijk van het geselecteerde type. STR_TREES_RANDOM_TYPE :{BLACK}Willekeurige soorten bomen diff --git a/src/lang/english.txt b/src/lang/english.txt index e1eb804224..0cb24e5754 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3216,7 +3216,7 @@ STR_BASIC_HOUSE_SET_NAME :Basic houses STR_SELECT_TOWN_CAPTION :{WHITE}Select town STR_SELECT_TOWN_LIST_ITEM :{BLACK}{TOWN} -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type @@ -3225,6 +3225,12 @@ STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Random T STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plant trees randomly throughout the landscape STR_TREES_REMOVE_TREES_BUTTON :{BLACK}Remove all Trees STR_TREES_REMOVE_TREES_TOOLTIP :{BLACK}Remove all Trees over landscape +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Plant single trees by dragging over the landscape. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Grove +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Plant small forests by dragging over the landscape. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Forest +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Plant large forests by dragging over the landscape. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Land Generation @@ -3881,10 +3887,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}Company STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on goal to centre main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Question -STR_GOAL_QUESTION_CAPTION_INFORMATION :Information -STR_GOAL_QUESTION_CAPTION_WARNING :Warning -STR_GOAL_QUESTION_CAPTION_ERROR :Error +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}Question +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}Information +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}Warning +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}Error ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Cancel diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index 160a5eab0c..fa785b6396 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -2425,7 +2425,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index 455d29bb2d..385d387308 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -2509,7 +2509,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Size: {G STR_OBJECT_CLASS_LTHS :Lighthouses STR_OBJECT_CLASS_TRNS :Transmitters -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trees STR_PLANT_TREE_TOOLTIP :{BLACK}Select tree type to plant. If the tile already has a tree, this will add more trees of mixed types independent of the selected type STR_TREES_RANDOM_TYPE :{BLACK}Trees of random type diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index b191f01b20..f883e6a033 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -2059,7 +2059,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Grandeco STR_OBJECT_CLASS_LTHS :Lumturoj STR_OBJECT_CLASS_TRNS :Transigantoj -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arboj STR_PLANT_TREE_TOOLTIP :{BLACK}Elektu arbo-tipon por planti. Kiam la regiono jam havas arbojn, aliaj arb-tipoj plantiĝos STR_TREES_RANDOM_TYPE :{BLACK}Arboj de hazardaj tipoj diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index 735eaab658..0ffc4e9464 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -2523,7 +2523,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Suurus: STR_OBJECT_CLASS_LTHS :Majakad STR_OBJECT_CLASS_TRNS :Saatejaamad -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Puud STR_PLANT_TREE_TOOLTIP :{BLACK}Vali istutatava puu liik. Kui ruudus juba on puu, siis lisatakse rohkem eri liikide puid, olenemata valikust STR_TREES_RANDOM_TYPE :{BLACK}Suvalised puutüübid diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 57ba337a1f..08bd58aabb 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -2205,7 +2205,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Stødd: STR_OBJECT_CLASS_LTHS :Vitar STR_OBJECT_CLASS_TRNS :Sendarir -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Trø STR_TREES_RANDOM_TYPE :{BLACK}Tilvildarlig træ sløg STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Tilvildarlig trø diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 9fa844e9df..7ba6cb43c8 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -59,37 +59,37 @@ STR_CARGO_PLURAL_FIZZY_DRINKS :Sihijuomaa # Singular cargo name STR_CARGO_SINGULAR_NOTHING : -STR_CARGO_SINGULAR_PASSENGER :Matkustaja -STR_CARGO_SINGULAR_COAL :Kivihiili -STR_CARGO_SINGULAR_MAIL :Posti -STR_CARGO_SINGULAR_OIL :Öljy -STR_CARGO_SINGULAR_LIVESTOCK :Karja -STR_CARGO_SINGULAR_GOODS :Tavara -STR_CARGO_SINGULAR_GRAIN :Vilja -STR_CARGO_SINGULAR_WOOD :Raakapuu -STR_CARGO_SINGULAR_IRON_ORE :Rautamalmi -STR_CARGO_SINGULAR_STEEL :Teräs -STR_CARGO_SINGULAR_VALUABLES :Arvotavara -STR_CARGO_SINGULAR_COPPER_ORE :Kuparimalmi -STR_CARGO_SINGULAR_MAIZE :Maissi -STR_CARGO_SINGULAR_FRUIT :Hedelmä -STR_CARGO_SINGULAR_DIAMOND :Jalokivi -STR_CARGO_SINGULAR_FOOD :Ruoka -STR_CARGO_SINGULAR_PAPER :Paperi -STR_CARGO_SINGULAR_GOLD :Kulta -STR_CARGO_SINGULAR_WATER :Vesi -STR_CARGO_SINGULAR_WHEAT :Vehnä -STR_CARGO_SINGULAR_RUBBER :Kumi -STR_CARGO_SINGULAR_SUGAR :Sokeri -STR_CARGO_SINGULAR_TOY :Lelu -STR_CARGO_SINGULAR_SWEETS :Karkki -STR_CARGO_SINGULAR_COLA :Limsa -STR_CARGO_SINGULAR_CANDYFLOSS :Hattara -STR_CARGO_SINGULAR_BUBBLE :Kupla -STR_CARGO_SINGULAR_TOFFEE :Toffee -STR_CARGO_SINGULAR_BATTERY :Paristo -STR_CARGO_SINGULAR_PLASTIC :Muovi -STR_CARGO_SINGULAR_FIZZY_DRINK :Sihijuoma +STR_CARGO_SINGULAR_PASSENGER :matkustaja +STR_CARGO_SINGULAR_COAL :kivihiili +STR_CARGO_SINGULAR_MAIL :posti +STR_CARGO_SINGULAR_OIL :öljy +STR_CARGO_SINGULAR_LIVESTOCK :karja +STR_CARGO_SINGULAR_GOODS :tavara +STR_CARGO_SINGULAR_GRAIN :vilja +STR_CARGO_SINGULAR_WOOD :raakapuu +STR_CARGO_SINGULAR_IRON_ORE :rautamalmi +STR_CARGO_SINGULAR_STEEL :teräs +STR_CARGO_SINGULAR_VALUABLES :arvotavara +STR_CARGO_SINGULAR_COPPER_ORE :kuparimalmi +STR_CARGO_SINGULAR_MAIZE :maissi +STR_CARGO_SINGULAR_FRUIT :hedelmä +STR_CARGO_SINGULAR_DIAMOND :timantti +STR_CARGO_SINGULAR_FOOD :ruoka +STR_CARGO_SINGULAR_PAPER :paperi +STR_CARGO_SINGULAR_GOLD :kulta +STR_CARGO_SINGULAR_WATER :vesi +STR_CARGO_SINGULAR_WHEAT :vehnä +STR_CARGO_SINGULAR_RUBBER :kumi +STR_CARGO_SINGULAR_SUGAR :sokeri +STR_CARGO_SINGULAR_TOY :lelu +STR_CARGO_SINGULAR_SWEETS :karkki +STR_CARGO_SINGULAR_COLA :limsa +STR_CARGO_SINGULAR_CANDYFLOSS :hattara +STR_CARGO_SINGULAR_BUBBLE :kupla +STR_CARGO_SINGULAR_TOFFEE :toffee +STR_CARGO_SINGULAR_BATTERY :paristo +STR_CARGO_SINGULAR_PLASTIC :muovi +STR_CARGO_SINGULAR_FIZZY_DRINK :sihijuoma # Quantity of cargo STR_QUANTITY_NOTHING : @@ -688,10 +688,10 @@ STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLA STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}Soittolista – ”{STRING}” STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}Tyhjennä STR_PLAYLIST_CHANGE_SET :{BLACK}Vaihda kokoelma -STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Tyhjennä nykyinen soittolista (vain Oma1 tai Oma2) +STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}Tyhjennä nykyinen soittolista (vain oma{NBSP}1 tai oma{NBSP}2) STR_PLAYLIST_TOOLTIP_CHANGE_SET :{BLACK}Valitse toinen asennettu kokoelma musiikkivalikoimaksesi -STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Valitse musiikkiraita lisätäksesi sen nykyiseen soittolistaan (vain Oma1 tai Oma2). -STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Poista musiikkiraita nykyseiltä soittolistalta napsauttamalla (ainoastaan Custom1 tai Custom2) +STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}Valitse musiikkiraita lisätäksesi sen nykyiseen soittolistaan (vain oma{NBSP}1 tai oma{NBSP}2). +STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}Poista musiikkiraita nykyiseltä soittolistalta napsauttamalla (vain oma{NBSP}1 tai oma{NBSP}2) # Highscore window STR_HIGHSCORE_TOP_COMPANIES_WHO_REACHED :{BIG_FONT}{BLACK}Parhaat yhtiöt, jotka saavuttivat vuoden {NUM} @@ -2539,13 +2539,19 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Koko: {G STR_OBJECT_CLASS_LTHS :Majakat STR_OBJECT_CLASS_TRNS :Lähettimet -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Puita STR_PLANT_TREE_TOOLTIP :{BLACK}Valitse istutettava puutyyppi. Jos ruudussa on jo puu, tämä lisää uusia puita riippumatta valitun puun tyypistä STR_TREES_RANDOM_TYPE :{BLACK}Sattumanvaraisia puita STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Aseta sattumanvaraisia puita. Shift vaihtaa istutustilan ja kustannusarvion välillä STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Satunnaisia puita. STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Istuta puita satunnaisesti maastoon +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Tavallinen +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Istuta yksittäisiä puita vetämällä. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Metsikkö +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Istuta pieniä metsiä vetämällä. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Metsä +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Istuta isoja metsiä vetämällä. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Maanrakennus @@ -3175,10 +3181,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}Yhtiön STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Keskitä päänäkymä laitokseen/kuntaan/ruutuun napsauttamalla tavoitetta. Ctrl+Klik avaa uuden näkymän laitoksen/kunnan/ruudun sijaintiin # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Kysymys -STR_GOAL_QUESTION_CAPTION_INFORMATION :Tietoa -STR_GOAL_QUESTION_CAPTION_WARNING :Varoitus -STR_GOAL_QUESTION_CAPTION_ERROR :Virhe +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}Kysymys +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}Tietoa +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}Varoitus +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}Virhe ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Peruuta @@ -3252,7 +3258,7 @@ STR_STATION_VIEW_RATINGS_TOOLTIP :{BLACK}Näytä STR_STATION_VIEW_SUPPLY_RATINGS_TITLE :{BLACK}Kuukausittainen tarjonta ja paikallinen arvio: STR_STATION_VIEW_CARGO_SUPPLY_RATING :{WHITE}{STRING}: {YELLOW}{COMMA} / {STRING} ({COMMA}{NBSP}%) -STR_STATION_VIEW_GROUP :{BLACK}Järjestä +STR_STATION_VIEW_GROUP :{BLACK}Ryhmittele STR_STATION_VIEW_WAITING_STATION :Asema: Odottaa STR_STATION_VIEW_WAITING_AMOUNT :Määrä: Odottaa STR_STATION_VIEW_PLANNED_STATION :Asema: Suunniteltu @@ -3685,11 +3691,11 @@ STR_ENGINE_PREVIEW_ELRAIL_LOCOMOTIVE :sähköradan ve STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :yksiraiteisen veturi STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :Maglev-veturi -STR_ENGINE_PREVIEW_ROAD_VEHICLE :ajoneuvon -STR_ENGINE_PREVIEW_TRAM_VEHICLE :raitiovaunun +STR_ENGINE_PREVIEW_ROAD_VEHICLE :ajoneuvo +STR_ENGINE_PREVIEW_TRAM_VEHICLE :raitiovaunu -STR_ENGINE_PREVIEW_AIRCRAFT :ilma-aluksen -STR_ENGINE_PREVIEW_SHIP :laivan +STR_ENGINE_PREVIEW_AIRCRAFT :ilma-alus +STR_ENGINE_PREVIEW_SHIP :laiva STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER :{BLACK}Hinta: {CURRENCY_LONG} Paino: {WEIGHT_SHORT}{}Nopeus: {VELOCITY} Teho: {POWER}{}Käyttökustannukset: {CURRENCY_LONG}/vuosi{}Kapasiteetti: {CARGO_LONG} STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE :{BLACK}Hinta: {CURRENCY_LONG} Paino: {WEIGHT_SHORT}{}Nopeus: {VELOCITY} Teho: {POWER} Maks. vetovoima: {6:FORCE}{}Käyttökustannukset: {4:CURRENCY_LONG}/v{}Kapasiteetti: {5:CARGO_LONG} @@ -3894,7 +3900,7 @@ STR_REFIT_SHIP_LIST_TOOLTIP :{BLACK}Valitse STR_REFIT_AIRCRAFT_LIST_TOOLTIP :{BLACK}Valitse kuljetettavan rahdin tyyppi STR_REFIT_TRAIN_REFIT_BUTTON :{BLACK}Sovita juna -STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Korjaa ajoneuvo. +STR_REFIT_ROAD_VEHICLE_REFIT_BUTTON :{BLACK}Sovita ajoneuvo STR_REFIT_SHIP_REFIT_BUTTON :{BLACK}Sovita laiva STR_REFIT_AIRCRAFT_REFIT_BUTTON :{BLACK}Sovita ilma-alus @@ -4561,7 +4567,7 @@ STR_ERROR_SHIP_IN_THE_WAY :{WHITE}Laiva on STR_ERROR_AIRCRAFT_IN_THE_WAY :{WHITE}Ilma-alus on tiellä STR_ERROR_CAN_T_REFIT_TRAIN :{WHITE}Junaa ei voi sovittaa... -STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Ajoneuvoa ei voida korjata. +STR_ERROR_CAN_T_REFIT_ROAD_VEHICLE :{WHITE}Ajoneuvoa ei voi sovittaa… STR_ERROR_CAN_T_REFIT_SHIP :{WHITE}Laivaa ei voi sovittaa... STR_ERROR_CAN_T_REFIT_AIRCRAFT :{WHITE}Ilma-alusta ei voi sovittaa... @@ -4724,7 +4730,7 @@ STR_INDUSTRY_NAME_FOOD_PROCESSING_PLANT :Ruoanjalostamo STR_INDUSTRY_NAME_PAPER_MILL :Paperitehdas STR_INDUSTRY_NAME_GOLD_MINE :Kultakaivos STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :Pankki -STR_INDUSTRY_NAME_DIAMOND_MINE :Jalokivikaivos +STR_INDUSTRY_NAME_DIAMOND_MINE :Timanttikaivos STR_INDUSTRY_NAME_IRON_ORE_MINE :Rautakaivos STR_INDUSTRY_NAME_FRUIT_PLANTATION :Hedelmäviljelmä STR_INDUSTRY_NAME_RUBBER_PLANTATION :Kumiviljelmä diff --git a/src/lang/french.txt b/src/lang/french.txt index a8be76554d..d9a3607726 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -316,8 +316,15 @@ STR_SORT_BY_CARGO_CAPACITY :Capacité STR_SORT_BY_RANGE :Rayon d'action STR_SORT_BY_POPULATION :Population STR_SORT_BY_RATING :Qualité de service +STR_SORT_BY_NUM_VEHICLES :Nombre de véhicules +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Profit total l'année précédente +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Profit total cette année +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Profit moyen l'année précédente +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Profit moyen cette année # Group by options for vehicle list +STR_GROUP_BY_NONE :Aucun +STR_GROUP_BY_SHARED_ORDERS :Ordres partagés # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Mettre le jeu en pause @@ -774,6 +781,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Afficher STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Afficher le dernier message ou bulletin STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * SUSPENDU * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * SUSPENDU (en attente du recalcul des liens du graphique) * * STR_STATUSBAR_AUTOSAVE :{RED}ENREGISTREMENT AUTOMATIQUE STR_STATUSBAR_SAVING_GAME :{RED}* * SAUVEGARDE EN COURS * * @@ -1613,6 +1621,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Linéaire STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Plantation d'arbres durant la partie{NBSP}: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Contrôle l'apparition aléatoire des arbres durant la partie. Cela peut affecter les industries qui dépendent de la croissance des arbres, par exemple les scieries +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Croissance sans propagation {RED}(casse les scieries) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Croissance mais propagation uniquement dans les régions tropicales +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Croissance et propagation partout +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :Pas de croissance, pas de propagation {RED}(casse les scieries) STR_CONFIG_SETTING_TOOLBAR_POS :Position de la barre d'outils principale{NBSP}: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Position horizontale de la barre d'outils principale en haut de l'écran @@ -1650,10 +1662,10 @@ STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :Aucune STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Multiplicateur initial pour la taille des métropoles{NBSP}: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Taille moyenne des métropoles par rapport aux villes normales au début de la partie -STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Réactualiser le graphique de la distribution tous les {STRING}{NBSP}jour{P 0:2 "" s} -STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Intervalle entre la recalculation des liens du graphique. À chaque itération, une seule composante du graphique est recalculée. Donc, une valeur X pour ce réglage ne signifie pas que le graphique est réactualisé entièrement tous les X jours. Plus l'intervalle est court, plus de temps CPU est nécessaire pour la recalculation. Plus il est long, et plus de temps sera nécessaire pour que la distribution s'effectue sur de nouvelles routes. +STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Recalculer le graphe de distribution tous les {STRING}{NBSP}jour{P 0:2 "" s} +STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Intervalle entre le recalcul du graphe de distribution. À chaque itération, une seule composante du graphe est recalculée. Donc, une valeur X pour ce réglage ne signifie pas que le graphe est réactualisé entièrement tous les X jours. Plus l'intervalle est court, plus de temps CPU est nécessaire pour la recalcul. Plus il est long, et plus de temps sera nécessaire pour que la distribution s'effectue sur de nouvelles routes. STR_CONFIG_SETTING_LINKGRAPH_TIME :Prendre {STRING}{NBSP}jour{P 0:2 "" s} pour recalculer le graphe de distribution -STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Durée maximale (en jours) de la réactualisation d'une composante du graphique. À chaque itération, un thread est initié, qui a une durée maximale définie par ce réglage. Plus celui-ci est court, plus la probabilité que le thread ne termine pas sa tâche à temps est élevée. Le jeu s'interrompt alors jusqu'à la fin de la recalculation ("lag"). Plus le réglage est long, et moins rapidement la distribution sera réactualisée en cas de changement de routes. +STR_CONFIG_SETTING_LINKGRAPH_TIME_HELPTEXT :Durée maximale (en jours) du recalcul d'une composante du graphe. À chaque itération, un thread est initié, qui a une durée maximale définie par ce réglage. Plus celui-ci est court, plus la probabilité que le thread ne termine pas sa tâche à temps est élevée. Le jeu s'interrompt alors jusqu'à la fin du recalcul ("lag"). Plus le réglage est long, et moins rapidement la distribution sera réactualisée en cas de changement de routes. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manuel STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asymétrique STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :symétrique @@ -1666,7 +1678,7 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :La classe de ca STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Type de distribution pour les autres classes de cargaison{NBSP}: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asymétrique" signifie qu'une quantité arbitraire de cargaison peut être envoyée dans les deux directions. "manuel" signifie qu'aucune distribution n'est mise en place pour la cargaison. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Précision de la distribution{NBSP}: {STRING} -STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Plus ce réglage est élevé, plus la réactualisation du graphique de distribution occupe de temps CPU. S'il est trop élevé, cela peut produire de la latence ("lag"). Au contraire, plus la valeur est basse, plus la distribution sera imprécise et l'on risque de voir des cargaisons ne pas aller vers la destination attendue. +STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Plus ce réglage est élevé, plus le recalcul du graphe de distribution occupe de temps CPU. S'il est trop élevé, cela peut produire de la latence ("lag"). Au contraire, plus la valeur est basse, plus la distribution sera imprécise et l'on risque de voir des cargaisons ne pas aller vers la destination attendue. STR_CONFIG_SETTING_DEMAND_DISTANCE :Effet de la distance sur la demande{NBSP}: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Si cette valeur est supérieure à 0, la distance entre la station d'origine A d'une cargaison et une possible destination B a un impact sur la quantité de cargaison envoyée de A vers B. Plus la distance est grande entre les deux, moins de cargaison sera envoyée. Plus cette valeur est élevée, moins de cargaison sera envoyée vers des stations lointaines, et plus vers les stations plus proches. STR_CONFIG_SETTING_DEMAND_SIZE :Quantité de cargaison renvoyée en mode symétrique{NBSP}: {STRING} @@ -1976,6 +1988,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Rejoindr STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Actualiser STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Actualiser les informations sur le serveur +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Recherche internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Rechercher des serveurs publiés sur internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Recherche LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Rechercher des serveurs sur le réseau local STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Ajouter un serveur STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Ajouter un serveur à la liste de ceux parmi lesquels des parties en cours seront toujours cherchées STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Démarrer le serveur @@ -2201,11 +2217,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Partie toujours STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Partie toujours suspendue ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Partie toujours suspendue ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Partie toujours suspendue ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :Partie toujours suspendue ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Reprise de la partie ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :nombre de joueurs STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :connexion de clients STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manuel STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :script de jeu +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :en attente du recalcul du graphe de liens ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :départ STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} a rejoint la partie @@ -2522,13 +2540,19 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Taille{N STR_OBJECT_CLASS_LTHS :Phares STR_OBJECT_CLASS_TRNS :Transmetteurs -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbres STR_PLANT_TREE_TOOLTIP :{BLACK}Choix du type d'arbre. S'il y a déjà un arbre dans la case, plusieurs arbres de types différents y seront ajoutés, indépendamment du type sélectionné. STR_TREES_RANDOM_TYPE :{BLACK}Au hasard STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Planter des arbres provenant d'espèces choisies au hasard.{}Shift pour afficher seulement le coût estimé. STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Ajouter des arbres au hasard STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Semer des arbres au hasard sur l'ensemble du terrain +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Planter de simples arbres en glissant sur le terrain +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Bosquet +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}Planter de petites forêts en glissant sur le terrain +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Forêt +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Planter de larges forêts en glissant sur le terrain # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Création du terrain @@ -2761,7 +2785,7 @@ STR_FRAMERATE_GL_ROADVEHS :{WHITE} Ticks STR_FRAMERATE_GL_SHIPS :{BLACK} Ticks des navires{NBSP}: STR_FRAMERATE_GL_AIRCRAFT :{BLACK} Ticks des aéroplanes{NBSP}: STR_FRAMERATE_GL_LANDSCAPE :{BLACK} Ticks du monde{NBSP}: -STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Délai du flux des marchandises{NBSP}: +STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Délai du graphe de distribution{NBSP}: STR_FRAMERATE_DRAWING :{BLACK}Rendu des graphismes{NBSP}: STR_FRAMERATE_DRAWING_VIEWPORTS :{BLACK} Vues{NBSP}: STR_FRAMERATE_VIDEO :{BLACK}Sortie vidéo{NBSP}: @@ -2778,7 +2802,7 @@ STR_FRAMETIME_CAPTION_GL_ROADVEHS :Ticks des véhi STR_FRAMETIME_CAPTION_GL_SHIPS :Ticks des navires STR_FRAMETIME_CAPTION_GL_AIRCRAFT :Ticks des aéroplanes STR_FRAMETIME_CAPTION_GL_LANDSCAPE :Ticks du monde -STR_FRAMETIME_CAPTION_GL_LINKGRAPH :Délai du flux des marchandises +STR_FRAMETIME_CAPTION_GL_LINKGRAPH :Délai du graphe de distribution STR_FRAMETIME_CAPTION_DRAWING :Rendu des graphismes STR_FRAMETIME_CAPTION_DRAWING_VIEWPORTS :Rendu des vues STR_FRAMETIME_CAPTION_VIDEO :Sortie vidéo @@ -3158,10 +3182,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}Objectif STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Cliquer sur l'objectif pour centrer la vue principale sur l'industrie, la ville ou la case. Ctrl-clic pour ouvrir une nouvelle vue sur l'industrie, la ville ou la case. # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :Question -STR_GOAL_QUESTION_CAPTION_INFORMATION :Informations -STR_GOAL_QUESTION_CAPTION_WARNING :Attention -STR_GOAL_QUESTION_CAPTION_ERROR :Erreur +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}Question +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}Informations +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}Attention +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}Erreur ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :Annuler @@ -4240,6 +4264,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Sauvegarde modi STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Fichier illisible STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Fichier protégé en écriture STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Échec du contrôle d'intégrité des données +STR_GAME_SAVELOAD_ERROR_PATCHPACK :Sauvegarde créée avec une version modifiée STR_GAME_SAVELOAD_NOT_AVAILABLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Partie sauvegardée avec une version sans support des tramways. Tous les tramways ont été supprimés. diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index e9c100e1af..975da0671f 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -2683,7 +2683,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Meud: {G STR_OBJECT_CLASS_LTHS :Taighean-solais STR_OBJECT_CLASS_TRNS :Tùir chraobh-sgaoilidh -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Craobhan STR_PLANT_TREE_TOOLTIP :{BLACK}Tagh seòrsa na craoibhe airson cur. Ma tha craobh air an leac mu thràth, cuiridh seo barrachd chraobhan aig a bheil caochladh dhe sheòrsachan a tha neo-eisimeileach on t-seòrsa a thagh thu STR_TREES_RANDOM_TYPE :{BLACK}Craobhan dhe sheòrsa air thuaiream diff --git a/src/lang/galician.txt b/src/lang/galician.txt index eed680e1d3..e717c64cd5 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -2504,7 +2504,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Tamaño: STR_OBJECT_CLASS_LTHS :Faros STR_OBJECT_CLASS_TRNS :Transmisores -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Árbores STR_PLANT_TREE_TOOLTIP :{BLACK}Selecciona-lo tipo de árbore a plantar. Se xa hai unha árbore no cadro, isto engadirá máis árbores de varios tipos independentemente do tipo seleccionado STR_TREES_RANDOM_TYPE :{BLACK}Árbores de tipo aleatorio diff --git a/src/lang/german.txt b/src/lang/german.txt index bcf78ad47d..87924efab5 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -267,7 +267,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Zeigt au STR_BUTTON_DEFAULT :{BLACK}Standard STR_BUTTON_CANCEL :{BLACK}Abbrechen STR_BUTTON_OK :{BLACK}OK -STR_WARNING_PASSWORD_SECURITY :{YELLOW}Achtung: Server-Administratoren könnten in der Lage sein den eingegebenen Text zu lesen. +STR_WARNING_PASSWORD_SECURITY :{YELLOW}Warnung: Serveradministratoren können diesen Text einsehen. # On screen keyboard window STR_OSK_KEYBOARD_LAYOUT :^1234567890ß'€qwertzuiopü+asdfghjklöä# STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Spiel wurde in einer Version ohne Straßenbahnunterstützung gespeichert. Alle Straßenbahnen wurden entfernt @@ -5606,7 +5626,7 @@ STR_ERROR_GROUP_CAN_T_CREATE :{WHITE}Gruppe k STR_ERROR_GROUP_CAN_T_DELETE :{WHITE}Gruppe kann nicht gelöscht werden... STR_ERROR_GROUP_CAN_T_RENAME :{WHITE}Gruppe kann nicht umbenannt werden... STR_ERROR_GROUP_CAN_T_SET_PARENT :{WHITE}Übergeordnete Gruppe kann nicht gesetzt werden... -STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... Schleifen in der Gruppenhierarchy sind nicht erlaubt +STR_ERROR_GROUP_CAN_T_SET_PARENT_RECURSION :{WHITE}... Schleifen sind in der Gruppenhierarchie nicht erlaubt STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES :{WHITE}Entfernen aller Fahrzeuge dieser Gruppe nicht möglich... STR_ERROR_GROUP_CAN_T_ADD_VEHICLE :{WHITE}Fahrzeug kann nicht zu dieser Gruppe hinzugefügt werden... STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE :{WHITE}Fahrzeuge mit gemeinsamen Fahrplan können nicht zur Gruppe hinzugefügt werden... @@ -5816,10 +5836,10 @@ STR_INDUSTRY_NAME_SUGAR_MINE :{G=w}Zuckermine ##id 0x6000 STR_SV_EMPTY : STR_SV_UNNAMED :Unbenannt -STR_SV_TRAIN_NAME :Zug {COMMA} -STR_SV_ROAD_VEHICLE_NAME :Straßenfahrzeug {COMMA} -STR_SV_SHIP_NAME :Schiff {COMMA} -STR_SV_AIRCRAFT_NAME :Flugzeug {COMMA} +STR_SV_TRAIN_NAME :Zug #{COMMA} +STR_SV_ROAD_VEHICLE_NAME :Straßenfahrzeug #{COMMA} +STR_SV_SHIP_NAME :Schiff #{COMMA} +STR_SV_AIRCRAFT_NAME :Flugzeug #{COMMA} STR_SV_STNAME :{STRING} STR_SV_STNAME_NORTH :{STRING} Nord @@ -6126,6 +6146,7 @@ STR_FORMAT_BUOY_NAME :{TOWN} Boje STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Boje #{COMMA} STR_FORMAT_COMPANY_NUM :(Firma {COMMA}) STR_FORMAT_GROUP_NAME :Gruppe {COMMA} +STR_FORMAT_GROUP_VEHICLE_NAME :{GROUP} #{COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :Wegpunkt {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :Wegpunkt {TOWN} #{COMMA} diff --git a/src/lang/greek.txt b/src/lang/greek.txt index d28982ab0d..0bda878e92 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -2593,7 +2593,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Μέγε STR_OBJECT_CLASS_LTHS :Φάροι STR_OBJECT_CLASS_TRNS :Αναμεταδότες -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Δέντρα STR_PLANT_TREE_TOOLTIP :{BLACK}Επιλέξτε τύπο δέντρου για φύτευση. Αν το τετραγωνίδιο έχει ήδη ένα δέντρο, αυτό θα προσθέσει περισσότερα δέντρα μεικτών τύπων ανεξάρτητα από τον επιλεγμένο τύπο STR_TREES_RANDOM_TYPE :{BLACK}Δέντρα τυχαίου τύπου diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index 55fe5d7e23..c0c5a2c560 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -2476,7 +2476,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}גודל STR_OBJECT_CLASS_LTHS :מגדלורים STR_OBJECT_CLASS_TRNS :אנטנות -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}עצים STR_PLANT_TREE_TOOLTIP :{BLACK}בחר סוג עץ לנטיעה. במידה ויש עץ במשבצת, יתווספו עצים נוספים מסוגים שונים ללא קשר לסוג הנבחר STR_TREES_RANDOM_TYPE :{BLACK}עצים מסוג אקראי diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index e98f562982..9917413c7c 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -2577,7 +2577,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Méret: STR_OBJECT_CLASS_LTHS :Világítótornyok STR_OBJECT_CLASS_TRNS :Adótornyok -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Fák STR_PLANT_TREE_TOOLTIP :{BLACK}Ültetendő fa kiválasztása. Ha már van fa a mezőn, akkor újabb fák ültetése a kiválasztott fatípustól függetlenül STR_TREES_RANDOM_TYPE :{BLACK}Véletlenszerű fafélék diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index 056806aa31..498263b4b4 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -2302,7 +2302,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Stærð: STR_OBJECT_CLASS_LTHS :Vitar STR_OBJECT_CLASS_TRNS :Sendar -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Tré STR_PLANT_TREE_TOOLTIP :{BLACK}Veldu trjátegund sem á að gróðursetja. Ef það er fyrir tré á reitnum, verðu fleiri trjám mismunandi trjám plantað óhað hvaða tegund hefur verið valin STR_TREES_RANDOM_TYPE :{BLACK}Tré af handahófskenndri gerð diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index d0f1b2c8c7..846c33132f 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -2513,7 +2513,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Ukuran: STR_OBJECT_CLASS_LTHS :Mercusuar STR_OBJECT_CLASS_TRNS :Pemancar -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Pepohonan STR_PLANT_TREE_TOOLTIP :{BLACK}Pilih jenis pohon untuk ditanam. Jika pohon sudah tertanam, ini akan menambah jenis pohon secara acak dari tipe yang sama. STR_TREES_RANDOM_TYPE :{BLACK}Tanam pohon secara acak diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 198eaa945c..578072997e 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -2450,7 +2450,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Méid: { STR_OBJECT_CLASS_LTHS :Tithe solais STR_OBJECT_CLASS_TRNS :Tarchuradóirí -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Crainnte STR_PLANT_TREE_TOOLTIP :{BLACK}Roghnaigh an cineál crainn le cur STR_TREES_RANDOM_TYPE :{BLACK}Crainnte randamacha diff --git a/src/lang/italian.txt b/src/lang/italian.txt index a69dbd5de5..6ad7fd26c9 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -2543,7 +2543,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Dimensio STR_OBJECT_CLASS_LTHS :Fari STR_OBJECT_CLASS_TRNS :Trasmettitori -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Alberi STR_PLANT_TREE_TOOLTIP :{BLACK}Seleziona il tipo di albero da piantare. Se nel riquadro sono già presenti alberi, ne aggiunge altri di vari tipi, indipendentemente dal tipo selezionato STR_TREES_RANDOM_TYPE :{BLACK}Alberi casuali diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index fc20f31497..c4494b921f 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -2458,7 +2458,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}サイ STR_OBJECT_CLASS_LTHS :灯台 STR_OBJECT_CLASS_TRNS :電波塔 -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}植林 STR_PLANT_TREE_TOOLTIP :{BLACK}植林する樹類を選択します。既に木がある場合は追加で植林されます STR_TREES_RANDOM_TYPE :{BLACK}ランダムな樹類 diff --git a/src/lang/korean.txt b/src/lang/korean.txt index 0f27ce42f3..15a7ba228c 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -1268,7 +1268,7 @@ STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :선로의 어 STR_CONFIG_SETTING_SIGNALSIDE_LEFT :왼쪽에 STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :진행 방향에 STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :오른쪽에 -STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄움: {STRING} +STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄우기: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :이 설정을 켜면. 회사의 재정 상태를 확인하기 쉽도록 매년 말에 재정 창이 자동으로 뜹니다. STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :새로 지정하는 경로는 기본적으로 '직행'으로 처리: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :일반적으로 차량은 경로 상에 있는 모든 역에 정차하게 되어있습니다. 이 설정을 켜면, 차량이 마지막 목적지까지 정차없이 모든 역을 통과할 것입니다. 이 설정은 새로 경로를 지정하는 차량에만 적용되는 점을 알아두십시오. 하지만 각 차량의 경로는 두 가지 방법 중에 원하는 대로 다시 설정할 수 있습니다. @@ -1335,7 +1335,7 @@ STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :새 회사에 STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :옛날 공항을 사라지지 않고 계속 만들 수 있게 함: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :이 설정을 켜면, 소형 공항을 포함한 모든 공항 종류를 도입 이후에 계속 사용할 수 있게 됩니다. -STR_CONFIG_SETTING_WARN_LOST_VEHICLE :차량이 길을 잃으면 경고: {STRING} +STR_CONFIG_SETTING_WARN_LOST_VEHICLE :차량이 길을 잃으면 경고하기: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :다음 목적지로 가기 위한 경로를 찾을 수 없는 차량이 있으면 뉴스 메시지로 알려줍니다. STR_CONFIG_SETTING_WARN_RESTRICTION_WAIT_VEHICLE :열차가 경로 제한 때문에 멈춘 경우 경고: {STRING} STR_CONFIG_SETTING_WARN_RESTRICTION_WAIT_VEHICLE_HELPTEXT :경로 제한 기능때문에 열차가 경로 신호기에서 오랫동안 멈춰있는 경우 뉴스 메시지로 알려줍니다. @@ -1367,7 +1367,7 @@ STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :오류 메시 STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA}초 동안 STR_CONFIG_SETTING_HOVER_DELAY :도움말 보이기: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :마우스를 올려놓았을 때 도움말이 뜨는데 걸리는 시간을 설정합니다. 마우스 오른쪽 클릭으로 바로 뜨도록 할 수도 있습니다. -STR_CONFIG_SETTING_HOVER_DELAY_VALUE :마우스를 {COMMA}밀리초 동안 올려놓기 (1밀리초 = 1/1000초) +STR_CONFIG_SETTING_HOVER_DELAY_VALUE :마우스를 {COMMA}밀리초 동안 올려놓기 STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :마우스 오른쪽 클릭 STR_CONFIG_SETTING_POPULATION_IN_LABEL :도시 이름 옆에 도시의 인구 수를 표시함: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :도시 이름 옆에 도시의 인구 수를 표시합니다. @@ -1457,7 +1457,7 @@ STR_CONFIG_SETTING_SERVICEATHELIPAD :헬리콥터를 STR_CONFIG_SETTING_SERVICEATHELIPAD_HELPTEXT :공항에 격납고가 없어도 헬리콥터가 공항에 착륙할 때마다 점검을 하도록 합니다. STR_CONFIG_SETTING_NONSTOP_ORDER_ONLY :직통 경로만 허용: {STRING} STR_CONFIG_SETTING_NONSTOP_ORDER_ONLY_HELPTEXT :열차와 자동차에 직통 경로만 추가할 수 있게 합니다 -STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :철도/도로/항만/공항 건설창을 띄울 때 지형 편집창도 같이 띄움: {STRING} +STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR :철도/도로/항만/공항 건설창을 띄울 때 지형 편집창도 같이 띄우기: {STRING} STR_CONFIG_SETTING_LINK_TERRAFORM_TOOLBAR_HELPTEXT :수송 시설과 관련된 건설 창을 열 때 지형 편집 창을 같이 엽니다. STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR :소형지도 창에 표시될 땅의 색상: {STRING} STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :소형지도 창에 사용할 지형의 색상을 선택합니다. @@ -1540,7 +1540,7 @@ STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :게임을 자 STR_CONFIG_SETTING_AUTOSAVE_ON_NETWORK_DISCONNECT :네트워크 연결이 끊어지면 자동 저장: {STRING} STR_CONFIG_SETTING_AUTOSAVE_ON_NETWORK_DISCONNECT_HELPTEXT :이 설정을 켜면 서버와의 연결이 끊어졌을 때 게임을 자동으로 저장합니다. -STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :저장 파일의 이름으로 {STRING} 날짜 형식을 사용합니다. +STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES :저장 파일 이름으로 {STRING} 날짜 형식을 사용 STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_HELPTEXT :게임 저장 파일 이름에 사용할 날짜 형식을 선택합니다. STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_LONG :긴 (2012년 1월 1일) STR_CONFIG_SETTING_DATE_FORMAT_IN_SAVE_NAMES_SHORT :짧은 (2012.01.01) @@ -1668,7 +1668,7 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :멀티 플레 STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :게임 스크립트가 중지되기 직전에 계산할 수 있는 최대 횟수: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :게임 스크립트가 한 단계에서 계산할 수 있는 최대 계산 횟수를 설정합니다. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :스크립트당 최대 메모리 사용량: {STRING} -STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :강제로 종료되기 전에 단일 스크립트가 사용할 수 있는 메모리의 양입니다. 크기가 큰 맵에서는 값을 크게 설정해야할 수도 있습니다. +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :스크립트 하나가 강제 종료되기 전까지 사용할 수 있는 메모리의 양입니다. 크기가 큰 맵에서는 값을 크게 설정해야할 수도 있습니다. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SHARING_RAIL :철도 공유: {STRING} @@ -1755,7 +1755,7 @@ STR_CONFIG_SETTING_ECONOMY_TYPE_SMOOTH :부드러움 STR_CONFIG_SETTING_ECONOMY_TYPE_FROZEN :멈춤 STR_CONFIG_SETTING_ALLOW_SHARES :다른 회사의 지분을 사는 것을 허용: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :이 설정을 켜면, 회사의 지분을 거래할 수 있게 됩니다. 회사의 지분을 거래하려면 해당 회사가 어느 정도 오래되어야 합니다. -STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :지분 거래를 허용할 최소 회사 나이: {STRING} +STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES :지분 거래를 허용할 최소 회사 나이: {STRING}년 STR_CONFIG_SETTING_MIN_YEARS_FOR_SHARES_HELPTEXT :지분을 사고 팔기 위해 필요한 회사의 최소 나이를 설정합니다. STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :환승시 벌어들이는 중간 수익의 비율: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :더 많은 수익을 내기 위해, 수송 관계상 중간 구간에게 주어진 수익의 비율을 설정합니다. @@ -1770,7 +1770,7 @@ STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :드래그할 STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE_HELPTEXT :신호기를 CTRL+드래그 하여 설치할 때의 행동을 선택합니다. 이 설정을 끄면, 신호기가 없는 긴 폐색을 만들지 않기 위해 터널이나 다리 주변에 먼저 신호기가 설치될 것입니다. 이 설정을 켜면, 신호기는 터널/다리와 상관없이 매 n개의 칸마다 설치될 것입니다. STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :전자식 신호기의 사용: {STRING}년 이후에 STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :전자식 신호기를 사용할 수 있는 연도를 설정합니다. 이 이전에는 구식 신호기만 사용 가능합니다. (두 신호기는 기능적으로는 동일하고 모습만 다릅니다.) -STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :신호기 설치시 신호기 선택 창을 띄움: {STRING} +STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI :신호기 설치시 신호기 선택 창을 띄우기: {STRING} STR_CONFIG_SETTING_ENABLE_SIGNAL_GUI_HELPTEXT :설치할 신호기 종류를 고를 수 있는 신호기 선택 창을 표시합니다. 이 설정을 끄면, 신호기 선택 창 없이 CTRL+클릭 만으로 신호기의 종류를 바꿔야 합니다. STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE :기본적으로 만들 신호기 종류: {STRING} STR_CONFIG_SETTING_DEFAULT_SIGNAL_TYPE_HELPTEXT :기본으로 설치할 신호기의 종류를 선택합니다. @@ -1810,8 +1810,12 @@ STR_CONFIG_SETTING_TOWN_CARGO_FACTOR_HELPTEXT :도시가 생 STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR :산업 시설 화물 생성 계수 (적음 < 0 < 많음): {STRING} STR_CONFIG_SETTING_INDUSTRY_CARGO_FACTOR_HELPTEXT :1차 산업 시설이 생산하는 화물의 양을 2^(생성 계수)에 근접하게 조절합니다. 나무를 베는 산업 시설에는 적용되지 않습니다.{}모든 산업 시설 관련 NewGRF와 모두 호환되지는 않을 수 있습니다. -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :게임 진행 중에 나무가 자동적으로 번식: {STRING} -STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :게임 중에 나무가 자동적으로 번식하는지 여부를 조절합니다. 이 설정을 조정하면, 아열대 기후의 벌목소처럼 나무의 성장에 의존하는 산업시설에 영향을 끼칠 수 있습니다. +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :나무의 성장과 확장: {STRING} +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :게임 플레이 중 나무의 성장과 확장 여부를 조절합니다. 이 설정을 조정하면, 아열대 기후의 벌목소처럼 나무의 성장에 의존하는 산업시설에 영향을 끼칠 수 있습니다. +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :성장은 하되 확장은 안 함 {RED}(제재소가 멈출 수 있음) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :성장은 하되 열대 우림에서만 확장함 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :어디서나 성장하고 확장함 +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :성장과 확장 모두 안 함 {RED}(제재소가 멈출 수 있음) STR_CONFIG_SETTING_TREES_AROUND_SNOWLINE :조정된 눈 쌓인 나무: {STRING} STR_CONFIG_SETTING_TREES_AROUND_SNOWLINE_HELPTEXT :아한대 기후에서의 설선 근처의 눈 쌓인 나무의 개수를 조정합니다. 설선 위에는 나무가 적어집니다. 설선에서는 온대 기후의 나무와 눈 쌓인 나무가 공존할 것입니다. 설선 아래에선 온대 기후의 나무가 자랄 것입니다. @@ -2293,6 +2297,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}게임 STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}새로고침 STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}서버 정보를 새로 고칩니다. +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}인터넷 검색 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}인터넷에서 공개 서버를 검색합니다 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}LAN 검색 +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}로컬 영역 네트워크에서 서버를 검색합니다 STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}서버 추가 STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}서버를 목록에 수동으로 추가합니다. STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}서버 열기 @@ -3200,7 +3208,7 @@ STR_BASIC_HOUSE_SET_NAME :기본 건물 STR_SELECT_TOWN_CAPTION :{WHITE}도시 선택 STR_SELECT_TOWN_LIST_ITEM :{BLACK}{TOWN} -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}나무 STR_PLANT_TREE_TOOLTIP :{BLACK}심고싶은 나무의 종류를 선택합니다. 이미 나무가 심어져있는 경우에는 선택한 나무의 크기를 키웁니다 STR_TREES_RANDOM_TYPE :{BLACK}여러 종류의 나무 같이 심기 @@ -3209,6 +3217,12 @@ STR_TREES_RANDOM_TREES_BUTTON :{BLACK}무작 STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}전 지역에 걸쳐 무작위로 나무를 심습니다 STR_TREES_REMOVE_TREES_BUTTON :{BLACK}모든 나무 제거하기 STR_TREES_REMOVE_TREES_TOOLTIP :{BLACK}전 지역에 걸쳐 나무를 모두 제거합니다. +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}일반 +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}지면을 드래그해서 나무를 하나씩 놓습니다. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}작은 숲 +STR_TREES_MODE_FOREST_SM_TOOLTIP :{BLACK}지면을 드래그해서 작은 숲을 만듭니다. +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}큰 숲 +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}지면을 드래그해서 큰 숲을 만듭니다. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}지형 만들기 @@ -3865,10 +3879,10 @@ STR_GOALS_COMPANY_TITLE :{BLACK}회사 STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}산업시설/마을/칸의 위치로 화면을 이동하려면 클릭하십시오. CTRL+클릭하면 산업시설/마을/칸의 위치를 기준으로 새로운 외부 화면을 엽니다 # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :{G=m}질문 -STR_GOAL_QUESTION_CAPTION_INFORMATION :{G=f}정보 -STR_GOAL_QUESTION_CAPTION_WARNING :{G=f}경고 -STR_GOAL_QUESTION_CAPTION_ERROR :{G=f}오류 +STR_GOAL_QUESTION_CAPTION_QUESTION :{BLACK}질의 +STR_GOAL_QUESTION_CAPTION_INFORMATION :{BLACK}정보 +STR_GOAL_QUESTION_CAPTION_WARNING :{BLACK}경고 +STR_GOAL_QUESTION_CAPTION_ERROR :{YELLOW}오류 ############ Start of Goal Question button list STR_GOAL_QUESTION_BUTTON_CANCEL :취소 diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 5a30adba6b..d826bb0811 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -2685,7 +2685,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Magnitud STR_OBJECT_CLASS_LTHS :Phari STR_OBJECT_CLASS_TRNS :Emissoria -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Arbores STR_PLANT_TREE_TOOLTIP :{BLACK}Eligere arborem serendam. Si tegula iam arborem habet, plures arbores fortuitas addentur (forsitan non idem typus arboris) STR_TREES_RANDOM_TYPE :{BLACK}Arbor fortuita diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 3c58dbf70f..ed3e8d94ec 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -317,8 +317,15 @@ STR_SORT_BY_CARGO_CAPACITY :kravnesības STR_SORT_BY_RANGE :apgabala STR_SORT_BY_POPULATION :iedzīvotāju skaita STR_SORT_BY_RATING :vērtējuma +STR_SORT_BY_NUM_VEHICLES :Autotransporta līdzekļu skaits +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Kopējā peļņa pagājušajā gadā +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Kopējā peļņa šogad +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Vidējā peļņa iepriekšējā gadā +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Vidējā peļņa šajā gadā # Group by options for vehicle list +STR_GROUP_BY_NONE :Nav +STR_GROUP_BY_SHARED_ORDERS :Koplietojamie rīkojumi # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pauzēt spēli @@ -775,6 +782,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Rādīt STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Rādīt pēdējo ziņojumu vai avīzes rakstu STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUZE * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE} * * PAUZE (gaida saites diagrammas atjaunināšanu) * * STR_STATUSBAR_AUTOSAVE :{RED}AUTOMĀTISKĀ SAGLABĀŠANA STR_STATUSBAR_SAVING_GAME :{RED}* * SPĒLE TIEK SAGLABĀTA * * @@ -1614,6 +1622,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Lineārs STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Koku izvietojums spēlē: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Vadīt nejaušu koku parādīšanos spēles laikā. Tas var ietekmēt no kokaudzēšanas atkarīgas ražotnes, piemēram kokzāģētavas +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Augt, bet neizplatās {RED} (salauž kokzāģētavas) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Aug, bet izplatās tikai lietus mežos +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Aug un izplatās visur +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_GROWTH_NO_SPREAD :Augt, bet neizplatās {RED} (salauž kokzāģētavas) STR_CONFIG_SETTING_TOOLBAR_POS :Galvenās rīkjoslas novietojums: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Galvenās rīkjoslas horizontālais novietojums ekrāna augšējā daļā @@ -1979,6 +1991,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Pievieno STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Atsvaidzināt serveri STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Atsvaidzināt servera informāciju +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :Meklēt internetā +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Meklēt publiskos serverus internetā +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Meklēt LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Meklēt serverus lokālajā tīklā STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Pievienot serveri STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Pievienot serveri sarakstam, kurš vienmēr tiks pārbaudīts vai tajā nav palaistas spēles STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Palaist serveri @@ -2204,11 +2220,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Spēle joprojā STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Spēle joprojām pauzēta ({STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Spēle joprojām pauzēta ({STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Spēle vēl aizvien ir pauzēta ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :Spēle joprojām pauzēta ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Spēle atsākta ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :spēlētāju skaits STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :savieno spēlētājus STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :manuālā STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :spēles skripts +STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :gaida uz saišu grafika atjaunošanu ############ End of leave-in-this-order STR_NETWORK_MESSAGE_CLIENT_LEAVING :aizeju STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} ir pievienojies spēlei @@ -2525,7 +2543,7 @@ STR_OBJECT_BUILD_SIZE :{BLACK}Izmērs: STR_OBJECT_CLASS_LTHS :Bākas STR_OBJECT_CLASS_TRNS :Raidītāji -# Tree planting window (last two for SE only) +# Tree planting window (last eight for SE only) STR_PLANT_TREE_CAPTION :{WHITE}Koki STR_PLANT_TREE_TOOLTIP :{BLACK}Izvēlēties koka veidu stādīšanai. Ja lauciņš jau ir koks, tas pievienos vairāk jauktu veidu kokus neatkarīgi no izvēlētā veida STR_TREES_RANDOM_TYPE :{BLACK}Nejauši izvēlēta veida koki @@ -4250,6 +4268,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :Spēle ir sagla STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :Failu nevar nolasīt STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :Failā nevar ierakstīt STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :Datu integritātes pārbaude neizdevās +STR_GAME_SAVELOAD_ERROR_PATCHPACK :Saglabāšana notiek ar modificētu versiju STR_GAME_SAVELOAD_NOT_AVAILABLE :