diff --git a/.dorpsgek.yml b/.dorpsgek.yml index 363d8b0b42..7ce84af72f 100644 --- a/.dorpsgek.yml +++ b/.dorpsgek.yml @@ -10,6 +10,7 @@ notifications: only-by: - DorpsGek commit-comment: + discussion: pull-request: issue: tag-created: diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index ba365bfe4f..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,7 +0,0 @@ -## Version of OpenTTD - -## Expected result - -## Actual result - -## Steps to reproduce diff --git a/.github/ISSUE_TEMPLATE/bug.md b/.github/ISSUE_TEMPLATE/bug.md new file mode 100644 index 0000000000..4801435901 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.md @@ -0,0 +1,17 @@ +--- +name: Bugs +about: Found a bug in OpenTTD? +title: "Bug Report" +--- + +## Version of OpenTTD + + +## Expected result + + +## Actual result + + +## Steps to reproduce + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..2fd749087a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: +- name: Suggestions and ideas? + url: https://www.tt-forums.net/viewforum.php?f=32 + about: Have a suggestion or an idea for a cool new feature? Post them on our forum! diff --git a/.github/ISSUE_TEMPLATE/crash.md b/.github/ISSUE_TEMPLATE/crash.md new file mode 100644 index 0000000000..00f62f05c9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/crash.md @@ -0,0 +1,12 @@ +--- +name: Crash +about: Did OpenTTD crash? +title: "Crash Report" +--- + + +## Version of OpenTTD + + +## Steps to reproduce + diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index b5be82df79..312117d353 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -94,7 +94,7 @@ jobs: - name: Test run: | cd build - ctest -j $(nproc) + ctest -j $(nproc) --timeout 120 macos: name: Mac OS @@ -175,5 +175,5 @@ jobs: - name: Test run: | cd build - ctest -j $(sysctl -n hw.logicalcpu) + ctest -j $(sysctl -n hw.logicalcpu) --timeout 120 diff --git a/CMakeLists.txt b/CMakeLists.txt index c1cf7a957b..085970135a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,10 +4,12 @@ if(NOT BINARY_NAME) set(BINARY_NAME openttd) endif() -project(${BINARY_NAME}) +project(${BINARY_NAME} + VERSION 1.12.0 +) if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) - message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the bin directory") + message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the build directory. You may need to delete \"${CMAKE_SOURCE_DIR}/CMakeCache.txt\" first.") endif() # Debug mode by default. @@ -72,6 +74,9 @@ add_custom_target(find_version ${CMAKE_COMMAND} -DFIND_VERSION_BINARY_DIR=${CMAKE_BINARY_DIR}/generated -DCPACK_BINARY_DIR=${CMAKE_BINARY_DIR} + -DREV_MAJOR=${PROJECT_VERSION_MAJOR} + -DREV_MINOR=${PROJECT_VERSION_MINOR} + -DREV_BUILD=${PROJECT_VERSION_PATCH} $<$:-DANDROID=TRUE> -P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} @@ -233,6 +238,7 @@ if(MSVC) target_sources(openttd PRIVATE "${CMAKE_SOURCE_DIR}/os/windows/openttd.manifest") endif() +add_subdirectory(${CMAKE_SOURCE_DIR}/bin) add_subdirectory(${CMAKE_SOURCE_DIR}/src) add_subdirectory(${CMAKE_SOURCE_DIR}/media) @@ -253,7 +259,7 @@ if(IPO_FOUND) set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL True) set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO True) endif() -set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") +set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") process_compile_flags() include(LinkPackage) diff --git a/COMPILING.md b/COMPILING.md index 5e642dc874..06f54262e4 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -2,26 +2,27 @@ ## Required/optional libraries -The following libraries are used by OpenTTD for: +OpenTTD makes use of the following external libraries: -- zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads, +- (encouraged) zlib: (de)compressing of old (0.3.0-1.0.5) savegames, content downloads, heightmaps -- liblzo2: (de)compressing of old (pre 0.3.0) savegames -- liblzma: (de)compressing of savegames (1.1.0 and later) -- libpng: making screenshots and loading heightmaps +- (encouraged) liblzma: (de)compressing of savegames (1.1.0 and later) +- (encouraged) libpng: making screenshots and loading heightmaps +- (optional) liblzo2: (de)compressing of old (pre 0.3.0) savegames + +For Linux, the following additional libraries are used (for non-dedicated only): + +- libSDL2: hardware access (video, sound, mouse) - libfreetype: loading generic fonts and rendering them - libfontconfig: searching for fonts, resolving font names to actual fonts - libicu: handling of right-to-left scripts (e.g. Arabic and Persian) and - natural sorting of strings (Linux only) -- libSDL2: hardware access (video, sound, mouse) (not required for Windows or macOS) + natural sorting of strings OpenTTD does not require any of the libraries to be present, but without liblzma you cannot open most recent savegames and without zlib you cannot open most older savegames or use the content downloading system. -Without libSDL/liballegro on non-Windows and non-macOS machines you have -no graphical user interface; you would be building a dedicated server. -## Windows: +## Windows You need Microsoft Visual Studio 2017 or more recent. @@ -77,6 +78,8 @@ files himself via the `ZERO_CHECK` project. ## All other platforms Minimum required version of CMake is 3.9. +By default this produces a Debug build with assertations enabled. +This is a far slower build than release builds. ```bash mkdir build @@ -88,6 +91,25 @@ 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). +## CMake Options + +Via CMake, several options can be influenced to get different types of +builds. + +- `-DCMAKE_BUILD_TYPE=RelWithDebInfo`: build a release build. This is + significant faster than a debug build, but has far less useful information + in case of a crash. +- `-DOPTION_DEDICATED=ON`: build OpenTTD without a GUI. Useful if you are + running a headless server, as it requires less libraries to operate. +- `-DOPTION_USE_ASSERTS=OFF`: disable asserts. Use with care, as assert + statements capture early signs of trouble. Release builds have them + disabled by default. +- `-DOPTION_USE_THREADS=OFF`: disable the use of threads. This will block + the interface in many places, and in general gives a worse experience of + the game. Use with care. +- `-DOPTION_TOOLS_ONLY=ON`: only build tools like `strgen`. Does not build + the game itself. Useful for cross-compiling. + ## Supported compilers Every compiler that is supported by CMake and supports C++17, should be diff --git a/CREDITS.md b/CREDITS.md index 8c20a4ac18..33f8836265 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -14,7 +14,6 @@ - Ingo von Borstel (planetmaker) - General coding, Support (since 1.1) - Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5) - José Soler (Terkhen) - General coding (since 1.0) -- Leif Linse (Zuu) - AI/Game Script (since 1.2) ### Inactive Developers: @@ -28,6 +27,7 @@ - Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5) - Patric Stout (TrueBrain) - NoProgrammer (0.3 - 1.2), sys op (active) - Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3) +- Leif Linse (Zuu) - AI/Game Script (1.2 - 1.6) ### Retired Developers: diff --git a/README.md b/README.md index 14104e041a..a5142ffecb 100644 --- a/README.md +++ b/README.md @@ -46,15 +46,13 @@ OpenTTD has a [community-maintained wiki](https://wiki.openttd.org/), including OpenTTD has been ported to several platforms and operating systems. -The currently working platforms are: +The currently supported platforms are: -- FreeBSD (SDL) -- Haiku (SDL) -- Linux (SDL) -- macOS (universal) (Cocoa video and sound drivers) -- OpenBSD (SDL) -- OS/2 (SDL) -- Windows (Win32 GDI (faster) or SDL) +- Linux (SDL (OpenGL and non-OpenGL)) +- macOS (universal) (Cocoa) +- Windows (Win32 GDI / OpenGL) + +Other platforms may also work (in particular various BSD systems), but we don't actively test or maintain these. ### 1.3.1) Legacy support Platforms, languages and compilers change. @@ -79,9 +77,9 @@ For some platforms, you will need to refer to [the installation guide](https://w The free data files, split into OpenGFX for graphics, OpenSFX for sounds and OpenMSX for music can be found at: -- https://www.openttd.org/download-opengfx for OpenGFX -- https://www.openttd.org/download-opensfx for OpenSFX -- https://www.openttd.org/download-openmsx for OpenMSX +- https://www.openttd.org/downloads/opengfx-releases/ for OpenGFX +- https://www.openttd.org/downloads/opensfx-releases/ for OpenSFX +- https://www.openttd.org/downloads/openmsx-releases/ for OpenMSX Please follow the readme of these packages about the installation procedure. The Windows installer can optionally download and install these packages. diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt new file mode 100644 index 0000000000..9d75bc0eea --- /dev/null +++ b/bin/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(ai) +add_subdirectory(game) diff --git a/bin/ai/CMakeLists.txt b/bin/ai/CMakeLists.txt new file mode 100644 index 0000000000..83eb11962d --- /dev/null +++ b/bin/ai/CMakeLists.txt @@ -0,0 +1,40 @@ +set(AI_COMPAT_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/compat_0.7.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.0.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.1.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.2.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.3.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.4.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.5.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.6.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.7.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.8.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.9.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.10.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.11.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.12.nut +) + +foreach(AI_COMPAT_SOURCE_FILE IN LISTS AI_COMPAT_SOURCE_FILES) + string(REPLACE "${CMAKE_SOURCE_DIR}/bin/" "" AI_COMPAT_SOURCE_FILE_NAME "${AI_COMPAT_SOURCE_FILE}") + string(CONCAT AI_COMPAT_BINARY_FILE "${CMAKE_BINARY_DIR}/" "${AI_COMPAT_SOURCE_FILE_NAME}") + + add_custom_command(OUTPUT ${AI_COMPAT_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} -E copy + ${AI_COMPAT_SOURCE_FILE} + ${AI_COMPAT_BINARY_FILE} + MAIN_DEPENDENCY ${AI_COMPAT_SOURCE_FILE} + COMMENT "Copying ${AI_COMPAT_SOURCE_FILE_NAME}" + ) + + list(APPEND AI_COMPAT_BINARY_FILES ${AI_COMPAT_BINARY_FILE}) +endforeach() + +# Create a new target which copies all compat files +add_custom_target(ai_compat_files + DEPENDS ${AI_COMPAT_BINARY_FILES} +) + +add_dependencies(openttd + ai_compat_files +) diff --git a/bin/game/CMakeLists.txt b/bin/game/CMakeLists.txt new file mode 100644 index 0000000000..508254e1f2 --- /dev/null +++ b/bin/game/CMakeLists.txt @@ -0,0 +1,37 @@ +set(GS_COMPAT_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.2.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.3.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.4.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.5.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.6.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.7.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.8.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.9.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.10.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.11.nut + ${CMAKE_CURRENT_SOURCE_DIR}/compat_1.12.nut +) + +foreach(GS_COMPAT_SOURCE_FILE IN LISTS GS_COMPAT_SOURCE_FILES) + string(REPLACE "${CMAKE_SOURCE_DIR}/bin/" "" GS_COMPAT_SOURCE_FILE_NAME "${GS_COMPAT_SOURCE_FILE}") + string(CONCAT GS_COMPAT_BINARY_FILE "${CMAKE_BINARY_DIR}/" "${GS_COMPAT_SOURCE_FILE_NAME}") + + add_custom_command(OUTPUT ${GS_COMPAT_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} -E copy + ${GS_COMPAT_SOURCE_FILE} + ${GS_COMPAT_BINARY_FILE} + MAIN_DEPENDENCY ${GS_COMPAT_SOURCE_FILE} + COMMENT "Copying ${GS_COMPAT_SOURCE_FILE_NAME}" + ) + + list(APPEND GS_COMPAT_BINARY_FILES ${GS_COMPAT_BINARY_FILE}) +endforeach() + +# Create a new target which copies all compat files +add_custom_target(gs_compat_files + DEPENDS ${GS_COMPAT_BINARY_FILES} +) + +add_dependencies(openttd + gs_compat_files +) diff --git a/cmake/CompileFlags.cmake b/cmake/CompileFlags.cmake index f4047b8396..86d336b595 100644 --- a/cmake/CompileFlags.cmake +++ b/cmake/CompileFlags.cmake @@ -4,20 +4,22 @@ # macro(compile_flags) if(MSVC) - # Switch to MT (static) instead of MD (dynamic) binary + if(VCPKG_TARGET_TRIPLET MATCHES "-static" AND NOT VCPKG_TARGET_TRIPLET MATCHES "-md") + # Switch to MT (static) instead of MD (dynamic) binary - # For MSVC two generators are available - # - a command line generator (Ninja) using CMAKE_BUILD_TYPE to specify the - # configuration of the build tree - # - an IDE generator (Visual Studio) using CMAKE_CONFIGURATION_TYPES to - # specify all configurations that will be available in the generated solution - list(APPEND MSVC_CONFIGS "${CMAKE_BUILD_TYPE}" "${CMAKE_CONFIGURATION_TYPES}") + # For MSVC two generators are available + # - a command line generator (Ninja) using CMAKE_BUILD_TYPE to specify the + # configuration of the build tree + # - an IDE generator (Visual Studio) using CMAKE_CONFIGURATION_TYPES to + # specify all configurations that will be available in the generated solution + list(APPEND MSVC_CONFIGS "${CMAKE_BUILD_TYPE}" "${CMAKE_CONFIGURATION_TYPES}") - # Set usage of static runtime for all configurations - foreach(MSVC_CONFIG ${MSVC_CONFIGS}) - string(TOUPPER "CMAKE_CXX_FLAGS_${MSVC_CONFIG}" MSVC_FLAGS) - string(REPLACE "/MD" "/MT" ${MSVC_FLAGS} "${${MSVC_FLAGS}}") - endforeach() + # Set usage of static runtime for all configurations + foreach(MSVC_CONFIG ${MSVC_CONFIGS}) + string(TOUPPER "CMAKE_CXX_FLAGS_${MSVC_CONFIG}" MSVC_FLAGS) + string(REPLACE "/MD" "/MT" ${MSVC_FLAGS} "${${MSVC_FLAGS}}") + endforeach() + endif() # "If /Zc:rvalueCast is specified, the compiler follows section 5.4 of the # C++11 standard". We need C++11 for the way we use threads. diff --git a/cmake/CreateGrfCommand.cmake b/cmake/CreateGrfCommand.cmake index 4ad9734198..107ec09b88 100644 --- a/cmake/CreateGrfCommand.cmake +++ b/cmake/CreateGrfCommand.cmake @@ -35,9 +35,9 @@ function(create_grf_command) -DNFORENUM_EXECUTABLE=${NFORENUM_EXECUTABLE} -DGRFCODEC_EXECUTABLE=${GRFCODEC_EXECUTABLE} -P ${CMAKE_SOURCE_DIR}/cmake/scripts/CreateGRF.cmake - MAIN_DEPENDENCY ${GRF_NFO_SOURCE_FILES} + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/cmake/scripts/CreateGRF.cmake DEPENDS ${GRF_PNG_BINARY_FILES} - ${CMAKE_SOURCE_DIR}/cmake/scripts/CreateGRF.cmake + ${GRF_NFO_SOURCE_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating ${GRF_SOURCE_FOLDER_NAME}.grf" ) diff --git a/cmake/InstallAndPackage.cmake b/cmake/InstallAndPackage.cmake index ac72b44823..61ea9d6a7f 100644 --- a/cmake/InstallAndPackage.cmake +++ b/cmake/InstallAndPackage.cmake @@ -27,11 +27,13 @@ install(TARGETS openttd install(DIRECTORY ${CMAKE_BINARY_DIR}/lang ${CMAKE_BINARY_DIR}/baseset - ${CMAKE_SOURCE_DIR}/bin/ai - ${CMAKE_SOURCE_DIR}/bin/game + ${CMAKE_BINARY_DIR}/ai + ${CMAKE_BINARY_DIR}/game ${CMAKE_SOURCE_DIR}/bin/scripts DESTINATION ${DATA_DESTINATION_DIR} - COMPONENT language_files) + COMPONENT language_files + REGEX "ai/[^\.]+$" EXCLUDE # Ignore subdirs in ai dir +) install(FILES ${CMAKE_SOURCE_DIR}/COPYING.md diff --git a/cmake/scripts/CreateGRF.cmake b/cmake/scripts/CreateGRF.cmake index 8631284f33..d47e39aa0e 100644 --- a/cmake/scripts/CreateGRF.cmake +++ b/cmake/scripts/CreateGRF.cmake @@ -39,6 +39,20 @@ foreach(NFO_LINE IN LISTS NFO_LINES) endif() endforeach() -execute_process(COMMAND ${NFORENUM_EXECUTABLE} -s sprites/${GRF_SOURCE_FOLDER_NAME}.nfo) -execute_process(COMMAND ${GRFCODEC_EXECUTABLE} -n -s -e -p1 ${GRF_SOURCE_FOLDER_NAME}.grf) +execute_process(COMMAND ${NFORENUM_EXECUTABLE} -s sprites/${GRF_SOURCE_FOLDER_NAME}.nfo RESULT_VARIABLE RESULT) +if(RESULT) + if(NOT RESULT MATCHES "^[0-9]*$") + message(FATAL_ERROR "Failed to run NFORenum (${RESULT}), please check NFORENUM_EXECUTABLE variable") + endif() + message(FATAL_ERROR "NFORenum failed") +endif() + +execute_process(COMMAND ${GRFCODEC_EXECUTABLE} -n -s -e -p1 ${GRF_SOURCE_FOLDER_NAME}.grf RESULT_VARIABLE RESULT) +if(RESULT) + if(NOT RESULT MATCHES "^[0-9]*$") + message(FATAL_ERROR "Failed to run GRFCodec (${RESULT}), please check GRFCODEC_EXECUTABLE variable") + endif() + message(FATAL_ERROR "GRFCodec failed") +endif() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy ${GRF_SOURCE_FOLDER_NAME}.grf ${GRF_BINARY_FILE}) diff --git a/cmake/scripts/FindVersion.cmake b/cmake/scripts/FindVersion.cmake index fbb2f6c341..0b1ae65ba2 100644 --- a/cmake/scripts/FindVersion.cmake +++ b/cmake/scripts/FindVersion.cmake @@ -1,5 +1,15 @@ cmake_minimum_required(VERSION 3.5) +if(NOT REV_MAJOR) + set(REV_MAJOR 0) +endif() +if(NOT REV_MINOR) + set(REV_MINOR 0) +endif() +if(NOT REV_BUILD) + set(REV_BUILD 0) +endif() + # # Finds the current version of the current folder. # diff --git a/docs/company_colour_indexes.html b/docs/company_colour_indexes.html new file mode 100644 index 0000000000..fb9dea7add --- /dev/null +++ b/docs/company_colour_indexes.html @@ -0,0 +1,557 @@ + + + + + OpenTTD Company Colour Indexes + + + + +

Company Colour Indexes

+

Hex / dec indexes into the DOS palette

+

+ Visual representation of values derived from https://github.com/frosch123/TTDViewer/blob/master/src/recolor.xml#L186 +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
COLOUR_DARK_BLUE
0xc60xc70xc80xc90xca0xcb0xcc0xcd
198199200201202203204205
COLOUR_PALE_GREEN
0x600x610x620x630x640x650x660x67
96979899100101102103
COLOUR_PINK
0x2a0x2b0x2c0x2d0x2e0x2f0x300x31
4243444546474849
COLOUR_YELLOW
0x3e0x3f0x400x410x420x430x440x45
6263646566676869
COLOUR_RED
0xb30xb40xb50xb60xb70xa40xa50xa6
179180181182183164165166
COLOUR_LIGHT_BLUE
0x9a0x9b0x9c0x9d0x9e0x9f0xa00xa1
154155156157158159160161
COLOUR_GREEN
0x520x530x540x550xce0xcf0xd00xd1
82838485206207208209
COLOUR_DARK_GREEN
0x580x590x5a0x5b0x5c0x5d0x5e0x5f
8889909192939495
COLOUR_BLUE
0x920x930x940x950x960x970x980x99
146147148149150151152153
COLOUR_CREAM
0x720x730x740x750x760x770x780x79
114115116117118119120121
COLOUR_MAUVE
0x800x810x820x830x840x850x860x87
128129130131132133134135
COLOUR_PURPLE
0x880x890x8a0x8b0x8c0x8d0x8e0x8f
136137138139140141142143
COLOUR_ORANGE
0x400xc00xc10xc20xc30xc40xc50x27
6419219319419519619739
COLOUR_BROWN
0x200x210x220x230x240x250x260x27
3233343536373839
COLOUR_GREY
0x40x50x60x70x80x90xa0xb
4567891011
COLOUR_WHITE
0x80x90xa0xb0xc0xd0xe0xf
89101112131415
+ + diff --git a/docs/multiplayer.md b/docs/multiplayer.md index 89a490602e..daccbf06d6 100644 --- a/docs/multiplayer.md +++ b/docs/multiplayer.md @@ -211,3 +211,10 @@ Last updated: 2011-02-16 communication from an admin tool reach the programme. See section 1 'Starting a server' further up for the ports and protocols used by OpenTTD. The ports can be configured in the config file. + + - My advertising server warns a lot about getaddrinfo taking N seconds + This could be a transient issue with your (local) DNS server, but if the + problem persists there is likely a configuration issue in DNS resolving + on your computer. This seems to be a common configuration issue for + Docker instances, where the DNS resolving waits for a time out of usually + 5 seconds. diff --git a/media/baseset/openttd.grf b/media/baseset/openttd.grf index a63bfc4e29..837e4b12d2 100644 Binary files a/media/baseset/openttd.grf and b/media/baseset/openttd.grf differ diff --git a/media/baseset/openttd/openttdgui.nfo b/media/baseset/openttd/openttdgui.nfo index eb1313365e..2fd5a5bb4c 100644 --- a/media/baseset/openttd/openttdgui.nfo +++ b/media/baseset/openttd/openttdgui.nfo @@ -4,7 +4,7 @@ // See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . // -1 * 0 0C "OpenTTD GUI graphics" - -1 * 3 05 15 \b 186 // OPENTTD_SPRITE_COUNT + -1 * 3 05 15 \b 191 // OPENTTD_SPRITE_COUNT -1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal @@ -191,3 +191,8 @@ -1 sprites/openttdgui_convert_tram.png 8bpp 24 0 32 32 0 0 normal -1 sprites/openttdgui.png 8bpp 513 440 10 10 0 0 normal -1 sprites/openttdgui.png 8bpp 526 440 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 539 440 12 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 553 440 12 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 567 440 12 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 581 440 10 10 0 0 normal + -1 sprites/openttdgui.png 8bpp 593 440 10 10 0 0 normal diff --git a/media/baseset/openttd/openttdgui.png b/media/baseset/openttd/openttdgui.png index 1fc02aa61e..5b80c33260 100644 Binary files a/media/baseset/openttd/openttdgui.png and b/media/baseset/openttd/openttdgui.png differ diff --git a/os/emscripten/pre.js b/os/emscripten/pre.js index 113a3acc10..8c7a60c427 100644 --- a/os/emscripten/pre.js +++ b/os/emscripten/pre.js @@ -69,10 +69,14 @@ Module.preRun.push(function() { } window.openttd_server_list = function() { - add_server = Module.cwrap("em_openttd_add_server", null, ["string", "number"]); + add_server = Module.cwrap("em_openttd_add_server", null, ["string"]); - /* Add servers that support WebSocket here. Example: - * add_server("localhost", 3979); */ + /* Add servers that support WebSocket here. Examples: + * add_server("localhost"); + * add_server("localhost:3979"); + * add_server("127.0.0.1:3979"); + * add_server("[::1]:3979"); + */ } var leftButtonDown = false; diff --git a/regression/regression/info.nut b/regression/regression/info.nut index 340dcff5c3..50c9fa5146 100644 --- a/regression/regression/info.nut +++ b/regression/regression/info.nut @@ -7,6 +7,7 @@ class Regression extends AIInfo { function GetAPIVersion() { return "1.12"; } function GetDate() { return "2007-03-18"; } function CreateInstance() { return "Regression"; } + function UseAsRandomAI() { return false; } } RegisterAI(Regression()); diff --git a/regression/stationlist/info.nut b/regression/stationlist/info.nut index a58fd20ba8..0558ccc1fb 100644 --- a/regression/stationlist/info.nut +++ b/regression/stationlist/info.nut @@ -7,6 +7,7 @@ class StationList extends AIInfo { function GetAPIVersion() { return "1.12"; } function GetDate() { return "2007-03-18"; } function CreateInstance() { return "StationList"; } + function UseAsRandomAI() { return false; } } RegisterAI(StationList()); diff --git a/src/3rdparty/squirrel/squirrel/sqarray.h b/src/3rdparty/squirrel/squirrel/sqarray.h index 5c26352079..13ae11619c 100644 --- a/src/3rdparty/squirrel/squirrel/sqarray.h +++ b/src/3rdparty/squirrel/squirrel/sqarray.h @@ -17,9 +17,9 @@ public: return newarray; } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif - void Finalize(){ + void Finalize() override { _values.resize(0); } bool Get(const SQInteger nidx,SQObjectPtr &val) @@ -78,9 +78,13 @@ public: ShrinkIfNeeded(); return true; } - void Release() + void Release() override { - sq_delete(this,SQArray); + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override + { + sq_delete(this, SQArray); } SQObjectPtrVec _values; }; diff --git a/src/3rdparty/squirrel/squirrel/sqclass.h b/src/3rdparty/squirrel/squirrel/sqclass.h index 895c053c24..4fb6ecbd97 100644 --- a/src/3rdparty/squirrel/squirrel/sqclass.h +++ b/src/3rdparty/squirrel/squirrel/sqclass.h @@ -59,7 +59,7 @@ public: } void Finalize(); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable ** ); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif SQInteger Next(const SQObjectPtr &refpos, SQObjectPtr &outkey, SQObjectPtr &outval); SQInstance *CreateInstance(); @@ -126,31 +126,33 @@ public: } return false; } - void Release() { + void Release() override { _uiRef++; try { if (_hook) { _hook(_userpointer,0);} } catch (...) { _uiRef--; if (_uiRef == 0) { - SQInteger size = _memsize; - this->~SQInstance(); - SQ_FREE(this, size); + this->_sharedstate->DelayFinalFree(this); } throw; } _uiRef--; if(_uiRef > 0) return; + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override + { SQInteger size = _memsize; this->~SQInstance(); SQ_FREE(this, size); } - void Finalize(); + void Finalize() override; #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable ** ); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif bool InstanceOf(SQClass *trg); - bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res); + bool GetMetaMethod(SQVM *v,SQMetaMethod mm,SQObjectPtr &res) override; SQClass *_class; SQUserPointer _userpointer; diff --git a/src/3rdparty/squirrel/squirrel/sqclosure.h b/src/3rdparty/squirrel/squirrel/sqclosure.h index a42dcd575a..8480fb8af2 100644 --- a/src/3rdparty/squirrel/squirrel/sqclosure.h +++ b/src/3rdparty/squirrel/squirrel/sqclosure.h @@ -32,7 +32,7 @@ public: bool Save(SQVM *v,SQUserPointer up,SQWRITEFUNC write); static bool Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &ret); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_outervalues.resize(0); } #endif SQObjectPtr _env; @@ -66,7 +66,7 @@ public: bool Yield(SQVM *v); bool Resume(SQVM *v,SQInteger target); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_stack.resize(0);_closure=_null_;} #endif SQObjectPtr _closure; @@ -106,7 +106,7 @@ public: sq_delete(this,SQNativeClosure); } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){_outervalues.resize(0);} #endif SQInteger _nparamscheck; diff --git a/src/3rdparty/squirrel/squirrel/sqobject.cpp b/src/3rdparty/squirrel/squirrel/sqobject.cpp index d48baca1e9..a113f316de 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.cpp +++ b/src/3rdparty/squirrel/squirrel/sqobject.cpp @@ -486,104 +486,81 @@ bool SQFunctionProto::Load(SQVM *v,SQUserPointer up,SQREADFUNC read,SQObjectPtr #ifndef NO_GARBAGE_COLLECTOR -#define START_MARK() if(!(_uiRef&MARK_FLAG)){ \ - _uiRef|=MARK_FLAG; - -#define END_MARK() RemoveFromChain(&_sharedstate->_gc_chain, this); \ - AddToChain(chain, this); } - -void SQVM::Mark(SQCollectable **chain) +void SQVM::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - SQSharedState::MarkObject(_lasterror,chain); - SQSharedState::MarkObject(_errorhandler,chain); - SQSharedState::MarkObject(_debughook,chain); - SQSharedState::MarkObject(_roottable, chain); - SQSharedState::MarkObject(temp_reg, chain); - for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::MarkObject(_callsstack[k]._closure, chain); - END_MARK() + SQSharedState::EnqueueMarkObject(_lasterror,queue); + SQSharedState::EnqueueMarkObject(_errorhandler,queue); + SQSharedState::EnqueueMarkObject(_debughook,queue); + SQSharedState::EnqueueMarkObject(_roottable, queue); + SQSharedState::EnqueueMarkObject(temp_reg, queue); + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::EnqueueMarkObject(_stack[i], queue); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::EnqueueMarkObject(_vargsstack[j], queue); + for(SQInteger k = 0; k < _callsstacksize; k++) SQSharedState::EnqueueMarkObject(_callsstack[k]._closure, queue); } -void SQArray::Mark(SQCollectable **chain) +void SQArray::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - SQInteger len = _values.size(); - for(SQInteger i = 0;i < len; i++) SQSharedState::MarkObject(_values[i], chain); - END_MARK() -} -void SQTable::Mark(SQCollectable **chain) -{ - START_MARK() - if(_delegate) _delegate->Mark(chain); - SQInteger len = _numofnodes; - for(SQInteger i = 0; i < len; i++){ - SQSharedState::MarkObject(_nodes[i].key, chain); - SQSharedState::MarkObject(_nodes[i].val, chain); - } - END_MARK() + SQInteger len = _values.size(); + for(SQInteger i = 0;i < len; i++) SQSharedState::EnqueueMarkObject(_values[i], queue); } -void SQClass::Mark(SQCollectable **chain) +void SQTable::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - _members->Mark(chain); - if(_base) _base->Mark(chain); - SQSharedState::MarkObject(_attributes, chain); - for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { - SQSharedState::MarkObject(_defaultvalues[i].val, chain); - SQSharedState::MarkObject(_defaultvalues[i].attrs, chain); - } - for(SQUnsignedInteger j =0; j< _methods.size(); j++) { - SQSharedState::MarkObject(_methods[j].val, chain); - SQSharedState::MarkObject(_methods[j].attrs, chain); - } - for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { - SQSharedState::MarkObject(_metamethods[k], chain); - } - END_MARK() + if(_delegate) queue.Enqueue(_delegate); + SQInteger len = _numofnodes; + for(SQInteger i = 0; i < len; i++){ + SQSharedState::EnqueueMarkObject(_nodes[i].key, queue); + SQSharedState::EnqueueMarkObject(_nodes[i].val, queue); + } } -void SQInstance::Mark(SQCollectable **chain) +void SQClass::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - _class->Mark(chain); - SQUnsignedInteger nvalues = _class->_defaultvalues.size(); - for(SQUnsignedInteger i =0; i< nvalues; i++) { - SQSharedState::MarkObject(_values[i], chain); - } - END_MARK() + queue.Enqueue(_members); + if(_base) queue.Enqueue(_base); + SQSharedState::EnqueueMarkObject(_attributes, queue); + for(SQUnsignedInteger i =0; i< _defaultvalues.size(); i++) { + SQSharedState::EnqueueMarkObject(_defaultvalues[i].val, queue); + SQSharedState::EnqueueMarkObject(_defaultvalues[i].attrs, queue); + } + for(SQUnsignedInteger j =0; j< _methods.size(); j++) { + SQSharedState::EnqueueMarkObject(_methods[j].val, queue); + SQSharedState::EnqueueMarkObject(_methods[j].attrs, queue); + } + for(SQUnsignedInteger k =0; k< _metamethods.size(); k++) { + SQSharedState::EnqueueMarkObject(_metamethods[k], queue); + } } -void SQGenerator::Mark(SQCollectable **chain) +void SQInstance::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::MarkObject(_stack[i], chain); - for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::MarkObject(_vargsstack[j], chain); - SQSharedState::MarkObject(_closure, chain); - END_MARK() + queue.Enqueue(_class); + SQUnsignedInteger nvalues = _class->_defaultvalues.size(); + for(SQUnsignedInteger i =0; i< nvalues; i++) { + SQSharedState::EnqueueMarkObject(_values[i], queue); + } } -void SQClosure::Mark(SQCollectable **chain) +void SQGenerator::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::MarkObject(_defaultparams[i], chain); - END_MARK() + for(SQUnsignedInteger i = 0; i < _stack.size(); i++) SQSharedState::EnqueueMarkObject(_stack[i], queue); + for(SQUnsignedInteger j = 0; j < _vargsstack.size(); j++) SQSharedState::EnqueueMarkObject(_vargsstack[j], queue); + SQSharedState::EnqueueMarkObject(_closure, queue); } -void SQNativeClosure::Mark(SQCollectable **chain) +void SQClosure::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) { - START_MARK() - for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::MarkObject(_outervalues[i], chain); - END_MARK() + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::EnqueueMarkObject(_outervalues[i], queue); + for(SQUnsignedInteger i = 0; i < _defaultparams.size(); i++) SQSharedState::EnqueueMarkObject(_defaultparams[i], queue); } -void SQUserData::Mark(SQCollectable **chain){ - START_MARK() - if(_delegate) _delegate->Mark(chain); - END_MARK() +void SQNativeClosure::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) +{ + for(SQUnsignedInteger i = 0; i < _outervalues.size(); i++) SQSharedState::EnqueueMarkObject(_outervalues[i], queue); +} + +void SQUserData::EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue){ + if(_delegate) queue.Enqueue(_delegate); } void SQCollectable::UnMark() { _uiRef&=~MARK_FLAG; } diff --git a/src/3rdparty/squirrel/squirrel/sqobject.h b/src/3rdparty/squirrel/squirrel/sqobject.h index 0b4576f3d4..9212766eef 100644 --- a/src/3rdparty/squirrel/squirrel/sqobject.h +++ b/src/3rdparty/squirrel/squirrel/sqobject.h @@ -2,7 +2,7 @@ #ifndef _SQOBJECT_H_ #define _SQOBJECT_H_ -#include +#include #include "squtils.h" #define SQ_CLOSURESTREAM_HEAD (('S'<<24)|('Q'<<16)|('I'<<8)|('R')) @@ -345,11 +345,54 @@ struct SQCollectable : public SQRefCounted { SQCollectable *_prev; SQSharedState *_sharedstate; virtual void Release()=0; - virtual void Mark(SQCollectable **chain)=0; + virtual void EnqueueMarkObjectForChildren(class SQGCMarkerQueue &queue)=0; void UnMark(); virtual void Finalize()=0; static void AddToChain(SQCollectable **chain,SQCollectable *c); static void RemoveFromChain(SQCollectable **chain,SQCollectable *c); + + /** + * Helper to perform the final memory freeing of this instance. Since the destructor might + * release more objects, this can cause a very deep recursion. As such, the calls to this + * are to be done via _sharedstate->DelayFinalFree which ensures the calls to this method + * are done in an iterative instead of recursive approach. + */ + virtual void FinalFree() {} +}; + +/** + * Helper container for state to change the garbage collection from a recursive to an iterative approach. + * The iterative approach provides effectively a depth first search approach. + */ +class SQGCMarkerQueue { + std::vector stack; ///< The elements to still process, with the most recent elements at the back. +public: + /** Whether there are any elements left to process. */ + bool IsEmpty() { return this->stack.empty(); } + + /** + * Remove the most recently added element from the queue. + * Removal when the queue is empty results in undefined behaviour. + */ + SQCollectable *Pop() + { + SQCollectable *collectable = this->stack.back(); + this->stack.pop_back(); + return collectable; + } + + /** + * Add a collectable to the queue, but only when it has not been marked yet. + * When adding it to the queue, the collectable will be marked, so subsequent calls + * will not add it again. + */ + void Enqueue(SQCollectable *collectable) + { + if ((collectable->_uiRef & MARK_FLAG) == 0) { + collectable->_uiRef |= MARK_FLAG; + this->stack.push_back(collectable); + } + } }; diff --git a/src/3rdparty/squirrel/squirrel/sqstate.cpp b/src/3rdparty/squirrel/squirrel/sqstate.cpp index 8233ad1789..31345d6640 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.cpp +++ b/src/3rdparty/squirrel/squirrel/sqstate.cpp @@ -99,6 +99,7 @@ SQSharedState::SQSharedState() _notifyallexceptions = false; _scratchpad=NULL; _scratchpadsize=0; + _collectable_free_processing = false; #ifndef NO_GARBAGE_COLLECTOR _gc_chain=NULL; #endif @@ -226,20 +227,48 @@ SQInteger SQSharedState::GetMetaMethodIdxByName(const SQObjectPtr &name) return -1; } +/** + * Helper function that is to be used instead of calling FinalFree directly on the instance, + * so the frees can happen iteratively. This as in the FinalFree the references to any other + * objects are released, which can cause those object to be freed yielding a potentially + * very deep stack in case of for example a link list. + * + * This is done internally by a vector onto which the to be freed instances are pushed. When + * this is called when not already processing, this method will actually call the FinalFree + * function which might cause more elements to end up in the queue which this method then + * picks up continueing until it has processed all instances in that queue. + * @param collectable The collectable to (eventually) free. + */ +void SQSharedState::DelayFinalFree(SQCollectable *collectable) +{ + this->_collectable_free_queue.push_back(collectable); + + if (!this->_collectable_free_processing) { + this->_collectable_free_processing = true; + while (!this->_collectable_free_queue.empty()) { + SQCollectable *collectable = this->_collectable_free_queue.back(); + this->_collectable_free_queue.pop_back(); + collectable->FinalFree(); + } + this->_collectable_free_processing = false; + } +} + + #ifndef NO_GARBAGE_COLLECTOR -void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) +void SQSharedState::EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue) { switch(type(o)){ - case OT_TABLE:_table(o)->Mark(chain);break; - case OT_ARRAY:_array(o)->Mark(chain);break; - case OT_USERDATA:_userdata(o)->Mark(chain);break; - case OT_CLOSURE:_closure(o)->Mark(chain);break; - case OT_NATIVECLOSURE:_nativeclosure(o)->Mark(chain);break; - case OT_GENERATOR:_generator(o)->Mark(chain);break; - case OT_THREAD:_thread(o)->Mark(chain);break; - case OT_CLASS:_class(o)->Mark(chain);break; - case OT_INSTANCE:_instance(o)->Mark(chain);break; + case OT_TABLE:queue.Enqueue(_table(o));break; + case OT_ARRAY:queue.Enqueue(_array(o));break; + case OT_USERDATA:queue.Enqueue(_userdata(o));break; + case OT_CLOSURE:queue.Enqueue(_closure(o));break; + case OT_NATIVECLOSURE:queue.Enqueue(_nativeclosure(o));break; + case OT_GENERATOR:queue.Enqueue(_generator(o));break; + case OT_THREAD:queue.Enqueue(_thread(o));break; + case OT_CLASS:queue.Enqueue(_class(o));break; + case OT_INSTANCE:queue.Enqueue(_instance(o));break; default: break; //shutup compiler } } @@ -248,27 +277,36 @@ void SQSharedState::MarkObject(SQObjectPtr &o,SQCollectable **chain) SQInteger SQSharedState::CollectGarbage(SQVM *vm) { SQInteger n=0; - SQCollectable *tchain=NULL; SQVM *vms = _thread(_root_vm); - vms->Mark(&tchain); + SQGCMarkerQueue queue; + queue.Enqueue(vms); #ifdef WITH_ASSERT SQInteger x = _table(_thread(_root_vm)->_roottable)->CountUsed(); #endif - _refs_table.Mark(&tchain); - MarkObject(_registry,&tchain); - MarkObject(_consts,&tchain); - MarkObject(_metamethodsmap,&tchain); - MarkObject(_table_default_delegate,&tchain); - MarkObject(_array_default_delegate,&tchain); - MarkObject(_string_default_delegate,&tchain); - MarkObject(_number_default_delegate,&tchain); - MarkObject(_generator_default_delegate,&tchain); - MarkObject(_thread_default_delegate,&tchain); - MarkObject(_closure_default_delegate,&tchain); - MarkObject(_class_default_delegate,&tchain); - MarkObject(_instance_default_delegate,&tchain); - MarkObject(_weakref_default_delegate,&tchain); + _refs_table.EnqueueMarkObject(queue); + EnqueueMarkObject(_registry,queue); + EnqueueMarkObject(_consts,queue); + EnqueueMarkObject(_metamethodsmap,queue); + EnqueueMarkObject(_table_default_delegate,queue); + EnqueueMarkObject(_array_default_delegate,queue); + EnqueueMarkObject(_string_default_delegate,queue); + EnqueueMarkObject(_number_default_delegate,queue); + EnqueueMarkObject(_generator_default_delegate,queue); + EnqueueMarkObject(_thread_default_delegate,queue); + EnqueueMarkObject(_closure_default_delegate,queue); + EnqueueMarkObject(_class_default_delegate,queue); + EnqueueMarkObject(_instance_default_delegate,queue); + EnqueueMarkObject(_weakref_default_delegate,queue); + + SQCollectable *tchain=NULL; + + while (!queue.IsEmpty()) { + SQCollectable *q = queue.Pop(); + q->EnqueueMarkObjectForChildren(queue); + SQCollectable::RemoveFromChain(&_gc_chain, q); + SQCollectable::AddToChain(&tchain, q); + } SQCollectable *t = _gc_chain; SQCollectable *nx = NULL; @@ -357,12 +395,12 @@ RefTable::~RefTable() } #ifndef NO_GARBAGE_COLLECTOR -void RefTable::Mark(SQCollectable **chain) +void RefTable::EnqueueMarkObject(SQGCMarkerQueue &queue) { RefNode *nodes = (RefNode *)_nodes; for(SQUnsignedInteger n = 0; n < _numofslots; n++) { if(type(nodes->obj) != OT_NULL) { - SQSharedState::MarkObject(nodes->obj,chain); + SQSharedState::EnqueueMarkObject(nodes->obj,queue); } nodes++; } diff --git a/src/3rdparty/squirrel/squirrel/sqstate.h b/src/3rdparty/squirrel/squirrel/sqstate.h index da6bf9ae64..547e6de47d 100644 --- a/src/3rdparty/squirrel/squirrel/sqstate.h +++ b/src/3rdparty/squirrel/squirrel/sqstate.h @@ -34,7 +34,7 @@ struct RefTable { void AddRef(SQObject &obj); SQBool Release(SQObject &obj); #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObject(SQGCMarkerQueue &queue); #endif void Finalize(); private: @@ -61,9 +61,10 @@ struct SQSharedState public: SQChar* GetScratchPad(SQInteger size); SQInteger GetMetaMethodIdxByName(const SQObjectPtr &name); + void DelayFinalFree(SQCollectable *collectable); #ifndef NO_GARBAGE_COLLECTOR SQInteger CollectGarbage(SQVM *vm); - static void MarkObject(SQObjectPtr &o,SQCollectable **chain); + static void EnqueueMarkObject(SQObjectPtr &o,SQGCMarkerQueue &queue); #endif SQObjectPtrVec *_metamethods; SQObjectPtr _metamethodsmap; @@ -74,6 +75,10 @@ public: SQObjectPtr _registry; SQObjectPtr _consts; SQObjectPtr _constructoridx; + /** Queue to make freeing of collectables iterative. */ + std::vector _collectable_free_queue; + /** Whether someone is already processing the _collectable_free_queue. */ + bool _collectable_free_processing; #ifndef NO_GARBAGE_COLLECTOR SQCollectable *_gc_chain; #endif diff --git a/src/3rdparty/squirrel/squirrel/sqtable.h b/src/3rdparty/squirrel/squirrel/sqtable.h index 52d9ba41ab..fad2fdc605 100644 --- a/src/3rdparty/squirrel/squirrel/sqtable.h +++ b/src/3rdparty/squirrel/squirrel/sqtable.h @@ -50,7 +50,7 @@ public: newtable->_delegate = NULL; return newtable; } - void Finalize(); + void Finalize() override; SQTable *Clone(); ~SQTable() { @@ -60,7 +60,7 @@ public: SQ_FREE(_nodes, _numofnodes * sizeof(_HashNode)); } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue) override; #endif inline _HashNode *_Get(const SQObjectPtr &key,SQHash hash) { @@ -81,7 +81,11 @@ public: SQInteger CountUsed(){ return _usednodes;} void Clear(); - void Release() + void Release() override + { + this->_sharedstate->DelayFinalFree(this); + } + void FinalFree() override { sq_delete(this, SQTable); } diff --git a/src/3rdparty/squirrel/squirrel/squserdata.h b/src/3rdparty/squirrel/squirrel/squserdata.h index 3bf1a9dbad..ca4933de2d 100644 --- a/src/3rdparty/squirrel/squirrel/squserdata.h +++ b/src/3rdparty/squirrel/squirrel/squserdata.h @@ -18,7 +18,7 @@ struct SQUserData : SQDelegable return ud; } #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); void Finalize(){SetDelegate(NULL);} #endif void Release() { diff --git a/src/3rdparty/squirrel/squirrel/sqvm.h b/src/3rdparty/squirrel/squirrel/sqvm.h index 9c8e986fbc..dbfe2309c7 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.h +++ b/src/3rdparty/squirrel/squirrel/sqvm.h @@ -113,7 +113,7 @@ public: #endif #ifndef NO_GARBAGE_COLLECTOR - void Mark(SQCollectable **chain); + void EnqueueMarkObjectForChildren(SQGCMarkerQueue &queue); #endif void Finalize(); void GrowCallStack() { diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index e360cedb88..7cace3fc11 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -192,7 +192,7 @@ struct AIListWindow : public Window { { switch (widget) { case WID_AIL_LIST: { // Select one of the AIs - int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST, 0, this->line_height) - 1; + int sel = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_AIL_LIST) - 1; if (sel < (int)this->info_list->size()) { this->selected = sel; this->SetDirty(); @@ -691,31 +691,20 @@ static const NWidgetPart _nested_ai_config_widgets[] = { EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), - NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetFill(0, 1), SetDataTip(AWV_DECREASE, STR_NULL), - NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetFill(0, 1), SetDataTip(AWV_INCREASE, STR_NULL), - NWidget(NWID_SPACER), SetMinimalSize(6, 0), - NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_DIFFICULTY_LEVEL_SETTING_MAXIMUM_NO_COMPETITORS, STR_NULL), SetFill(1, 0), SetPadding(1, 0, 0, 0), - EndContainer(), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 9), NWidget(WWT_FRAME, COLOUR_MAUVE), SetDataTip(STR_AI_CONFIG_GAMESCRIPT, STR_NULL), SetPadding(0, 5, 4, 5), - NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetSizingType(NWST_STEP), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), + NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_AIC_GAMELIST), SetMinimalSize(288, 14), SetFill(1, 0), SetMatrixDataTip(1, 1, STR_AI_CONFIG_GAMELIST_TOOLTIP), EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 12), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), - EndContainer(), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CHANGE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_CONFIG_CHANGE, STR_AI_CONFIG_CHANGE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONFIGURE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_CONFIG_CONFIGURE, STR_AI_CONFIG_CONFIGURE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CLOSE), SetFill(1, 0), SetMinimalSize(93, 0), SetDataTip(STR_AI_SETTINGS_CLOSE, STR_NULL), + EndContainer(), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_README, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_CHANGELOG, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TEXTFILE_VIEW_LICENCE, STR_NULL), EndContainer(), - NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 12), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_CONTENT_DOWNLOAD), SetFill(1, 0), SetMinimalSize(279, 0), SetPadding(0, 7, 9, 7), SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT), EndContainer(), EndContainer(), EndContainer(), @@ -787,7 +776,9 @@ struct AIConfigWindow : public Window { break; case WID_AIC_LIST: - this->line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); + this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + this->line_height = GetMinSizing(NWST_STEP, this->line_height); + resize->height = this->line_height; size->height = 8 * this->line_height; break; @@ -899,7 +890,7 @@ struct AIConfigWindow : public Window { } case WID_AIC_LIST: { // Select a slot - this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget, 0, this->line_height); + this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget); this->InvalidateData(); if (click_count > 1 && this->selected_slot != INVALID_COMPANY) ShowAIListWindow((CompanyID)this->selected_slot); break; diff --git a/src/autoreplace.cpp b/src/autoreplace.cpp index 59980546ee..e1b73448dd 100644 --- a/src/autoreplace.cpp +++ b/src/autoreplace.cpp @@ -11,6 +11,7 @@ #include "command_func.h" #include "group.h" #include "autoreplace_base.h" +#include "core/bitmath_func.hpp" #include "core/pool_func.hpp" #include "safeguards.h" @@ -64,7 +65,7 @@ void RemoveAllEngineReplacement(EngineRenewList *erl) EngineID EngineReplacement(EngineRenewList erl, EngineID engine, GroupID group, bool *replace_when_old) { const EngineRenew *er = GetEngineReplacement(erl, engine, group); - if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !Group::Get(group)->replace_protection))) { + if (er == nullptr && (group == DEFAULT_GROUP || (Group::IsValidID(group) && !HasBit(Group::Get(group)->flags, GroupFlags::GF_REPLACE_PROTECTION)))) { /* We didn't find anything useful in the vehicle's own group so we will try ALL_GROUP */ er = GetEngineReplacement(erl, engine, ALL_GROUP); } diff --git a/src/autoreplace_cmd.cpp b/src/autoreplace_cmd.cpp index fe86917c77..d9996bb117 100644 --- a/src/autoreplace_cmd.cpp +++ b/src/autoreplace_cmd.cpp @@ -741,6 +741,9 @@ CommandCost CmdAutoreplaceVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1 const Company *c = Company::Get(_current_company); bool wagon_removal = c->settings.renew_keep_length; + const Group *g = Group::GetIfValid(v->group_id); + if (g != nullptr) wagon_removal = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + /* Test whether any replacement is set, before issuing a whole lot of commands that would end in nothing changed */ Vehicle *w = v; bool any_replacements = false; diff --git a/src/autoreplace_gui.cpp b/src/autoreplace_gui.cpp index b42d645f0a..3e514829b4 100644 --- a/src/autoreplace_gui.cpp +++ b/src/autoreplace_gui.cpp @@ -82,7 +82,7 @@ class ReplaceVehicleWindow : public Window { bool replace_engines; ///< If \c true, engines are replaced, if \c false, wagons are replaced (only for trains). bool reset_sel_engine; ///< Also reset #sel_engine while updating left and/or right and no valid engine selected. GroupID sel_group; ///< Group selected to replace. - int details_height; ///< Minimal needed height of the details panels (found so far). + int details_height; ///< Minimal needed height of the details panels, in text lines (found so far). byte sort_criteria; ///< Criteria of sorting vehicles. bool descending_sort_order; ///< Order of sorting vehicles. bool show_hidden_engines; ///< Whether to show the hidden engines. @@ -230,7 +230,7 @@ public: this->engines[0].ForceRebuild(); this->engines[1].ForceRebuild(); this->reset_sel_engine = true; - this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->details_height = ((vehicletype == VEH_TRAIN) ? 10 : 9); this->sel_engine[0] = INVALID_ENGINE; this->sel_engine[1] = INVALID_ENGINE; this->show_hidden_engines = _engine_sort_show_hidden_engines[vehicletype]; @@ -275,7 +275,7 @@ public: case WID_RV_LEFT_DETAILS: case WID_RV_RIGHT_DETAILS: - size->height = this->details_height; + size->height = FONT_HEIGHT_NORMAL * this->details_height + padding.height; break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { @@ -378,8 +378,15 @@ public: break; case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { - const Company *c = Company::Get(_local_company); - SetDParam(0, c->settings.renew_keep_length ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); + bool remove_wagon; + const Group *g = Group::GetIfValid(this->sel_group); + if (g != nullptr) { + remove_wagon = HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + } else { + const Company *c = Company::Get(_local_company); + remove_wagon = c->settings.renew_keep_length; + } + SetDParam(0, remove_wagon ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF); break; } @@ -478,7 +485,7 @@ public: NWidgetBase *nwi = this->GetWidget(side == 0 ? WID_RV_LEFT_DETAILS : WID_RV_RIGHT_DETAILS); int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine[side], ted); - needed_height = std::max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + needed_height = std::max(needed_height, (text_end - (int)nwi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL); } } if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. @@ -531,9 +538,16 @@ public: } break; - case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: // toggle renew_keep_length - DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); + case WID_RV_TRAIN_WAGONREMOVE_TOGGLE: { + const Group *g = Group::GetIfValid(this->sel_group); + if (g != nullptr) { + DoCommandP(0, this->sel_group | (GroupFlags::GF_REPLACE_WAGON_REMOVAL << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL) ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_FLAG); + } else { + // toggle renew_keep_length + DoCommandP(0, GetCompanySettingIndex("company.renew_keep_length"), Company::Get(_local_company)->settings.renew_keep_length ? 0 : 1, CMD_CHANGE_COMPANY_SETTING); + } break; + } case WID_RV_START_REPLACE: { // Start replacing if (this->GetWidget(widget)->ButtonHit(pt)) { diff --git a/src/base_media_func.h b/src/base_media_func.h index 8491f0e510..f5a5995f17 100644 --- a/src/base_media_func.h +++ b/src/base_media_func.h @@ -274,7 +274,7 @@ template return p; } -#include "network/network_content.h" +#include "network/core/tcp_content_type.h" template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s) { diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index 20d75c2318..e563ad97ad 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1061,7 +1061,7 @@ struct BuildVehicleWindow : Window { CargoID cargo_filter[NUM_CARGO + 3]; ///< Available cargo filters; CargoID or CF_ANY or CF_NONE or CF_ENGINES StringID cargo_filter_texts[NUM_CARGO + 4]; ///< Texts for filter_cargo, terminated by INVALID_STRING_ID byte cargo_filter_criteria; ///< Selected cargo filter - int details_height; ///< Minimal needed height of the details panels (found so far). + int details_height; ///< Minimal needed height of the details panels, in text lines (found so far). Scrollbar *vscroll; TestedEngineDetails te; ///< Tested cost and capacity after refit. @@ -1121,7 +1121,7 @@ struct BuildVehicleWindow : Window { widget->tool_tip = STR_SHOW_HIDDEN_ENGINES_VEHICLE_TRAIN_TOOLTIP + type; widget->SetLowered(this->show_hidden_engines); - this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9); this->FinishInitNested(tile == INVALID_TILE ? (int)type : tile); @@ -1559,7 +1559,7 @@ struct BuildVehicleWindow : Window { break; case WID_BV_PANEL: - size->height = this->details_height; + size->height = FONT_HEIGHT_NORMAL * this->details_height + padding.height; break; case WID_BV_SORT_ASCENDING_DESCENDING: { @@ -1627,12 +1627,12 @@ struct BuildVehicleWindow : Window { NWidgetBase *nwi = this->GetWidget(WID_BV_PANEL); int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT, nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine, this->te); - needed_height = std::max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM); + needed_height = std::max(needed_height, (text_end - (int)nwi->pos_y - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL); } if (needed_height != this->details_height) { // Details window are not high enough, enlarge them. int resize = needed_height - this->details_height; this->details_height = needed_height; - this->ReInit(0, resize); + this->ReInit(0, resize * FONT_HEIGHT_NORMAL); return; } } diff --git a/src/cargotype.cpp b/src/cargotype.cpp index e30b9899f1..bf9561dda8 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -84,8 +84,7 @@ void SetupCargoForClimate(LandscapeID l) */ CargoID GetCargoIDByLabel(CargoLabel cl) { - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (cs->label == cl) return cs->Index(); } @@ -103,8 +102,7 @@ CargoID GetCargoIDByBitnum(uint8 bitnum) { if (bitnum == INVALID_CARGO) return CT_INVALID; - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (cs->bitnum == bitnum) return cs->Index(); } @@ -132,7 +130,6 @@ SpriteID CargoSpec::GetCargoIcon() const std::vector _sorted_cargo_specs; ///< Cargo specifications sorted alphabetically by name. uint8 _sorted_standard_cargo_specs_size; ///< Number of standard cargo specifications stored in the _sorted_cargo_specs array. - /** Sort cargo specifications by their name. */ static bool CargoSpecNameSorter(const CargoSpec * const &a, const CargoSpec * const &b) { @@ -169,9 +166,8 @@ static bool CargoSpecClassSorter(const CargoSpec * const &a, const CargoSpec * c void InitializeSortedCargoSpecs() { _sorted_cargo_specs.clear(); - const CargoSpec *cargo; /* Add each cargo spec to the list. */ - FOR_ALL_CARGOSPECS(cargo) { + for (const CargoSpec *cargo : CargoSpec::Iterate()) { _sorted_cargo_specs.push_back(cargo); } @@ -181,7 +177,7 @@ void InitializeSortedCargoSpecs() _standard_cargo_mask = 0; _sorted_standard_cargo_specs_size = 0; - FOR_ALL_SORTED_CARGOSPECS(cargo) { + for (const auto &cargo : _sorted_cargo_specs) { if (cargo->classes & CC_SPECIAL) break; _sorted_standard_cargo_specs_size++; SetBit(_standard_cargo_mask, cargo->Index()); diff --git a/src/cargotype.h b/src/cargotype.h index 9645bf7c59..4a295f1ae5 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -59,7 +59,7 @@ struct CargoSpec { uint8 rating_colour; uint8 weight; ///< Weight of a single unit of this cargo type in 1/16 ton (62.5 kg). uint16 multiplier; ///< Capacity multiplier for vehicles. (8 fractional bits) - uint16 initial_payment; + uint32 initial_payment; ///< Initial payment rate before inflation is applied. uint8 transit_days[2]; bool is_freight; ///< Cargo type is considered to be freight (affects train freight multiplier). @@ -122,6 +122,49 @@ struct CargoSpec { SpriteID GetCargoIcon() const; + /** + * Iterator to iterate all valid CargoSpec + */ + struct Iterator { + typedef CargoSpec value_type; + typedef CargoSpec *pointer; + typedef CargoSpec &reference; + typedef size_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit Iterator(size_t index) : index(index) + { + this->ValidateIndex(); + }; + + bool operator==(const Iterator &other) const { return this->index == other.index; } + bool operator!=(const Iterator &other) const { return !(*this == other); } + CargoSpec * operator*() const { return CargoSpec::Get(this->index); } + Iterator & operator++() { this->index++; this->ValidateIndex(); return *this; } + + private: + size_t index; + void ValidateIndex() { while (this->index < CargoSpec::GetArraySize() && !(CargoSpec::Get(this->index)->IsValid())) this->index++; } + }; + + /* + * Iterable ensemble of all valid CargoSpec + */ + struct IterateWrapper { + size_t from; + IterateWrapper(size_t from = 0) : from(from) {} + Iterator begin() { return Iterator(this->from); } + Iterator end() { return Iterator(CargoSpec::GetArraySize()); } + bool empty() { return this->begin() == this->end(); } + }; + + /** + * Returns an iterable ensemble of all valid CargoSpec + * @param from index of the first CargoSpec to consider + * @return an iterable ensemble of all valid CargoSpec + */ + static IterateWrapper Iterate(size_t from = 0) { return IterateWrapper(from); } + private: static CargoSpec array[NUM_CARGO]; ///< Array holding all CargoSpecs @@ -150,19 +193,8 @@ static inline bool IsCargoInClass(CargoID c, CargoClass cc) return (CargoSpec::Get(c)->classes & cc) != 0; } -#define FOR_ALL_CARGOSPECS_FROM(var, start) for (size_t cargospec_index = start; var = nullptr, cargospec_index < CargoSpec::GetArraySize(); cargospec_index++) \ - if ((var = CargoSpec::Get(cargospec_index))->IsValid()) -#define FOR_ALL_CARGOSPECS(var) FOR_ALL_CARGOSPECS_FROM(var, 0) - #define FOR_EACH_SET_CARGO_ID(var, cargo_bits) FOR_EACH_SET_BIT_EX(CargoID, var, CargoTypes, cargo_bits) -/** - * Loop header for iterating over cargoes, sorted by name. This includes phony cargoes like regearing cargoes. - * @param var Reference getting the cargospec. - * @see CargoSpec - */ -#define FOR_ALL_SORTED_CARGOSPECS(var) for (uint8 index = 0; index < _sorted_cargo_specs.size() && (var = _sorted_cargo_specs[index], true) ; index++) - /** * Loop header for iterating over 'real' cargoes, sorted by name. Phony cargoes like regearing cargoes are skipped. * @param var Reference getting the cargospec. diff --git a/src/command.cpp b/src/command.cpp index 22b0cee4ae..cbebb35730 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -196,7 +196,7 @@ CommandProc CmdDeleteGroup; CommandProc CmdAddVehicleGroup; CommandProc CmdAddSharedVehicleGroup; CommandProc CmdRemoveAllVehiclesGroup; -CommandProc CmdSetGroupReplaceProtection; +CommandProc CmdSetGroupFlag; CommandProc CmdSetGroupLivery; CommandProc CmdMoveOrder; @@ -362,7 +362,7 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdAddVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_VEHICLE_GROUP DEF_CMD(CmdAddSharedVehicleGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_ADD_SHARE_VEHICLE_GROUP DEF_CMD(CmdRemoveAllVehiclesGroup, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_REMOVE_ALL_VEHICLES_GROUP - DEF_CMD(CmdSetGroupReplaceProtection, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_REPLACE_PROTECTION + DEF_CMD(CmdSetGroupFlag, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_FLAG DEF_CMD(CmdSetGroupLivery, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_SET_GROUP_LIVERY DEF_CMD(CmdMoveOrder, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_MOVE_ORDER DEF_CMD(CmdChangeTimetable, 0, CMDT_ROUTE_MANAGEMENT ), // CMD_CHANGE_TIMETABLE diff --git a/src/command_type.h b/src/command_type.h index 2419d7b312..732932b7a8 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -324,7 +324,7 @@ enum Commands { CMD_ADD_VEHICLE_GROUP, ///< add a vehicle to a group CMD_ADD_SHARED_VEHICLE_GROUP, ///< add all other shared vehicles to a group which are missing CMD_REMOVE_ALL_VEHICLES_GROUP, ///< remove all vehicles from a group - CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group + CMD_SET_GROUP_FLAG, ///< set/clear a flag for a group CMD_SET_GROUP_LIVERY, ///< set the livery for a group CMD_MOVE_ORDER, ///< move an order diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp index ab9e7e12ef..063d32d3f3 100644 --- a/src/company_cmd.cpp +++ b/src/company_cmd.cpp @@ -571,8 +571,7 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY) GeneratePresidentName(c); SetWindowDirty(WC_GRAPH_LEGEND, 0); - SetWindowClassesDirty(WC_CLIENT_LIST_POPUP); - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_LINKGRAPH_LEGEND, 0); BuildOwnerLegend(); InvalidateWindowData(WC_SMALLMAP, 0, 1); @@ -909,6 +908,8 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 CompanyAdminRemove(c_index, (CompanyRemoveReason)reason); if (StoryPage::GetNumItems() == 0 || Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); + break; } diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 20059829d6..e0f2b0aa95 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -243,10 +243,10 @@ static const NWidgetPart _nested_company_finances_widgets[] = { EndContainer(), NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0), NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total. - NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL), - NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT), NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0), - NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN), NWidget(NWID_HORIZONTAL), @@ -293,6 +293,24 @@ struct CompanyFinancesWindow : Window { SetDParam(1, (CompanyID)this->window_number); break; + case WID_CF_BALANCE_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->money); + break; + } + + case WID_CF_LOAN_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->current_loan); + break; + } + + case WID_CF_TOTAL_VALUE: { + const Company *c = Company::Get((CompanyID)this->window_number); + SetDParam(0, c->money - c->current_loan); + break; + } + case WID_CF_MAXLOAN_VALUE: SetDParam(0, _economy.max_loan); break; @@ -351,27 +369,6 @@ struct CompanyFinancesWindow : Window { break; } - case WID_CF_BALANCE_VALUE: { - const Company *c = Company::Get((CompanyID)this->window_number); - SetDParam(0, c->money); - DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); - break; - } - - case WID_CF_LOAN_VALUE: { - const Company *c = Company::Get((CompanyID)this->window_number); - SetDParam(0, c->current_loan); - DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); - break; - } - - case WID_CF_TOTAL_VALUE: { - const Company *c = Company::Get((CompanyID)this->window_number); - SetDParam(0, c->money - c->current_loan); - DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT); - break; - } - case WID_CF_LOAN_LINE: GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK); break; @@ -957,7 +954,7 @@ public: break; case WID_SCL_MATRIX: { - uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX, 0, this->line_height); + uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SCL_MATRIX); if (row >= this->rows) return; if (this->livery_class < LC_GROUP_RAIL) { @@ -1176,107 +1173,112 @@ static const NWidgetPart _nested_select_company_manager_face_widgets[] = { EndContainer(), EndContainer(), EndContainer(), - - NWidget(NWID_HORIZONTAL), - NWidget(NWID_SPACER), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetFill(0, 1), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting. - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), - NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(NWID_VERTICAL), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + NWidget(NWID_SPACER), SetFill(0, 1), + EndContainer(), + EndContainer(), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. + NWidget(NWID_VERTICAL), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_HAIR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_EYEBROWS, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_NOSE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_MOUSTACHE, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_CHIN, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_JACKET, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_COLLAR, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting. NWidget(NWID_HORIZONTAL), - NWidget(NWID_VERTICAL), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 4), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetSizingType(NWST_STEP), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetSizingType(NWST_STEP), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), - NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetSizingType(NWST_STEP), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), - EndContainer(), - EndContainer(), + NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT, 0, WD_FRAMERECT_LEFT), + SetDataTip(STR_FACE_EARRING, STR_NULL), SetTextColour(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP), + NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetFill(0, 1), EndContainer(), @@ -1305,9 +1307,6 @@ class SelectCompanyManagerFaceWindow : public Window Dimension yesno_dim; ///< Dimension of a yes/no button of a part in the advanced face window. Dimension number_dim; ///< Dimension of a number widget of a part in the advanced face window. - static const StringID PART_TEXTS_IS_FEMALE[]; ///< Strings depending on #is_female, used to describe parts (2 entries for a part). - static const StringID PART_TEXTS[]; ///< Fixed strings to describe parts of the face. - /** * Draw dynamic a label to the left of the button and a value in the button * @@ -1340,6 +1339,10 @@ class SelectCompanyManagerFaceWindow : public Window this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache + + this->GetWidget(WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_MOUSTACHE; + this->GetWidget(WID_SCMF_TIE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_TIE; + this->GetWidget(WID_SCMF_LIPS_MOUSTACHE_TEXT)->widget_data = this->is_moust_male ? STR_FACE_MOUSTACHE : STR_FACE_LIPS; } public: @@ -1405,6 +1408,21 @@ public: void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { + case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_EARRING)); + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_MOUSTACHE)); + break; + + case WID_SCMF_TIE_EARRING_TEXT: + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_EARRING)); + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_TIE)); + break; + + case WID_SCMF_LIPS_MOUSTACHE_TEXT: + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_LIPS)); + *size = maxdim(*size, GetStringBoundingBox(STR_FACE_MOUSTACHE)); + break; + case WID_SCMF_FACE: { Dimension face_size = GetSpriteSize(SPR_GRADIENT); size->width = std::max(size->width, face_size.width); @@ -1412,35 +1430,6 @@ public: break; } - case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: - case WID_SCMF_TIE_EARRING_TEXT: { - int offset = (widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2; - *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1])); - size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - } - - case WID_SCMF_LIPS_MOUSTACHE_TEXT: - *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE)); - size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - - case WID_SCMF_HAS_GLASSES_TEXT: - case WID_SCMF_HAIR_TEXT: - case WID_SCMF_EYEBROWS_TEXT: - case WID_SCMF_EYECOLOUR_TEXT: - case WID_SCMF_GLASSES_TEXT: - case WID_SCMF_NOSE_TEXT: - case WID_SCMF_CHIN_TEXT: - case WID_SCMF_JACKET_TEXT: - case WID_SCMF_COLLAR_TEXT: - *size = GetStringBoundingBox(PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT]); - size->width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - case WID_SCMF_HAS_MOUSTACHE_EARRING: case WID_SCMF_HAS_GLASSES: *size = this->yesno_dim; @@ -1525,30 +1514,6 @@ public: void DrawWidget(const Rect &r, int widget) const override { switch (widget) { - case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT: - case WID_SCMF_TIE_EARRING_TEXT: { - StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female]; - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), str, TC_GOLD, SA_RIGHT); - break; - } - - case WID_SCMF_LIPS_MOUSTACHE_TEXT: - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT); - break; - - case WID_SCMF_HAS_GLASSES_TEXT: - case WID_SCMF_HAIR_TEXT: - case WID_SCMF_EYEBROWS_TEXT: - case WID_SCMF_EYECOLOUR_TEXT: - case WID_SCMF_GLASSES_TEXT: - case WID_SCMF_NOSE_TEXT: - case WID_SCMF_CHIN_TEXT: - case WID_SCMF_JACKET_TEXT: - case WID_SCMF_COLLAR_TEXT: - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT); - break; - - case WID_SCMF_HAS_MOUSTACHE_EARRING: if (this->is_female) { // Only for female faces this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true); @@ -1736,25 +1701,6 @@ public: } }; -/** Both text values of parts of the face that depend on the #is_female boolean value. */ -const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = { - STR_FACE_MOUSTACHE, STR_FACE_EARRING, // WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT - STR_FACE_TIE, STR_FACE_EARRING, // WID_SCMF_TIE_EARRING_TEXT -}; - -/** Textual names for parts of the face. */ -const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = { - STR_FACE_GLASSES, // WID_SCMF_HAS_GLASSES_TEXT - STR_FACE_HAIR, // WID_SCMF_HAIR_TEXT - STR_FACE_EYEBROWS, // WID_SCMF_EYEBROWS_TEXT - STR_FACE_EYECOLOUR, // WID_SCMF_EYECOLOUR_TEXT - STR_FACE_GLASSES, // WID_SCMF_GLASSES_TEXT - STR_FACE_NOSE, // WID_SCMF_NOSE_TEXT - STR_FACE_CHIN, // WID_SCMF_CHIN_TEXT - STR_FACE_JACKET, // WID_SCMF_JACKET_TEXT - STR_FACE_COLLAR, // WID_SCMF_COLLAR_TEXT -}; - /** Company manager face selection window description */ static WindowDesc _select_company_manager_face_desc( WDP_AUTO, "company_face", 0, 0, @@ -1902,8 +1848,7 @@ struct CompanyInfrastructureWindow : Window size->width = std::max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width); - RailType rt; - FOR_ALL_SORTED_RAILTYPES(rt) { + for (const auto &rt : _sorted_railtypes) { if (HasBit(this->railtypes, rt)) { lines++; SetDParam(0, GetRailTypeInfo(rt)->strings.name); @@ -1925,8 +1870,7 @@ struct CompanyInfrastructureWindow : Window size->width = std::max(size->width, GetStringBoundingBox(widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT).width); - RoadType rt; - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { lines++; SetDParam(0, GetRoadTypeInfo(rt)->strings.name); @@ -2035,8 +1979,7 @@ struct CompanyInfrastructureWindow : Window if (this->railtypes != RAILTYPES_NONE) { /* Draw name of each valid railtype. */ - RailType rt; - FOR_ALL_SORTED_RAILTYPES(rt) { + for (const auto &rt : _sorted_railtypes) { if (HasBit(this->railtypes, rt)) { SetDParam(0, GetRailTypeInfo(rt)->strings.name); DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); @@ -2053,8 +1996,7 @@ struct CompanyInfrastructureWindow : Window case WID_CI_RAIL_COUNT: { /* Draw infrastructure count for each valid railtype. */ uint32 rail_total = c->infrastructure.GetRailTotal(); - RailType rt; - FOR_ALL_SORTED_RAILTYPES(rt) { + for (const auto &rt : _sorted_railtypes) { if (HasBit(this->railtypes, rt)) { this->DrawCountLine(r, y, c->infrastructure.rail[rt], RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); } @@ -2070,8 +2012,7 @@ struct CompanyInfrastructureWindow : Window DrawString(r.left, r.right, y, widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT); /* Draw name of each valid roadtype. */ - RoadType rt; - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { SetDParam(0, GetRoadTypeInfo(rt)->strings.name); DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING); @@ -2084,8 +2025,7 @@ struct CompanyInfrastructureWindow : Window case WID_CI_ROAD_COUNT: case WID_CI_TRAM_COUNT: { uint32 road_tram_total = widget == WID_CI_ROAD_COUNT ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal(); - RoadType rt; - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_COUNT)) { this->DrawCountLine(r, y, c->infrastructure.road[rt], RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_tram_total)); } diff --git a/src/console.cpp b/src/console.cpp index 3c782357d2..fbd34c1977 100644 --- a/src/console.cpp +++ b/src/console.cpp @@ -24,8 +24,17 @@ static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in on static const uint ICON_MAX_RECURSE = 10; ///< Maximum number of recursion /* console parser */ -IConsoleCmd *_iconsole_cmds; ///< list of registered commands -IConsoleAlias *_iconsole_aliases; ///< list of registered aliases +/* static */ IConsole::CommandList &IConsole::Commands() +{ + static IConsole::CommandList cmds; + return cmds; +} + +/* static */ IConsole::AliasList &IConsole::Aliases() +{ + static IConsole::AliasList aliases; + return aliases; +} FILE *_iconsole_output_file; @@ -195,49 +204,13 @@ bool GetArgumentInteger(uint32 *value, const char *arg) } /** - * Add an item to an alphabetically sorted list. - * @param base first item of the list - * @param item_new the item to add + * Creates a copy of a string with underscores removed from it + * @param name String to remove the underscores from. + * @return A copy of \a name, without underscores. */ -template -void IConsoleAddSorted(T **base, T *item_new) +static std::string RemoveUnderscores(std::string name) { - if (*base == nullptr) { - *base = item_new; - return; - } - - T *item_before = nullptr; - T *item = *base; - /* The list is alphabetically sorted, insert the new item at the correct location */ - while (item != nullptr) { - if (strcmp(item->name, item_new->name) > 0) break; // insert here - - item_before = item; - item = item->next; - } - - if (item_before == nullptr) { - *base = item_new; - } else { - item_before->next = item_new; - } - - item_new->next = item; -} - -/** - * Remove underscores from a string; the string will be modified! - * @param[in,out] name String to remove the underscores from. - * @return \a name, with its contents modified. - */ -char *RemoveUnderscores(char *name) -{ - char *q = name; - for (const char *p = name; *p != '\0'; p++) { - if (*p != '_') *q++ = *p; - } - *q = '\0'; + name.erase(std::remove(name.begin(), name.end(), '_'), name.end()); return name; } @@ -246,15 +219,9 @@ char *RemoveUnderscores(char *name) * @param name name of the command that will be used * @param proc function that will be called upon execution of command */ -void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook) +/* static */ void IConsole::CmdRegister(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook) { - IConsoleCmd *item_new = MallocT(1); - item_new->name = RemoveUnderscores(stredup(name)); - item_new->next = nullptr; - item_new->proc = proc; - item_new->hook = hook; - - IConsoleAddSorted(&_iconsole_cmds, item_new); + IConsole::Commands().try_emplace(RemoveUnderscores(name), name, proc, hook); } /** @@ -262,13 +229,10 @@ void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook * * @param name command to be found * @return return Cmdstruct of the found command, or nullptr on failure */ -IConsoleCmd *IConsoleCmdGet(const char *name) +/* static */ IConsoleCmd *IConsole::CmdGet(const std::string &name) { - IConsoleCmd *item; - - for (item = _iconsole_cmds; item != nullptr; item = item->next) { - if (strcmp(item->name, name) == 0) return item; - } + auto item = IConsole::Commands().find(RemoveUnderscores(name)); + if (item != IConsole::Commands().end()) return &item->second; return nullptr; } @@ -277,22 +241,10 @@ IConsoleCmd *IConsoleCmdGet(const char *name) * @param name name of the alias that will be used * @param cmd name of the command that 'name' will be alias of */ -void IConsoleAliasRegister(const char *name, const char *cmd) +/* static */ void IConsole::AliasRegister(const std::string &name, const std::string &cmd) { - if (IConsoleAliasGet(name) != nullptr) { - IConsoleError("an alias with this name already exists; insertion aborted"); - return; - } - - char *new_alias = RemoveUnderscores(stredup(name)); - char *cmd_aliased = stredup(cmd); - IConsoleAlias *item_new = MallocT(1); - - item_new->next = nullptr; - item_new->cmdline = cmd_aliased; - item_new->name = new_alias; - - IConsoleAddSorted(&_iconsole_aliases, item_new); + auto result = IConsole::Aliases().try_emplace(RemoveUnderscores(name), name, cmd); + if (!result.second) IConsoleError("an alias with this name already exists; insertion aborted"); } /** @@ -300,16 +252,13 @@ void IConsoleAliasRegister(const char *name, const char *cmd) * @param name alias to be found * @return return Aliasstruct of the found alias, or nullptr on failure */ -IConsoleAlias *IConsoleAliasGet(const char *name) +/* static */ IConsoleAlias *IConsole::AliasGet(const std::string &name) { - IConsoleAlias *item; - - for (item = _iconsole_aliases; item != nullptr; item = item->next) { - if (strcmp(item->name, name) == 0) return item; - } - + auto item = IConsole::Aliases().find(RemoveUnderscores(name)); + if (item != IConsole::Aliases().end()) return &item->second; return nullptr; } + /** * An alias is just another name for a command, or for more commands * Execute it as well. @@ -329,7 +278,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char return; } - for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) { + for (const char *cmdptr = alias->cmdline.c_str(); *cmdptr != '\0'; cmdptr++) { switch (*cmdptr) { case '\'': // ' will double for "" alias_stream = strecpy(alias_stream, "\"", lastof(alias_buffer)); @@ -372,7 +321,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char if (param < 0 || param >= tokencount) { IConsoleError("too many or wrong amount of parameters passed to alias, aborting"); - IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name, alias->cmdline); + IConsolePrintF(CC_WARNING, "Usage of alias '%s': %s", alias->name.c_str(), alias->cmdline.c_str()); return; } @@ -491,8 +440,7 @@ void IConsoleCmdExec(const char *cmdstr, const uint recurse_count) * First try commands, then aliases. Execute * the found action taking into account its hooking code */ - RemoveUnderscores(tokens[0]); - IConsoleCmd *cmd = IConsoleCmdGet(tokens[0]); + IConsoleCmd *cmd = IConsole::CmdGet(tokens[0]); if (cmd != nullptr) { ConsoleHookResult chr = (cmd->hook == nullptr ? CHR_ALLOW : cmd->hook(true)); switch (chr) { @@ -508,7 +456,7 @@ void IConsoleCmdExec(const char *cmdstr, const uint recurse_count) } t_index--; - IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); + IConsoleAlias *alias = IConsole::AliasGet(tokens[0]); if (alias != nullptr) { IConsoleAliasExec(alias, t_index, &tokens[1], recurse_count + 1); return; diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp index 5dc5581983..baec74c1aa 100644 --- a/src/console_cmds.cpp +++ b/src/console_cmds.cpp @@ -13,6 +13,7 @@ #include "engine_func.h" #include "landscape.h" #include "saveload/saveload.h" +#include "network/core/game_info.h" #include "network/network.h" #include "network/network_func.h" #include "network/network_base.h" @@ -58,7 +59,7 @@ public: /** Declare the file storage cache as being invalid, also clears all stored files. */ void InvalidateFileList() { - this->Clear(); + this->clear(); this->file_list_valid = false; } @@ -402,7 +403,7 @@ DEF_CONSOLE_CMD(ConListFiles) } _console_file_list.ValidateFileList(true); - for (uint i = 0; i < _console_file_list.Length(); i++) { + for (uint i = 0; i < _console_file_list.size(); i++) { IConsolePrintF(CC_DEFAULT, "%d) %s", i, _console_file_list[i].title); } @@ -730,7 +731,14 @@ DEF_CONSOLE_CMD(ConClientNickChange) return true; } - if (!NetworkServerChangeClientName(client_id, argv[2])) { + char *client_name = argv[2]; + StrTrimInPlace(client_name); + if (!NetworkIsValidClientName(client_name)) { + IConsoleError("Cannot give a client an empty name"); + return true; + } + + if (!NetworkServerChangeClientName(client_id, client_name)) { IConsoleError("Cannot give a client a duplicate name"); } @@ -899,16 +907,15 @@ DEF_CONSOLE_CMD(ConNetworkReconnect) break; } - if (StrEmpty(_settings_client.network.last_host)) { + if (StrEmpty(_settings_client.network.last_joined)) { IConsolePrint(CC_DEFAULT, "No server for reconnecting."); return true; } /* Don't resolve the address first, just print it directly as it comes from the config file. */ - IConsolePrintF(CC_DEFAULT, "Reconnecting to %s:%d...", _settings_client.network.last_host, _settings_client.network.last_port); + IConsolePrintF(CC_DEFAULT, "Reconnecting to %s ...", _settings_client.network.last_joined); - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), playas); - return true; + return NetworkClientConnectGame(_settings_client.network.last_joined, playas); } DEF_CONSOLE_CMD(ConNetworkConnect) @@ -921,37 +928,8 @@ DEF_CONSOLE_CMD(ConNetworkConnect) } if (argc < 2) return false; - if (_networking) NetworkDisconnect(); // we are in network-mode, first close it! - const char *port = nullptr; - const char *company = nullptr; - char *ip = argv[1]; - /* Default settings: default port and new company */ - uint16 rport = NETWORK_DEFAULT_PORT; - CompanyID join_as = COMPANY_NEW_COMPANY; - - ParseConnectionString(&company, &port, ip); - - IConsolePrintF(CC_DEFAULT, "Connecting to %s...", ip); - if (company != nullptr) { - join_as = (CompanyID)atoi(company); - IConsolePrintF(CC_DEFAULT, " company-no: %d", join_as); - - /* From a user pov 0 is a new company, internally it's different and all - * companies are offset by one to ease up on users (eg companies 1-8 not 0-7) */ - if (join_as != COMPANY_SPECTATOR) { - if (join_as > MAX_COMPANIES) return false; - join_as--; - } - } - if (port != nullptr) { - rport = atoi(port); - IConsolePrintF(CC_DEFAULT, " port: %s", port); - } - - NetworkClientConnectGame(NetworkAddress(ip, rport), join_as); - - return true; + return NetworkClientConnectGame(argv[1], COMPANY_NEW_COMPANY); } /********************************* @@ -1365,7 +1343,9 @@ DEF_CONSOLE_CMD(ConRescanNewGRF) return true; } - RequestNewGRFScan(); + if (!RequestNewGRFScan()) { + IConsoleWarning("NewGRF scanning is already running. Please wait until completed to run again."); + } return true; } @@ -1421,12 +1401,11 @@ DEF_CONSOLE_CMD(ConAlias) if (argc < 3) return false; - alias = IConsoleAliasGet(argv[1]); + alias = IConsole::AliasGet(argv[1]); if (alias == nullptr) { - IConsoleAliasRegister(argv[1], argv[2]); + IConsole::AliasRegister(argv[1], argv[2]); } else { - free(alias->cmdline); - alias->cmdline = stredup(argv[2]); + alias->cmdline = argv[2]; } return true; } @@ -1451,7 +1430,7 @@ DEF_CONSOLE_CMD(ConScreenShot) ScreenshotType type = SC_VIEWPORT; uint32 width = 0; uint32 height = 0; - const char *name = nullptr; + std::string name{}; uint32 arg_index = 1; if (argc > arg_index) { @@ -1520,13 +1499,13 @@ DEF_CONSOLE_CMD(ConInfoCmd) if (argc < 2) return false; - const IConsoleCmd *cmd = IConsoleCmdGet(argv[1]); + const IConsoleCmd *cmd = IConsole::CmdGet(argv[1]); if (cmd == nullptr) { IConsoleError("the given command was not found"); return true; } - IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name); + IConsolePrintF(CC_DEFAULT, "command name: %s", cmd->name.c_str()); IConsolePrintF(CC_DEFAULT, "command proc: %p", cmd->proc); if (cmd->hook != nullptr) IConsoleWarning("command is hooked"); @@ -1585,21 +1564,20 @@ DEF_CONSOLE_CMD(ConHelp) const IConsoleCmd *cmd; const IConsoleAlias *alias; - RemoveUnderscores(argv[1]); - cmd = IConsoleCmdGet(argv[1]); + cmd = IConsole::CmdGet(argv[1]); if (cmd != nullptr) { cmd->proc(0, nullptr); return true; } - alias = IConsoleAliasGet(argv[1]); + alias = IConsole::AliasGet(argv[1]); if (alias != nullptr) { - cmd = IConsoleCmdGet(alias->cmdline); + cmd = IConsole::CmdGet(alias->cmdline); if (cmd != nullptr) { cmd->proc(0, nullptr); return true; } - IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline); + IConsolePrintF(CC_ERROR, "ERROR: alias is of special type, please see its execution-line: '%s'", alias->cmdline.c_str()); return true; } @@ -1626,9 +1604,10 @@ DEF_CONSOLE_CMD(ConListCommands) return true; } - for (const IConsoleCmd *cmd = _iconsole_cmds; cmd != nullptr; cmd = cmd->next) { - if (argv[1] == nullptr || strstr(cmd->name, argv[1]) != nullptr) { - if (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE) IConsolePrintF(CC_DEFAULT, "%s", cmd->name); + for (auto &it : IConsole::Commands()) { + const IConsoleCmd *cmd = &it.second; + if (argv[1] == nullptr || cmd->name.find(argv[1]) != std::string::npos) { + if (cmd->hook == nullptr || cmd->hook(false) != CHR_HIDE) IConsolePrintF(CC_DEFAULT, "%s", cmd->name.c_str()); } } @@ -1642,9 +1621,10 @@ DEF_CONSOLE_CMD(ConListAliases) return true; } - for (const IConsoleAlias *alias = _iconsole_aliases; alias != nullptr; alias = alias->next) { - if (argv[1] == nullptr || strstr(alias->name, argv[1]) != nullptr) { - IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name, alias->cmdline); + for (auto &it : IConsole::Aliases()) { + const IConsoleAlias *alias = &it.second; + if (argv[1] == nullptr || alias->name.find(argv[1]) != std::string::npos) { + IConsolePrintF(CC_DEFAULT, "%s => %s", alias->name.c_str(), alias->cmdline.c_str()); } } @@ -2138,9 +2118,9 @@ DEF_CONSOLE_CMD(ConNewGRFProfile) static void IConsoleDebugLibRegister() { - IConsoleCmdRegister("resettile", ConResetTile); - IConsoleAliasRegister("dbg_echo", "echo %A; echo %B"); - IConsoleAliasRegister("dbg_echo2", "echo %!"); + IConsole::CmdRegister("resettile", ConResetTile); + IConsole::AliasRegister("dbg_echo", "echo %A; echo %B"); + IConsole::AliasRegister("dbg_echo2", "echo %!"); } #endif @@ -2334,139 +2314,138 @@ DEF_CONSOLE_CMD(ConDumpInfo) void IConsoleStdLibRegister() { - IConsoleCmdRegister("debug_level", ConDebugLevel); - IConsoleCmdRegister("echo", ConEcho); - IConsoleCmdRegister("echoc", ConEchoC); - IConsoleCmdRegister("exec", ConExec); - IConsoleCmdRegister("exit", ConExit); - IConsoleCmdRegister("part", ConPart); - IConsoleCmdRegister("help", ConHelp); - IConsoleCmdRegister("info_cmd", ConInfoCmd); - IConsoleCmdRegister("list_cmds", ConListCommands); - IConsoleCmdRegister("list_aliases", ConListAliases); - IConsoleCmdRegister("newgame", ConNewGame); - IConsoleCmdRegister("restart", ConRestart); - IConsoleCmdRegister("reload", ConReload); - IConsoleCmdRegister("getseed", ConGetSeed); - IConsoleCmdRegister("getdate", ConGetDate); - IConsoleCmdRegister("getsysdate", ConGetSysDate); - IConsoleCmdRegister("quit", ConExit); - IConsoleCmdRegister("resetengines", ConResetEngines, ConHookNoNetwork); - IConsoleCmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork); - IConsoleCmdRegister("return", ConReturn); - IConsoleCmdRegister("screenshot", ConScreenShot); - IConsoleCmdRegister("script", ConScript); - IConsoleCmdRegister("scrollto", ConScrollToTile); - IConsoleCmdRegister("alias", ConAlias); - IConsoleCmdRegister("load", ConLoad); - IConsoleCmdRegister("rm", ConRemove); - IConsoleCmdRegister("save", ConSave); - IConsoleCmdRegister("saveconfig", ConSaveConfig); - IConsoleCmdRegister("ls", ConListFiles); - IConsoleCmdRegister("open_cheats", ConOpenCheats); - IConsoleCmdRegister("cheats", ConOpenCheats); - IConsoleCmdRegister("cd", ConChangeDirectory); - IConsoleCmdRegister("pwd", ConPrintWorkingDirectory); - IConsoleCmdRegister("clear", ConClearBuffer); - IConsoleCmdRegister("setting", ConSetting); - IConsoleCmdRegister("setting_newgame", ConSettingNewgame); - IConsoleCmdRegister("list_settings",ConListSettings); - IConsoleCmdRegister("gamelog", ConGamelogPrint); - IConsoleCmdRegister("rescan_newgrf", ConRescanNewGRF); + IConsole::CmdRegister("debug_level", ConDebugLevel); + IConsole::CmdRegister("echo", ConEcho); + IConsole::CmdRegister("echoc", ConEchoC); + IConsole::CmdRegister("exec", ConExec); + IConsole::CmdRegister("exit", ConExit); + IConsole::CmdRegister("part", ConPart); + IConsole::CmdRegister("help", ConHelp); + IConsole::CmdRegister("info_cmd", ConInfoCmd); + IConsole::CmdRegister("list_cmds", ConListCommands); + IConsole::CmdRegister("list_aliases", ConListAliases); + IConsole::CmdRegister("newgame", ConNewGame); + IConsole::CmdRegister("restart", ConRestart); + IConsole::CmdRegister("reload", ConReload); + IConsole::CmdRegister("getseed", ConGetSeed); + IConsole::CmdRegister("getdate", ConGetDate); + IConsole::CmdRegister("getsysdate", ConGetSysDate); + IConsole::CmdRegister("quit", ConExit); + IConsole::CmdRegister("resetengines", ConResetEngines, ConHookNoNetwork); + IConsole::CmdRegister("reset_enginepool", ConResetEnginePool, ConHookNoNetwork); + IConsole::CmdRegister("return", ConReturn); + IConsole::CmdRegister("screenshot", ConScreenShot); + IConsole::CmdRegister("script", ConScript); + IConsole::CmdRegister("scrollto", ConScrollToTile); + IConsole::CmdRegister("alias", ConAlias); + IConsole::CmdRegister("load", ConLoad); + IConsole::CmdRegister("rm", ConRemove); + IConsole::CmdRegister("save", ConSave); + IConsole::CmdRegister("saveconfig", ConSaveConfig); + IConsole::CmdRegister("ls", ConListFiles); + IConsole::CmdRegister("cd", ConChangeDirectory); + IConsole::CmdRegister("pwd", ConPrintWorkingDirectory); + IConsole::CmdRegister("clear", ConClearBuffer); + IConsole::CmdRegister("setting", ConSetting); + IConsole::CmdRegister("setting_newgame", ConSettingNewgame); + IConsole::CmdRegister("list_settings", ConListSettings); + IConsole::CmdRegister("gamelog", ConGamelogPrint); + IConsole::CmdRegister("rescan_newgrf", ConRescanNewGRF); + IConsole::CmdRegister("cheats", ConOpenCheats); - IConsoleAliasRegister("dir", "ls"); - IConsoleAliasRegister("del", "rm %+"); - IConsoleAliasRegister("newmap", "newgame"); - IConsoleAliasRegister("patch", "setting %+"); - IConsoleAliasRegister("set", "setting %+"); - IConsoleAliasRegister("set_newgame", "setting_newgame %+"); - IConsoleAliasRegister("list_patches", "list_settings %+"); - IConsoleAliasRegister("developer", "setting developer %+"); + IConsole::AliasRegister("dir", "ls"); + IConsole::AliasRegister("del", "rm %+"); + IConsole::AliasRegister("newmap", "newgame"); + IConsole::AliasRegister("patch", "setting %+"); + IConsole::AliasRegister("set", "setting %+"); + IConsole::AliasRegister("set_newgame", "setting_newgame %+"); + IConsole::AliasRegister("list_patches", "list_settings %+"); + IConsole::AliasRegister("developer", "setting developer %+"); - IConsoleCmdRegister("list_ai_libs", ConListAILibs); - IConsoleCmdRegister("list_ai", ConListAI); - IConsoleCmdRegister("reload_ai", ConReloadAI); - IConsoleCmdRegister("rescan_ai", ConRescanAI); - IConsoleCmdRegister("start_ai", ConStartAI); - IConsoleCmdRegister("stop_ai", ConStopAI); + IConsole::CmdRegister("list_ai_libs", ConListAILibs); + IConsole::CmdRegister("list_ai", ConListAI); + IConsole::CmdRegister("reload_ai", ConReloadAI); + IConsole::CmdRegister("rescan_ai", ConRescanAI); + IConsole::CmdRegister("start_ai", ConStartAI); + IConsole::CmdRegister("stop_ai", ConStopAI); - IConsoleCmdRegister("list_game", ConListGame); - IConsoleCmdRegister("list_game_libs", ConListGameLibs); - IConsoleCmdRegister("rescan_game", ConRescanGame); + IConsole::CmdRegister("list_game", ConListGame); + IConsole::CmdRegister("list_game_libs", ConListGameLibs); + IConsole::CmdRegister("rescan_game", ConRescanGame); - IConsoleCmdRegister("companies", ConCompanies); - IConsoleAliasRegister("players", "companies"); + IConsole::CmdRegister("companies", ConCompanies); + IConsole::AliasRegister("players", "companies"); /* networking functions */ /* Content downloading is only available with ZLIB */ #if defined(WITH_ZLIB) - IConsoleCmdRegister("content", ConContent); + IConsole::CmdRegister("content", ConContent); #endif /* defined(WITH_ZLIB) */ /*** Networking commands ***/ - IConsoleCmdRegister("say", ConSay, ConHookNeedNetwork); - IConsoleCmdRegister("say_company", ConSayCompany, ConHookNeedNetwork); - IConsoleAliasRegister("say_player", "say_company %+"); - IConsoleCmdRegister("say_client", ConSayClient, ConHookNeedNetwork); + IConsole::CmdRegister("say", ConSay, ConHookNeedNetwork); + IConsole::CmdRegister("say_company", ConSayCompany, ConHookNeedNetwork); + IConsole::AliasRegister("say_player", "say_company %+"); + IConsole::CmdRegister("say_client", ConSayClient, ConHookNeedNetwork); - IConsoleCmdRegister("connect", ConNetworkConnect, ConHookClientOnly); - IConsoleCmdRegister("clients", ConNetworkClients, ConHookNeedNetwork); - IConsoleCmdRegister("status", ConStatus, ConHookServerOnly); - IConsoleCmdRegister("server_info", ConServerInfo, ConHookServerOnly); - IConsoleAliasRegister("info", "server_info"); - IConsoleCmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly); - IConsoleCmdRegister("rcon", ConRcon, ConHookNeedNetwork); + IConsole::CmdRegister("connect", ConNetworkConnect, ConHookClientOnly); + IConsole::CmdRegister("clients", ConNetworkClients, ConHookNeedNetwork); + IConsole::CmdRegister("status", ConStatus, ConHookServerOnly); + IConsole::CmdRegister("server_info", ConServerInfo, ConHookServerOnly); + IConsole::AliasRegister("info", "server_info"); + IConsole::CmdRegister("reconnect", ConNetworkReconnect, ConHookClientOnly); + IConsole::CmdRegister("rcon", ConRcon, ConHookNeedNetwork); - IConsoleCmdRegister("join", ConJoinCompany, ConHookNeedNetwork); - IConsoleAliasRegister("spectate", "join 255"); - IConsoleCmdRegister("move", ConMoveClient, ConHookServerOnly); - IConsoleCmdRegister("reset_company", ConResetCompany, ConHookServerOnly); - IConsoleAliasRegister("clean_company", "reset_company %A"); - IConsoleCmdRegister("client_name", ConClientNickChange, ConHookServerOnly); - IConsoleCmdRegister("kick", ConKick, ConHookServerOnly); - IConsoleCmdRegister("ban", ConBan, ConHookServerOnly); - IConsoleCmdRegister("unban", ConUnBan, ConHookServerOnly); - IConsoleCmdRegister("banlist", ConBanList, ConHookServerOnly); + IConsole::CmdRegister("join", ConJoinCompany, ConHookNeedNetwork); + IConsole::AliasRegister("spectate", "join 255"); + IConsole::CmdRegister("move", ConMoveClient, ConHookServerOnly); + IConsole::CmdRegister("reset_company", ConResetCompany, ConHookServerOnly); + IConsole::AliasRegister("clean_company", "reset_company %A"); + IConsole::CmdRegister("client_name", ConClientNickChange, ConHookServerOnly); + IConsole::CmdRegister("kick", ConKick, ConHookServerOnly); + IConsole::CmdRegister("ban", ConBan, ConHookServerOnly); + IConsole::CmdRegister("unban", ConUnBan, ConHookServerOnly); + IConsole::CmdRegister("banlist", ConBanList, ConHookServerOnly); - IConsoleCmdRegister("pause", ConPauseGame, ConHookServerOnly); - IConsoleCmdRegister("unpause", ConUnpauseGame, ConHookServerOnly); + IConsole::CmdRegister("pause", ConPauseGame, ConHookServerOnly); + IConsole::CmdRegister("unpause", ConUnpauseGame, ConHookServerOnly); - IConsoleCmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork); - IConsoleAliasRegister("company_password", "company_pw %+"); + IConsole::CmdRegister("company_pw", ConCompanyPassword, ConHookNeedNetwork); + IConsole::AliasRegister("company_password", "company_pw %+"); - IConsoleAliasRegister("net_frame_freq", "setting frame_freq %+"); - IConsoleAliasRegister("net_sync_freq", "setting sync_freq %+"); - IConsoleAliasRegister("server_pw", "setting server_password %+"); - IConsoleAliasRegister("server_password", "setting server_password %+"); - IConsoleAliasRegister("rcon_pw", "setting rcon_password %+"); - IConsoleAliasRegister("rcon_password", "setting rcon_password %+"); - IConsoleAliasRegister("name", "setting client_name %+"); - IConsoleAliasRegister("server_name", "setting server_name %+"); - IConsoleAliasRegister("server_port", "setting server_port %+"); - IConsoleAliasRegister("server_advertise", "setting server_advertise %+"); - IConsoleAliasRegister("max_clients", "setting max_clients %+"); - IConsoleAliasRegister("max_companies", "setting max_companies %+"); - IConsoleAliasRegister("max_spectators", "setting max_spectators %+"); - IConsoleAliasRegister("max_join_time", "setting max_join_time %+"); - IConsoleAliasRegister("pause_on_join", "setting pause_on_join %+"); - IConsoleAliasRegister("autoclean_companies", "setting autoclean_companies %+"); - IConsoleAliasRegister("autoclean_protected", "setting autoclean_protected %+"); - IConsoleAliasRegister("autoclean_unprotected", "setting autoclean_unprotected %+"); - IConsoleAliasRegister("restart_game_year", "setting restart_game_year %+"); - IConsoleAliasRegister("min_players", "setting min_active_clients %+"); - IConsoleAliasRegister("reload_cfg", "setting reload_cfg %+"); + IConsole::AliasRegister("net_frame_freq", "setting frame_freq %+"); + IConsole::AliasRegister("net_sync_freq", "setting sync_freq %+"); + IConsole::AliasRegister("server_pw", "setting server_password %+"); + IConsole::AliasRegister("server_password", "setting server_password %+"); + IConsole::AliasRegister("rcon_pw", "setting rcon_password %+"); + IConsole::AliasRegister("rcon_password", "setting rcon_password %+"); + IConsole::AliasRegister("name", "setting client_name %+"); + IConsole::AliasRegister("server_name", "setting server_name %+"); + IConsole::AliasRegister("server_port", "setting server_port %+"); + IConsole::AliasRegister("server_advertise", "setting server_advertise %+"); + IConsole::AliasRegister("max_clients", "setting max_clients %+"); + IConsole::AliasRegister("max_companies", "setting max_companies %+"); + IConsole::AliasRegister("max_spectators", "setting max_spectators %+"); + IConsole::AliasRegister("max_join_time", "setting max_join_time %+"); + IConsole::AliasRegister("pause_on_join", "setting pause_on_join %+"); + IConsole::AliasRegister("autoclean_companies", "setting autoclean_companies %+"); + IConsole::AliasRegister("autoclean_protected", "setting autoclean_protected %+"); + IConsole::AliasRegister("autoclean_unprotected", "setting autoclean_unprotected %+"); + IConsole::AliasRegister("restart_game_year", "setting restart_game_year %+"); + IConsole::AliasRegister("min_players", "setting min_active_clients %+"); + IConsole::AliasRegister("reload_cfg", "setting reload_cfg %+"); /* debugging stuff */ #ifdef _DEBUG IConsoleDebugLibRegister(); #endif - IConsoleCmdRegister("fps", ConFramerate); - IConsoleCmdRegister("fps_wnd", ConFramerateWindow); + IConsole::CmdRegister("fps", ConFramerate); + IConsole::CmdRegister("fps_wnd", ConFramerateWindow); /* NewGRF development stuff */ - IConsoleCmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool); - IConsoleCmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool); + IConsole::CmdRegister("reload_newgrfs", ConNewGRFReload, ConHookNewGRFDeveloperTool); + IConsole::CmdRegister("newgrf_profile", ConNewGRFProfile, ConHookNewGRFDeveloperTool); - IConsoleCmdRegister("dump_info", ConDumpInfo); + IConsole::CmdRegister("dump_info", ConDumpInfo); } diff --git a/src/console_internal.h b/src/console_internal.h index 630f69607b..ca2f92193b 100644 --- a/src/console_internal.h +++ b/src/console_internal.h @@ -11,6 +11,7 @@ #define CONSOLE_INTERNAL_H #include "gfx_type.h" +#include static const uint ICON_CMDLN_SIZE = 1024; ///< maximum length of a typed in command static const uint ICON_MAX_STREAMSIZE = 2048; ///< maximum length of a totally expanded command @@ -33,9 +34,9 @@ enum ConsoleHookResult { typedef bool IConsoleCmdProc(byte argc, char *argv[]); typedef ConsoleHookResult IConsoleHook(bool echo); struct IConsoleCmd { - char *name; ///< name of command - IConsoleCmd *next; ///< next command in list + IConsoleCmd(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook) : name(name), proc(proc), hook(hook) {} + std::string name; ///< name of command IConsoleCmdProc *proc; ///< process executed when command is typed IConsoleHook *hook; ///< any special trigger action that needs executing }; @@ -53,25 +54,31 @@ struct IConsoleCmd { * - ";" allows for combining commands (see example 'ng') */ struct IConsoleAlias { - char *name; ///< name of the alias - IConsoleAlias *next; ///< next alias in list + IConsoleAlias(const std::string &name, const std::string &cmdline) : name(name), cmdline(cmdline) {} - char *cmdline; ///< command(s) that is/are being aliased + std::string name; ///< name of the alias + std::string cmdline; ///< command(s) that is/are being aliased }; -/* console parser */ -extern IConsoleCmd *_iconsole_cmds; ///< List of registered commands. -extern IConsoleAlias *_iconsole_aliases; ///< List of registered aliases. +struct IConsole +{ + typedef std::map CommandList; + typedef std::map AliasList; + + /* console parser */ + static CommandList &Commands(); + static AliasList &Aliases(); + + /* Commands */ + static void CmdRegister(const std::string &name, IConsoleCmdProc *proc, IConsoleHook *hook = nullptr); + static IConsoleCmd *CmdGet(const std::string &name); + static void AliasRegister(const std::string &name, const std::string &cmd); + static IConsoleAlias *AliasGet(const std::string &name); +}; /* console functions */ void IConsoleClearBuffer(); -/* Commands */ -void IConsoleCmdRegister(const char *name, IConsoleCmdProc *proc, IConsoleHook *hook = nullptr); -void IConsoleAliasRegister(const char *name, const char *cmd); -IConsoleCmd *IConsoleCmdGet(const char *name); -IConsoleAlias *IConsoleAliasGet(const char *name); - /* console std lib (register ingame commands/aliases) */ void IConsoleStdLibRegister(); @@ -81,6 +88,5 @@ bool GetArgumentInteger(uint32 *value, const char *arg); void IConsoleGUIInit(); void IConsoleGUIFree(); void IConsoleGUIPrint(TextColour colour_code, char *string); -char *RemoveUnderscores(char *name); #endif /* CONSOLE_INTERNAL_H */ diff --git a/src/core/geometry_type.hpp b/src/core/geometry_type.hpp index 92a1d97df6..cba944fb6f 100644 --- a/src/core/geometry_type.hpp +++ b/src/core/geometry_type.hpp @@ -62,10 +62,4 @@ struct PointDimension { int height; }; -/** A pair of two integers */ -struct Pair { - int a; - int b; -}; - #endif /* GEOMETRY_TYPE_HPP */ diff --git a/src/debug.cpp b/src/debug.cpp index 975c5cb885..46921c27f0 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -139,8 +139,8 @@ static void debug_print(const char *dbg, const char *buf) seprintf(buffer, lastof(buffer), "%sdbg: [%s] %s\n", GetLogPrefix(), dbg, buf); #if defined(_WIN32) wchar_t system_buf[512]; - convert_to_fs(buffer, system_buf, lengthof(system_buf), true); - _fputts(system_buf, stderr); + convert_to_fs(buffer, system_buf, lengthof(system_buf)); + fputws(system_buf, stderr); #else fputs(buffer, stderr); #endif diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index c5d76877cc..cc245b38fe 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -456,7 +456,7 @@ static bool DisasterTick_Aircraft(DisasterVehicle *v, uint16 image_override, boo DestructIndustry(i); SetDParam(0, i->town->index); - AddTileNewsItem(news_message, NT_ACCIDENT, v->dest_tile); + AddIndustryNewsItem(news_message, NT_ACCIDENT, i->index); if (_settings_client.sound.disaster) SndPlayTileFx(SND_12_EXPLOSION, i->location.tile); } } else if (v->current_order.GetDestination() == 0) { diff --git a/src/dock_gui.cpp b/src/dock_gui.cpp index ac85d37631..7d5cf95c9a 100644 --- a/src/dock_gui.cpp +++ b/src/dock_gui.cpp @@ -172,7 +172,7 @@ struct BuildDocksToolbarWindow : Window { case WID_DT_RIVER: // Build river button (in scenario editor) if (_game_mode != GM_EDITOR) return; - HandlePlacePushButton(this, WID_DT_RIVER, SPR_CURSOR_RIVER, HT_RECT); + HandlePlacePushButton(this, WID_DT_RIVER, SPR_CURSOR_RIVER, HT_RECT | HT_DIAGONAL); break; case WID_DT_BUILD_AQUEDUCT: // Build aqueduct button @@ -248,7 +248,7 @@ struct BuildDocksToolbarWindow : Window { DoCommandP(end_tile, start_tile, (_game_mode == GM_EDITOR && _ctrl_pressed) ? WATER_CLASS_SEA : WATER_CLASS_CANAL, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_BUILD_CANALS), CcPlaySound_CONSTRUCTION_WATER); break; case DDSP_CREATE_RIVER: - DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER, CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcPlaySound_CONSTRUCTION_WATER); + DoCommandP(end_tile, start_tile, WATER_CLASS_RIVER | (_ctrl_pressed ? 1 << 2 : 0), CMD_BUILD_CANAL | CMD_MSG(STR_ERROR_CAN_T_PLACE_RIVERS), CcPlaySound_CONSTRUCTION_WATER); break; case DDSP_BUILD_STATION: { uint32 p2 = (uint32)INVALID_STATION << 16; // no station to join diff --git a/src/economy.cpp b/src/economy.cpp index 716446ba9e..9982e79e02 100644 --- a/src/economy.cpp +++ b/src/economy.cpp @@ -798,8 +798,7 @@ void RecomputePrices() } /* Setup cargo payment */ - CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (CargoSpec *cs : CargoSpec::Iterate()) { cs->current_payment = ((int64)cs->initial_payment * _economy.inflation_payment) >> 16; } diff --git a/src/engine.cpp b/src/engine.cpp index 596e870636..41cd9dba80 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -66,12 +66,6 @@ static_assert(lengthof(_orig_rail_vehicle_info) + lengthof(_orig_road_vehicle_in const uint EngineOverrideManager::NUM_DEFAULT_ENGINES = _engine_counts[VEH_TRAIN] + _engine_counts[VEH_ROAD] + _engine_counts[VEH_SHIP] + _engine_counts[VEH_AIRCRAFT]; -Engine::Engine() : - overrides_count(0), - overrides(nullptr) -{ -} - Engine::Engine(VehicleType type, EngineID base) { this->type = type; @@ -136,11 +130,6 @@ Engine::Engine(VehicleType type, EngineID base) } } -Engine::~Engine() -{ - UnloadWagonOverrides(this); -} - /** * Checks whether the engine is a valid (non-articulated part of an) engine. * @return true if enabled @@ -722,11 +711,9 @@ static void EnableEngineForCompany(EngineID eid, CompanyID company) SetBit(e->company_avail, company); if (e->type == VEH_TRAIN) { - assert(e->u.rail.railtype < RAILTYPE_END); - c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, _date); + c->avail_railtypes = GetCompanyRailtypes(c->index); } else if (e->type == VEH_ROAD) { - assert(e->u.road.roadtype < ROADTYPE_END); - c->avail_roadtypes = AddDateIntroducedRoadTypes(c->avail_roadtypes | GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes, _date); + c->avail_roadtypes = GetCompanyRoadTypes(c->index); } if (company == _local_company) { diff --git a/src/engine_base.h b/src/engine_base.h index 2e434b589e..7822111e77 100644 --- a/src/engine_base.h +++ b/src/engine_base.h @@ -15,6 +15,12 @@ #include "core/pool_type.hpp" #include "newgrf_commons.h" +struct WagonOverride { + std::vector engines; + CargoID cargo; + const SpriteGroup *group; +}; + typedef Pool EnginePool; extern EnginePool _engine_pool; @@ -56,13 +62,11 @@ struct Engine : EnginePool::PoolItem<&_engine_pool> { * evaluating callbacks. */ GRFFilePropsBase grf_prop; - uint16 overrides_count; - struct WagonOverride *overrides; + std::vector overrides; uint16 list_position; - Engine(); + Engine() {} Engine(VehicleType type, EngineID base); - ~Engine(); bool IsEnabled() const; /** diff --git a/src/fileio.cpp b/src/fileio.cpp index 6b33f8aa24..f2a2b14f3a 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -279,7 +279,7 @@ bool FioCheckFileExists(const std::string &filename, Subdirectory subdir) */ bool FileExists(const std::string &filename) { - return access(OTTD2FS(filename.c_str()), 0) == 0; + return access(OTTD2FS(filename).c_str(), 0) == 0; } /** @@ -358,7 +358,7 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc } #if defined(_WIN32) - if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf.c_str())) == INVALID_FILE_ATTRIBUTES) return nullptr; + if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf).c_str()) == INVALID_FILE_ATTRIBUTES) return nullptr; #endif f = fopen(buf.c_str(), mode); @@ -506,11 +506,11 @@ void FioCreateDirectory(const std::string &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.c_str()), nullptr); + CreateDirectory(OTTD2FS(name).c_str(), nullptr); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) - mkdir(OTTD2FS(name.c_str())); + mkdir(OTTD2FS(name).c_str()); #else - mkdir(OTTD2FS(name.c_str()), 0755); + mkdir(OTTD2FS(name).c_str(), 0755); #endif } @@ -1315,7 +1315,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s if (path == nullptr || (dir = ttd_opendir(path)) == nullptr) return 0; while ((dirent = readdir(dir)) != nullptr) { - const char *d_name = FS2OTTD(dirent->d_name); + std::string d_name = FS2OTTD(dirent->d_name); if (!FiosIsValidFile(path, dirent, &sb)) continue; @@ -1325,7 +1325,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s if (S_ISDIR(sb.st_mode)) { /* Directory */ if (!recursive) continue; - if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; + if (d_name == "." || d_name == "..") continue; AppendPathSeparator(filename); num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { diff --git a/src/fileio_func.h b/src/fileio_func.h index 6dbaea8970..1428356506 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -132,7 +132,7 @@ int closedir(DIR *d); */ static inline DIR *ttd_opendir(const char *path) { - return opendir(OTTD2FS(path)); + return opendir(OTTD2FS(path).c_str()); } diff --git a/src/fios.cpp b/src/fios.cpp index b48bc21089..8528e8c622 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -63,11 +63,6 @@ bool FiosItem::operator< (const FiosItem &other) const return (_savegame_sort_order & SORT_DESCENDING) ? r > 0 : r < 0; } -FileList::~FileList() -{ - this->Clear(); -} - /** * Construct a file list with the given kind of files, for the stated purpose. * @param abstract_filetype Kind of files to collect. @@ -75,7 +70,7 @@ FileList::~FileList() */ void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop) { - this->Clear(); + this->clear(); assert(fop == SLO_LOAD || fop == SLO_SAVE); switch (abstract_filetype) { @@ -107,7 +102,8 @@ void FileList::BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperati */ const FiosItem *FileList::FindItem(const char *file) { - for (const FiosItem *item = this->Begin(); item != this->End(); item++) { + for (const auto &it : *this) { + const FiosItem *item = ⁢ if (strcmp(file, item->name) == 0) return item; if (strcmp(file, item->title) == 0) return item; } @@ -117,13 +113,14 @@ const FiosItem *FileList::FindItem(const char *file) int i = strtol(file, &endptr, 10); if (file == endptr || *endptr != '\0') i = -1; - if (IsInsideMM(i, 0, this->Length())) return this->Get(i); + if (IsInsideMM(i, 0, this->size())) return &this->at(i); /* As a last effort assume it is an OpenTTD savegame and * that the ".sav" part was not given. */ char long_file[MAX_PATH]; seprintf(long_file, lastof(long_file), "%s.sav", file); - for (const FiosItem *item = this->Begin(); item != this->End(); item++) { + for (const auto &it : *this) { + const FiosItem *item = ⁢ if (strcmp(long_file, item->name) == 0) return item; if (strcmp(long_file, item->title) == 0) return item; } @@ -302,14 +299,14 @@ bool FiosFileScanner::AddFile(const std::string &filename, size_t basepath_lengt 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 (filename == fios->name) return false; + for (const auto &fios : file_list) { + if (filename == fios.name) return false; } - FiosItem *fios = file_list.Append(); + FiosItem *fios = &file_list.emplace_back(); #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.c_str()), 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; @@ -367,13 +364,13 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c size_t sort_start; char d_name[sizeof(fios->name)]; - file_list.Clear(); + file_list.clear(); assert(_fios_path != nullptr); /* A parent directory link exists if we are not in the root directory */ if (!FiosIsRoot(_fios_path->c_str())) { - fios = file_list.Append(); + fios = &file_list.emplace_back(); fios->type = FIOS_TYPE_PARENT; fios->mtime = 0; strecpy(fios->name, "..", lastof(fios->name)); @@ -384,13 +381,13 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show subdirectories */ if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) { while ((dirent = readdir(dir)) != nullptr) { - strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); + strecpy(d_name, FS2OTTD(dirent->d_name).c_str(), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ 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(); + fios = &file_list.emplace_back(); fios->type = FIOS_TYPE_DIR; fios->mtime = 0; strecpy(fios->name, d_name, lastof(fios->name)); @@ -407,12 +404,12 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c { SortingBits order = _savegame_sort_order; _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; - std::sort(file_list.files.begin(), file_list.files.end()); + std::sort(file_list.begin(), file_list.end()); _savegame_sort_order = order; } /* This is where to start sorting for the filenames */ - sort_start = file_list.Length(); + sort_start = file_list.size(); /* Show files */ FiosFileScanner scanner(fop, callback_proc, file_list); @@ -422,12 +419,12 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c scanner.Scan(nullptr, subdir, true, true); } - std::sort(file_list.files.begin() + sort_start, file_list.files.end()); + std::sort(file_list.begin() + sort_start, file_list.end()); /* Show drives */ FiosGetDrives(file_list); - file_list.Compact(); + file_list.shrink_to_fit(); } /** diff --git a/src/fios.h b/src/fios.h index 8d8faac07b..28a1cc6aa5 100644 --- a/src/fios.h +++ b/src/fios.h @@ -13,7 +13,7 @@ #include "gfx_type.h" #include "company_base.h" #include "newgrf_config.h" -#include "network/core/tcp_content.h" +#include "network/core/tcp_content_type.h" /** Special values for save-load window for the data parameter of #InvalidateWindowData. */ @@ -109,94 +109,10 @@ struct FiosItem { }; /** List of file information. */ -class FileList { +class FileList : public std::vector { public: - ~FileList(); - - /** - * Construct a new entry in the file list. - * @return Pointer to the new items to be initialized. - */ - inline FiosItem *Append() - { - return &this->files.emplace_back(); - } - - /** - * Get the number of files in the list. - * @return The number of files stored in the list. - */ - inline size_t Length() const - { - return this->files.size(); - } - - /** - * Get a pointer to the first file information. - * @return Address of the first file information. - */ - inline const FiosItem *Begin() const - { - return this->files.data(); - } - - /** - * Get a pointer behind the last file information. - * @return Address behind the last file information. - */ - inline const FiosItem *End() const - { - return this->Begin() + this->Length(); - } - - /** - * Get a pointer to the indicated file information. File information must exist. - * @return Address of the indicated existing file information. - */ - inline const FiosItem *Get(size_t index) const - { - return this->files.data() + index; - } - - /** - * Get a pointer to the indicated file information. File information must exist. - * @return Address of the indicated existing file information. - */ - inline FiosItem *Get(size_t index) - { - return this->files.data() + index; - } - - inline const FiosItem &operator[](size_t index) const - { - return this->files[index]; - } - - /** - * Get a reference to the indicated file information. File information must exist. - * @return The requested file information. - */ - inline FiosItem &operator[](size_t index) - { - return this->files[index]; - } - - /** Remove all items from the list. */ - inline void Clear() - { - this->files.clear(); - } - - /** Compact the list down to the smallest block size boundary. */ - inline void Compact() - { - this->files.shrink_to_fit(); - } - void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop); const FiosItem *FindItem(const char *file); - - std::vector files; ///< The list of files. }; enum SortingBits { diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index d4c3021364..b7bc09115d 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -256,8 +256,8 @@ static void SortSaveGameList(FileList &file_list) * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE) * Only sort savegames/scenarios, not directories */ - for (const FiosItem *item = file_list.Begin(); item != file_list.End(); item++) { - switch (item->type) { + for (const auto &item : file_list) { + switch (item.type) { case FIOS_TYPE_DIR: sort_start++; break; case FIOS_TYPE_PARENT: sort_start++; break; case FIOS_TYPE_DRIVE: sort_end++; break; @@ -265,7 +265,7 @@ static void SortSaveGameList(FileList &file_list) } } - std::sort(file_list.files.begin() + sort_start, file_list.files.end() - sort_end); + std::sort(file_list.begin() + sort_start, file_list.end() - sort_end); } struct SaveLoadWindow : public Window { @@ -445,14 +445,14 @@ public: uint y = r.top + WD_FRAMERECT_TOP; uint scroll_pos = this->vscroll->GetPosition(); - for (uint row = 0; row < this->fios_items.Length(); row++) { + for (uint row = 0; row < this->fios_items.size(); row++) { if (!this->fios_items_shown[row]) { /* The current item is filtered out : we do not show it */ scroll_pos++; continue; } if (row < scroll_pos) continue; - const FiosItem *item = this->fios_items.Get(row); + const FiosItem *item = &this->fios_items[row]; if (item == this->selected) { GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE); @@ -659,7 +659,7 @@ public: if (!this->fios_items_shown[i]) y++; i++; } - const FiosItem *file = this->fios_items.Get(y); + const FiosItem *file = &this->fios_items[y]; const char *name = FiosBrowseTo(file); if (name == nullptr) { @@ -762,7 +762,7 @@ public: if (!this->fios_items_shown[i]) y++; i++; } - const FiosItem *file = this->fios_items.Get(y); + const FiosItem *file = &this->fios_items[y]; if (file != this->highlighted) { this->highlighted = file; @@ -840,7 +840,7 @@ public: _fios_path_changed = true; this->fios_items.BuildFileList(this->abstract_filetype, this->fop); - this->vscroll->SetCount((uint)this->fios_items.Length()); + this->vscroll->SetCount((uint)this->fios_items.size()); this->selected = nullptr; _load_check_data.Clear(); @@ -880,10 +880,10 @@ public: case SLIWD_FILTER_CHANGES: /* Filter changes */ - this->fios_items_shown.resize(this->fios_items.Length()); + this->fios_items_shown.resize(this->fios_items.size()); uint items_shown_count = 0; ///< The number of items shown in the list /* We pass through every fios item */ - for (uint i = 0; i < this->fios_items.Length(); i++) { + for (uint i = 0; i < this->fios_items.size(); i++) { if (this->string_filter.IsEmpty()) { /* We don't filter anything out if the filter editbox is empty */ this->fios_items_shown[i] = true; diff --git a/src/fontcache.cpp b/src/fontcache.cpp index a3cceabc61..825376453b 100644 --- a/src/fontcache.cpp +++ b/src/fontcache.cpp @@ -87,7 +87,6 @@ public: virtual void ClearFontCache(); virtual const Sprite *GetGlyph(GlyphID key); virtual uint GetGlyphWidth(GlyphID key); - virtual int GetHeight() const; virtual bool GetDrawGlyphShadow(); virtual GlyphID MapCharToGlyph(WChar key) { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } virtual const void *GetFontTable(uint32 tag, size_t &length) { length = 0; return nullptr; } @@ -102,6 +101,7 @@ public: SpriteFontCache::SpriteFontCache(FontSize fs) : FontCache(fs), glyph_to_spriteid_map(nullptr) { this->InitializeUnicodeGlyphMap(); + this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); } /** @@ -177,6 +177,7 @@ void SpriteFontCache::ClearGlyphToSpriteMap() void SpriteFontCache::ClearFontCache() { Layouter::ResetFontCache(this->fs); + this->height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); } const Sprite *SpriteFontCache::GetGlyph(GlyphID key) @@ -193,11 +194,6 @@ uint SpriteFontCache::GetGlyphWidth(GlyphID key) return SpriteExists(sprite) ? GetSprite(sprite, ST_FONT)->width + ScaleFontTrad(this->fs != FS_NORMAL ? 1 : 0) : 0; } -int SpriteFontCache::GetHeight() const -{ - return ScaleFontTrad(this->height); -} - bool SpriteFontCache::GetDrawGlyphShadow() { return false; @@ -428,14 +424,14 @@ void FreeTypeFontCache::SetFontSize(FontSize fs, FT_Face face, int pixels) { if (pixels == 0) { /* Try to determine a good height based on the minimal height recommended by the font. */ - int scaled_height = ScaleFontTrad(_default_font_height[this->fs]); + int scaled_height = ScaleFontTrad(this->GetDefaultFontHeight(this->fs)); pixels = scaled_height; TT_Header *head = (TT_Header *)FT_Get_Sfnt_Table(this->face, ft_sfnt_head); if (head != nullptr) { /* Font height is minimum height plus the difference between the default * height for this font size and the small size. */ - int diff = scaled_height - ScaleFontTrad(_default_font_height[FS_SMALL]); + int diff = scaled_height - ScaleFontTrad(this->GetDefaultFontHeight(FS_SMALL)); pixels = Clamp(std::min(head->Lowest_Rec_PPEM, MAX_FONT_MIN_REC_SIZE) + diff, scaled_height, MAX_FONT_SIZE); } } else { diff --git a/src/fontcache.h b/src/fontcache.h index 73675cf44e..c3b20cb4f7 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -45,7 +45,7 @@ public: * Get the height of the font. * @return The height of the font. */ - virtual int GetHeight() const { return this->height; } + inline int GetHeight() const { return this->height; } /** * Get the ascender value of the font. diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index 9ac78dc68b..a2fd03044e 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -683,7 +683,7 @@ struct FramerateWindow : Window { case WID_FRW_TIMES_AVERAGE: { /* Open time graph windows when clicking detail measurement lines */ const Scrollbar *sb = this->GetScrollbar(WID_FRW_SCROLLBAR); - int line = sb->GetScrolledRowFromWidget(pt.y - FONT_HEIGHT_NORMAL - VSPACING, this, widget, VSPACING, FONT_HEIGHT_NORMAL); + int line = sb->GetScrolledRowFromWidget(pt.y, this, widget, VSPACING + FONT_HEIGHT_NORMAL); if (line != INT_MAX) { line++; /* Find the visible line that was clicked */ diff --git a/src/gfx.cpp b/src/gfx.cpp index 5b85476035..8b304b3b32 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -895,15 +895,17 @@ const char *GetCharAtPosition(const char *str, int x, FontSize start_fontsize) /** * Draw single character horizontally centered around (x,y) * @param c Character (glyph) to draw - * @param x X position to draw character - * @param y Y position to draw character + * @param r Rectangle to draw character within * @param colour Colour to use, for details see _string_colourmap in * table/palettes.h or docs/ottd-colourtext-palette.png or the enum TextColour in gfx_type.h */ -void DrawCharCentered(WChar c, int x, int y, TextColour colour) +void DrawCharCentered(WChar c, const Rect &r, TextColour colour) { SetColourRemap(colour); - GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP); + GfxMainBlitter(GetGlyph(FS_NORMAL, c), + CenterBounds(r.left, r.right, GetCharacterWidth(FS_NORMAL, c)), + CenterBounds(r.top, r.bottom, FONT_HEIGHT_NORMAL), + BM_COLOUR_REMAP); } /** @@ -1331,7 +1333,7 @@ void LoadStringWidthTable(bool monospace) } } - ReInitAllWindows(); + ReInitAllWindows(false); } /** diff --git a/src/gfx_func.h b/src/gfx_func.h index 6f401a69a7..7d259e6d7c 100644 --- a/src/gfx_func.h +++ b/src/gfx_func.h @@ -97,30 +97,12 @@ void DrawSpriteCentered(SpriteID img, PaletteID pal, int x, int y, const SubSpri void DrawSpriteCenteredRect(SpriteID img, PaletteID pal, int left, int top, int right, int bottom, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI); void DrawSpriteCenteredRect(SpriteID img, PaletteID pal, const Rect &r, const SubSprite *sub = nullptr, ZoomLevel zoom = ZOOM_LVL_GUI); -/** How to align the to-be drawn text. */ -enum StringAlignment { - SA_LEFT = 0 << 0, ///< Left align the text. - SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text. - SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit). - SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment. - - SA_TOP = 0 << 2, ///< Top align the text. - SA_VERT_CENTER = 1 << 2, ///< Vertically center the text. - SA_BOTTOM = 2 << 2, ///< Bottom align the text. - SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment. - - SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically. - - SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages. -}; -DECLARE_ENUM_AS_BIT_SET(StringAlignment) - int DrawString(int left, int right, int top, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); int DrawString(int left, int right, int top, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = SA_LEFT, bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, const char *str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); int DrawStringMultiLine(int left, int right, int top, int bottom, StringID str, TextColour colour = TC_FROMSTRING, StringAlignment align = (SA_TOP | SA_LEFT), bool underline = false, FontSize fontsize = FS_NORMAL); -void DrawCharCentered(WChar c, int x, int y, TextColour colour); +void DrawCharCentered(WChar c, const Rect &r, TextColour colour); void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode = FILLRECT_OPAQUE); void GfxFillPolygon(const std::vector &shape, int colour, FillRectMode mode = FILLRECT_OPAQUE); diff --git a/src/gfx_type.h b/src/gfx_type.h index 3b9f04d9e8..a6bf3cf6d5 100644 --- a/src/gfx_type.h +++ b/src/gfx_type.h @@ -323,4 +323,22 @@ enum Support8bpp { S8BPP_HARDWARE, ///< Full 8bpp support by OS and hardware. }; + /** How to align the to-be drawn text. */ +enum StringAlignment { + SA_LEFT = 0 << 0, ///< Left align the text. + SA_HOR_CENTER = 1 << 0, ///< Horizontally center the text. + SA_RIGHT = 2 << 0, ///< Right align the text (must be a single bit). + SA_HOR_MASK = 3 << 0, ///< Mask for horizontal alignment. + + SA_TOP = 0 << 2, ///< Top align the text. + SA_VERT_CENTER = 1 << 2, ///< Vertically center the text. + SA_BOTTOM = 2 << 2, ///< Bottom align the text. + SA_VERT_MASK = 3 << 2, ///< Mask for vertical alignment. + + SA_CENTER = SA_HOR_CENTER | SA_VERT_CENTER, ///< Center both horizontally and vertically. + + SA_FORCE = 1 << 4, ///< Force the alignment, i.e. don't swap for RTL languages. +}; +DECLARE_ENUM_AS_BIT_SET(StringAlignment) + #endif /* GFX_TYPE_H */ diff --git a/src/gfxinit.cpp b/src/gfxinit.cpp index 7e2c2cc625..c0ba4c4d4d 100644 --- a/src/gfxinit.cpp +++ b/src/gfxinit.cpp @@ -244,6 +244,28 @@ static void LoadSpriteTables() } +static void RealChangeBlitter(const char *repl_blitter) +{ + const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName(); + if (strcmp(cur_blitter, repl_blitter) == 0) return; + + DEBUG(driver, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter); + Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter); + if (new_blitter == nullptr) NOT_REACHED(); + DEBUG(driver, 1, "Successfully switched to %s.", repl_blitter); + + if (!VideoDriver::GetInstance()->AfterBlitterChange()) { + /* Failed to switch blitter, let's hope we can return to the old one. */ + if (BlitterFactory::SelectBlitter(cur_blitter) == nullptr || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); + } + + /* Clear caches that might have sprites for another blitter. */ + VideoDriver::GetInstance()->ClearSystemSprites(); + ClearFontCache(); + GfxClearSpriteCache(); + ReInitAllWindows(false); +} + /** * Check blitter needed by NewGRF config and switch if needed. * @return False when nothing changed, true otherwise. @@ -309,7 +331,7 @@ static bool SwitchNewGRFBlitter() if (BlitterFactory::GetBlitterFactory(repl_blitter) == nullptr) continue; /* Inform the video driver we want to switch blitter as soon as possible. */ - VideoDriver::GetInstance()->ChangeBlitter(repl_blitter); + VideoDriver::GetInstance()->QueueOnMainThread(std::bind(&RealChangeBlitter, repl_blitter)); break; } @@ -323,7 +345,7 @@ void CheckBlitter() ClearFontCache(); GfxClearSpriteCache(); - ReInitAllWindows(); + ReInitAllWindows(false); } /** Initialise and load all the sprites. */ diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index e44bd1e701..7a650aae80 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -21,6 +21,7 @@ #include "sortlist_type.h" #include "core/geometry_func.hpp" #include "currency.h" +#include "zoom_func.h" #include "widgets/graph_widget.h" @@ -65,11 +66,11 @@ struct GraphLegendWindow : Window { bool rtl = _current_text_dir == TD_RTL; Dimension d = GetSpriteSize(SPR_COMPANY_ICON); - DrawCompanyIcon(cid, rtl ? r.right - d.width - 2 : r.left + 2, r.top + (r.bottom - r.top - d.height) / 2); + DrawCompanyIcon(cid, rtl ? r.right - d.width - ScaleGUITrad(2) : r.left + ScaleGUITrad(2), CenterBounds(r.top, r.bottom, d.height)); SetDParam(0, cid); SetDParam(1, cid); - DrawString(r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : (d.width + 4)), r.right - (rtl ? (d.width + 4) : (uint)WD_FRAMERECT_RIGHT), r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE); + DrawString(r.left + (rtl ? (uint)WD_FRAMERECT_LEFT : (d.width + ScaleGUITrad(4))), r.right - (rtl ? (d.width + ScaleGUITrad(4)) : (uint)WD_FRAMERECT_RIGHT), CenterBounds(r.top, r.bottom, FONT_HEIGHT_NORMAL), STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE); } void OnClick(Point pt, int widget, int click_count) override @@ -110,12 +111,13 @@ struct GraphLegendWindow : Window { static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index) { NWidgetVertical *vert = new NWidgetVertical(); - uint line_height = std::max(GetSpriteSize(SPR_COMPANY_ICON).height, FONT_HEIGHT_NORMAL) + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; + uint sprite_height = GetSpriteSize(SPR_COMPANY_ICON, nullptr, ZOOM_LVL_OUT_4X).height; for (int widnum = WID_GL_FIRST_COMPANY; widnum <= WID_GL_LAST_COMPANY; widnum++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_BROWN, widnum); - panel->sizing_type = NWST_STEP; - panel->SetMinimalSize(246, line_height); + panel->sizing_type = NWST_BUTTON; + panel->SetMinimalSize(246, sprite_height); + panel->SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, FS_NORMAL); panel->SetFill(1, 0); panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP); vert->Add(panel); @@ -138,6 +140,7 @@ static const NWidgetPart _nested_graph_legend_widgets[] = { NWidgetFunction(MakeNWidgetCompanyLines), NWidget(NWID_SPACER), SetMinimalSize(2, 0), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), EndContainer(), }; @@ -883,6 +886,7 @@ void ShowCompanyValueGraph() struct PaymentRatesGraphWindow : BaseGraphWindow { uint line_height; ///< Pixel height of each cargo type row. Scrollbar *vscroll; ///< Cargo list scrollbar. + uint legend_width; ///< Width of legend 'blob'. PaymentRatesGraphWindow(WindowDesc *desc, WindowNumber window_number) : BaseGraphWindow(desc, WID_CPR_GRAPH, STR_JUST_CURRENCY_SHORT) @@ -903,6 +907,12 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { this->FinishInitNested(window_number); } + void OnInit() override + { + /* Width of the legend blob. */ + this->legend_width = (FONT_HEIGHT_SMALL - ScaleFontTrad(1)) * 8 / 5; + } + void UpdateExcludedData() { this->excluded_data = 0; @@ -926,7 +936,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { SetDParam(0, cs->name); Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO); - d.width += 14; // colour field + d.width += this->legend_width + 4; // colour field d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(d, *size); @@ -949,6 +959,8 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { int x = r.left + WD_FRAMERECT_LEFT; int y = r.top; + uint row_height = FONT_HEIGHT_SMALL; + int padding = ScaleFontTrad(1); int pos = this->vscroll->GetPosition(); int max = pos + this->vscroll->GetCapacity(); @@ -964,12 +976,12 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { if (lowered) DrawFrameRect(r.left, y, r.right, y + this->line_height - 1, COLOUR_BROWN, lowered ? FR_LOWERED : FR_NONE); byte clk_dif = lowered ? 1 : 0; - int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT); + int rect_x = clk_dif + (rtl ? r.right - this->legend_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT); - GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, PC_BLACK); - GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour); + GfxFillRect(rect_x, y + padding + clk_dif, rect_x + this->legend_width, y + row_height - 1 + clk_dif, PC_BLACK); + GfxFillRect(rect_x + 1, y + padding + 1 + clk_dif, rect_x + this->legend_width - 1, y + row_height - 2 + clk_dif, cs->legend_colour); SetDParam(0, cs->name); - DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); + DrawString(rtl ? r.left : x + this->legend_width + 4 + clk_dif, (rtl ? r.right - this->legend_width - 4 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO); y += this->line_height; } @@ -999,7 +1011,7 @@ struct PaymentRatesGraphWindow : BaseGraphWindow { } case WID_CPR_MATRIX: { - uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX, 0, this->line_height); + uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CPR_MATRIX); if (row >= this->vscroll->GetCount()) return; const CargoSpec *cs; diff --git a/src/group.h b/src/group.h index 1be8d8b01f..e0f0b91960 100644 --- a/src/group.h +++ b/src/group.h @@ -62,13 +62,19 @@ struct GroupStatistics { static void UpdateAutoreplace(CompanyID company); }; +enum GroupFlags : uint8 { + GF_REPLACE_PROTECTION, ///< If set to true, the global autoreplace has no effect on the group + GF_REPLACE_WAGON_REMOVAL, ///< If set, autoreplace will perform wagon removal on vehicles in this group. + GF_END, +}; + /** Group data. */ struct Group : GroupPool::PoolItem<&_group_pool> { std::string name; ///< Group Name Owner owner; ///< Group Owner VehicleType vehicle_type; ///< Vehicle type of the group - bool replace_protection; ///< If set to true, the global autoreplace have no effect on the group + uint8 flags; ///< Group flags Livery livery; ///< Custom colour scheme for vehicles in this group GroupStatistics statistics; ///< NOSAVE: Statistics and caches on the vehicles in the group. diff --git a/src/group_cmd.cpp b/src/group_cmd.cpp index bf25dae862..bbef35ae23 100644 --- a/src/group_cmd.cpp +++ b/src/group_cmd.cpp @@ -315,7 +315,6 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 if (flags & DC_EXEC) { Group *g = new Group(_current_company); - g->replace_protection = false; g->vehicle_type = vt; g->parent = INVALID_GROUP; @@ -323,10 +322,12 @@ CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3 const Company *c = Company::Get(_current_company); g->livery.colour1 = c->livery[LS_DEFAULT].colour1; g->livery.colour2 = c->livery[LS_DEFAULT].colour2; + if (c->settings.renew_keep_length) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); } else { g->parent = pg->index; g->livery.colour1 = pg->livery.colour1; g->livery.colour2 = pg->livery.colour2; + g->flags = pg->flags; } _new_group_id = g->index; @@ -664,42 +665,50 @@ CommandCost CmdSetGroupLivery(TileIndex tile, DoCommandFlag flags, uint32 p1, ui } /** - * Set replace protection for a group and its sub-groups. + * Set group flag for a group and its sub-groups. * @param g initial group. - * @param protect 1 to set or 0 to clear protection. + * @param set 1 to set or 0 to clear protection. */ -static void SetGroupReplaceProtection(Group *g, bool protect) +static void SetGroupFlag(Group *g, GroupFlags flag, bool set, bool children) { - g->replace_protection = protect; + if (set) { + SetBit(g->flags, flag); + } else { + ClrBit(g->flags, flag); + } + + if (!children) return; for (Group *pg : Group::Iterate()) { - if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect); + if (pg->parent == g->index) SetGroupFlag(pg, flag, set, true); } } /** - * (Un)set global replace protection from a group + * (Un)set group flag from a group * @param tile unused * @param flags type of operation * @param p1 index of group array - * - p1 bit 0-15 : GroupID + * - p1 bit 0-15 : GroupID + * - p1 bit 16-18 : Flag to set, by value not bit. * @param p2 * - p2 bit 0 : 1 to set or 0 to clear protection. * - p2 bit 1 : 1 to apply to sub-groups. * @param text unused * @return the cost of this operation or an error */ -CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +CommandCost CmdSetGroupFlag(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { - Group *g = Group::GetIfValid(p1); + Group *g = Group::GetIfValid(GB(p1, 0, 16)); if (g == nullptr || g->owner != _current_company) return CMD_ERROR; + /* GroupFlags are stored in as an 8 bit bitfield but passed here by value, + * so 3 bits is sufficient to cover each possible value. */ + GroupFlags flag = (GroupFlags)GB(p1, 16, 3); + if (flag >= GroupFlags::GF_END) return CMD_ERROR; + if (flags & DC_EXEC) { - if (HasBit(p2, 1)) { - SetGroupReplaceProtection(g, HasBit(p2, 0)); - } else { - g->replace_protection = HasBit(p2, 0); - } + SetGroupFlag(g, flag, HasBit(p2, 0), HasBit(p2, 1)); SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack()); InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type); diff --git a/src/group_gui.cpp b/src/group_gui.cpp index 5e07168c95..27ef06fa0e 100644 --- a/src/group_gui.cpp +++ b/src/group_gui.cpp @@ -46,25 +46,25 @@ static const NWidgetPart _nested_group_widgets[] = { NWidget(NWID_HORIZONTAL), /* left part */ NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), SetMinimalTextLines(1, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_DEFAULT_VEHICLES), SetFill(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP), SetFill(1, 0), SetResize(0, 1), SetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_GL_LIST_GROUP_SCROLLBAR), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 0), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 1), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_CREATE_GROUP), SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_DELETE_GROUP), SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_RENAME_GROUP), SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_LIVERY_GROUP), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_LIVERY_GROUP), SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_GROUP_LIVERY_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), EndContainer(), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), EndContainer(), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_REPLACE_PROTECTION), SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP), EndContainer(), EndContainer(), @@ -86,14 +86,14 @@ static const NWidgetPart _nested_group_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1), + NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetDataTip(STR_BLACK_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 1), SetResize(1, 0), EndContainer(), - NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP), - NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP), NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), @@ -229,7 +229,7 @@ private: this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_GROUP_COUNT_WITH_SUBGROUP); this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height); - this->tiny_step_height += WD_MATRIX_TOP; + this->tiny_step_height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; this->tiny_step_height = GetMinSizing(NWST_STEP, this->tiny_step_height); return WD_FRAMERECT_LEFT + 8 + @@ -256,7 +256,7 @@ private: { /* Highlight the group if a vehicle is dragged over it */ if (g_id == this->group_over) { - GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP + WD_MATRIX_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]); + GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP + 1, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - 1, _colour_gradient[COLOUR_GREY][7]); } if (g_id == NEW_GROUP) return; @@ -387,7 +387,7 @@ public: resize->height = this->tiny_step_height; /* Minimum height is the height of the list widget minus all and default vehicles... */ - size->height = (this->vli.vtype >= VEH_SHIP ? 3.5 : 7) * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height) - 2 * this->tiny_step_height; + size->height = 4 * GetVehicleListHeight(this->vli.vtype, this->tiny_step_height); /* ... minus the buttons at the bottom ... */ uint max_icon_height = GetSpriteSize(this->GetWidget(WID_GL_CREATE_GROUP)->widget_data).height; @@ -430,11 +430,6 @@ public: *size = maxdim(*size, d); break; } - - case WID_GL_INFO: { - size->height = (FONT_HEIGHT_NORMAL * 3) + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - break; - } } } @@ -540,7 +535,7 @@ public: /* If not a default group and the group has replace protection, show an enabled replace sprite. */ uint16 protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN; - if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && Group::Get(this->vli.index)->replace_protection) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; + if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && HasBit(Group::Get(this->vli.index)->flags, GroupFlags::GF_REPLACE_PROTECTION)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN; this->GetWidget(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype; /* Set text of "group by" dropdown widget. */ @@ -556,11 +551,11 @@ public: { switch (widget) { case WID_GL_ALL_VEHICLES: - DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, ALL_GROUP); + DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP); break; case WID_GL_DEFAULT_VEHICLES: - DrawGroupInfo(r.top + WD_FRAMERECT_TOP, r.left, r.right, DEFAULT_GROUP); + DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP); break; case WID_GL_INFO: { @@ -601,14 +596,14 @@ public: } case WID_GL_LIST_GROUP: { - int y1 = r.top + WD_FRAMERECT_TOP; + int y1 = r.top; int max = std::min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.size()); for (int i = this->group_sb->GetPosition(); i < max; ++i) { const Group *g = this->groups[i]; assert(g->owner == this->owner); - DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, g->replace_protection, g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i])); + DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * LEVEL_WIDTH, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (i + 1 < (int)this->groups.size() && indents[i + 1] > this->indents[i])); y1 += this->tiny_step_height; } @@ -683,7 +678,7 @@ public: break; case WID_GL_LIST_GROUP: { // Matrix Group - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); if (id_g >= this->groups.size()) return; if (groups[id_g]->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) { @@ -805,7 +800,7 @@ public: case WID_GL_REPLACE_PROTECTION: { const Group *g = Group::GetIfValid(this->vli.index); if (g != nullptr) { - DoCommandP(0, this->vli.index, (g->replace_protection ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION); + DoCommandP(0, this->vli.index | (GroupFlags::GF_REPLACE_PROTECTION << 16), (HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION) ? 0 : 1) | (_ctrl_pressed << 1), CMD_SET_GROUP_FLAG); } break; } @@ -829,7 +824,7 @@ public: break; case WID_GL_LIST_GROUP: { // Matrix group - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); GroupID new_g = id_g >= this->groups.size() ? INVALID_GROUP : this->groups[id_g]->index; if (this->group_sel != new_g && g->parent != new_g) { @@ -862,7 +857,7 @@ public: this->group_over = INVALID_GROUP; this->SetDirty(); - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); GroupID new_g = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; DoCommandP(0, new_g, vindex | (_ctrl_pressed || this->grouping == GB_SHARED_ORDERS ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE), new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr); @@ -893,7 +888,11 @@ public: /* We do not support VehicleClicked() here since the contextual action may only make sense for individual vehicles */ if (vindex == v->index) { - ShowVehicleListWindow(v); + if (vehgroup.NumVehicles() == 1) { + ShowVehicleViewWindow(v); + } else { + ShowVehicleListWindow(v); + } } break; } @@ -999,7 +998,7 @@ public: break; case WID_GL_LIST_GROUP: { // ... the list of custom groups. - uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height); + uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP); new_group_over = id_g >= this->groups.size() ? NEW_GROUP : this->groups[id_g]->index; break; } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp index fc6f69c12f..b09dc2a8a5 100644 --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -38,6 +38,7 @@ #include "widgets/dropdown_type.h" #include "widgets/industry_widget.h" #include "clear_map.h" +#include "zoom_func.h" #include "table/strings.h" @@ -283,6 +284,7 @@ class BuildIndustryWindow : public Window { IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_PROBABILITY (if ever) Scrollbar *vscroll; + Dimension legend; ///< Dimension of the legend 'blob'. /** The largest allowed minimum-width of the window, given in line heights */ static const int MAX_MINWIDTH_LINEHEIGHTS = 20; @@ -409,6 +411,10 @@ public: void OnInit() override { + /* Width of the legend blob -- slightly larger than the smallmap legend blob. */ + this->legend.height = FONT_HEIGHT_SMALL; + this->legend.width = this->legend.height * 8 / 5; + this->SetupArrays(); } @@ -421,8 +427,9 @@ public: if (this->index[i] == INVALID_INDUSTRYTYPE) continue; d = maxdim(d, GetStringBoundingBox(GetIndustrySpec(this->index[i])->name)); } - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - d.width += FONT_HEIGHT_NORMAL * 5 / 4 + padding.width; + resize->height = std::max(this->legend.height, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_BUTTON, resize->height); + d.width += this->legend.width + ScaleFontTrad(7) + padding.width; d.height = 5 * resize->height; *size = maxdim(*size, d); break; @@ -513,30 +520,37 @@ public: uint text_offset = FONT_HEIGHT_NORMAL * 5 / 4; if (_current_text_dir == TD_RTL) { icon_right = r.right - WD_MATRIX_RIGHT; - icon_left = icon_right - square_size; - text_right = icon_right - text_offset; + icon_left = icon_right - this->legend.width; + text_right = icon_left - ScaleFontTrad(7); text_left = r.left + WD_MATRIX_LEFT; } else { icon_left = r.left + WD_MATRIX_LEFT; - icon_right = icon_left + square_size; - text_left = icon_left + text_offset; + icon_right = icon_left + this->legend.width; + text_left = icon_right + ScaleFontTrad(7); text_right = r.right - WD_MATRIX_RIGHT; } - int y = Center(r.top, this->resize.step_height); - for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++, y += this->resize.step_height) { + /* Vertical offset for legend icon. */ + int icon_top = (this->resize.step_height - this->legend.height + 1) / 2; + int icon_bottom = icon_top + this->legend.height; + + int y = r.top; + for (byte i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->count; i++) { bool selected = this->selected_index == i + this->vscroll->GetPosition(); if (this->index[i + this->vscroll->GetPosition()] == INVALID_INDUSTRYTYPE) { - DrawString(text_left, text_right, y, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE); + DrawString(text_left, text_right, y + WD_MATRIX_TOP, STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE); + y += this->resize.step_height; continue; } const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll->GetPosition()]); /* Draw the name of the industry in white is selected, otherwise, in orange */ - DrawString(text_left, text_right, y, indsp->name, selected ? TC_WHITE : TC_ORANGE); - GfxFillRect(icon_left, y + 1, icon_right, y + square_size, selected ? PC_WHITE : PC_BLACK); - GfxFillRect(icon_left + 1, y + 2, icon_right - 1, y + square_size - 1, indsp->map_colour); + DrawString(text_left, text_right, y + WD_MATRIX_TOP, indsp->name, selected ? TC_WHITE : TC_ORANGE); + GfxFillRect(icon_left, y + icon_top, icon_right, y + icon_bottom, selected ? PC_WHITE : PC_BLACK); + GfxFillRect(icon_left + 1, y + icon_top + 1, icon_right - 1, y + icon_bottom - 1, indsp->map_colour); + + y += this->resize.step_height; } break; } @@ -1865,11 +1879,13 @@ static const uint MAX_CARGOES = 16; ///< Maximum number of cargoes carried in a /** Data about a single field in the #IndustryCargoesWindow panel. */ struct CargoesField { static const int VERT_INTER_INDUSTRY_SPACE; - static const int HOR_CARGO_BORDER_SPACE; - static const int CARGO_STUB_WIDTH; - static const int HOR_CARGO_WIDTH, HOR_CARGO_SPACE; - static const int VERT_CARGO_SPACE, VERT_CARGO_EDGE; - static const int BLOB_DISTANCE, BLOB_WIDTH, BLOB_HEIGHT; + static const int BLOB_DISTANCE; + + static Dimension legend; + static Dimension cargo_border; + static Dimension cargo_line; + static Dimension cargo_space; + static Dimension cargo_stub; static const int INDUSTRY_LINE_COLOUR; static const int CARGO_LINE_COLOUR; @@ -2033,9 +2049,9 @@ struct CargoesField { int n = this->u.cargo.num_cargoes; if (n % 2 == 0) { - return xpos + cargo_field_width / 2 - (HOR_CARGO_WIDTH + HOR_CARGO_SPACE / 2) * (n / 2); + return xpos + cargo_field_width / 2 - (CargoesField::cargo_line.width + CargoesField::cargo_space.width / 2) * (n / 2); } else { - return xpos + cargo_field_width / 2 - HOR_CARGO_WIDTH / 2 - (HOR_CARGO_WIDTH + HOR_CARGO_SPACE) * (n / 2); + return xpos + cargo_field_width / 2 - CargoesField::cargo_line.width / 2 - (CargoesField::cargo_line.width + CargoesField::cargo_space.width) * (n / 2); } } @@ -2073,13 +2089,13 @@ struct CargoesField { int blob_left, blob_right; if (_current_text_dir == TD_RTL) { blob_right = xpos2 - BLOB_DISTANCE; - blob_left = blob_right - BLOB_WIDTH; + blob_left = blob_right - CargoesField::legend.width; } else { blob_left = xpos + BLOB_DISTANCE; - blob_right = blob_left + BLOB_WIDTH; + blob_right = blob_left + CargoesField::legend.width; } - GfxFillRect(blob_left, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT, blob_right, ypos2 - BLOB_DISTANCE, PC_BLACK); // Border - GfxFillRect(blob_left + 1, ypos2 - BLOB_DISTANCE - BLOB_HEIGHT + 1, blob_right - 1, ypos2 - BLOB_DISTANCE - 1, indsp->map_colour); + GfxFillRect(blob_left, ypos2 - BLOB_DISTANCE - CargoesField::legend.height, blob_right, ypos2 - BLOB_DISTANCE, PC_BLACK); // Border + GfxFillRect(blob_left + 1, ypos2 - BLOB_DISTANCE - CargoesField::legend.height + 1, blob_right - 1, ypos2 - BLOB_DISTANCE - 1, indsp->map_colour); } else { DrawString(xpos, xpos2, ypos, STR_INDUSTRY_CARGOES_HOUSES, TC_FROMSTRING, SA_HOR_CENTER); } @@ -2093,21 +2109,21 @@ struct CargoesField { other_right = this->u.industry.other_produced; other_left = this->u.industry.other_accepted; } - ypos1 += VERT_CARGO_EDGE; + ypos1 += CargoesField::cargo_border.height + (FONT_HEIGHT_NORMAL - CargoesField::cargo_line.height) / 2; for (uint i = 0; i < CargoesField::max_cargoes; i++) { if (other_right[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(other_right[i]); - int xp = xpos + industry_width + CARGO_STUB_WIDTH; + int xp = xpos + industry_width + CargoesField::cargo_stub.width; DrawHorConnection(xpos + industry_width, xp - 1, ypos1, csp); - GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + GfxDrawLine(xp, ypos1, xp, ypos1 + CargoesField::cargo_line.height - 1, CARGO_LINE_COLOUR); } if (other_left[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(other_left[i]); - int xp = xpos - CARGO_STUB_WIDTH; + int xp = xpos - CargoesField::cargo_stub.width; DrawHorConnection(xp + 1, xpos - 1, ypos1, csp); - GfxDrawLine(xp, ypos1, xp, ypos1 + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + GfxDrawLine(xp, ypos1, xp, ypos1 + CargoesField::cargo_line.height - 1, CARGO_LINE_COLOUR); } - ypos1 += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + ypos1 += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height; } break; } @@ -2118,15 +2134,15 @@ struct CargoesField { int bot = ypos - (this->u.cargo.bottom_end ? VERT_INTER_INDUSTRY_SPACE / 2 + 1 : 0) + normal_height - 1; int colpos = cargo_base; for (int i = 0; i < this->u.cargo.num_cargoes; i++) { - if (this->u.cargo.top_end) GfxDrawLine(colpos, top - 1, colpos + HOR_CARGO_WIDTH - 1, top - 1, CARGO_LINE_COLOUR); - if (this->u.cargo.bottom_end) GfxDrawLine(colpos, bot + 1, colpos + HOR_CARGO_WIDTH - 1, bot + 1, CARGO_LINE_COLOUR); + if (this->u.cargo.top_end) GfxDrawLine(colpos, top - 1, colpos + CargoesField::cargo_line.width - 1, top - 1, CARGO_LINE_COLOUR); + if (this->u.cargo.bottom_end) GfxDrawLine(colpos, bot + 1, colpos + CargoesField::cargo_line.width - 1, bot + 1, CARGO_LINE_COLOUR); GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); colpos++; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[i]); - GfxFillRect(colpos, top, colpos + HOR_CARGO_WIDTH - 2, bot, csp->legend_colour, FILLRECT_OPAQUE); - colpos += HOR_CARGO_WIDTH - 2; + GfxFillRect(colpos, top, colpos + CargoesField::cargo_line.width - 2, bot, csp->legend_colour, FILLRECT_OPAQUE); + colpos += CargoesField::cargo_line.width - 2; GfxDrawLine(colpos, top, colpos, bot, CARGO_LINE_COLOUR); - colpos += 1 + HOR_CARGO_SPACE; + colpos += 1 + CargoesField::cargo_space.width; } const CargoID *hor_left, *hor_right; @@ -2137,15 +2153,15 @@ struct CargoesField { hor_left = this->u.cargo.supp_cargoes; hor_right = this->u.cargo.cust_cargoes; } - ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; + ypos += CargoesField::cargo_border.height + VERT_INTER_INDUSTRY_SPACE / 2 + (FONT_HEIGHT_NORMAL - CargoesField::cargo_line.height) / 2; for (uint i = 0; i < MAX_CARGOES; i++) { if (hor_left[i] != INVALID_CARGO) { int col = hor_left[i]; int dx = 0; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); for (; col > 0; col--) { - int lf = cargo_base + col * HOR_CARGO_WIDTH + (col - 1) * HOR_CARGO_SPACE; - DrawHorConnection(lf, lf + HOR_CARGO_SPACE - dx, ypos, csp); + int lf = cargo_base + col * CargoesField::cargo_line.width + (col - 1) * CargoesField::cargo_space.width; + DrawHorConnection(lf, lf + CargoesField::cargo_space.width - dx, ypos, csp); dx = 1; } DrawHorConnection(xpos, cargo_base - dx, ypos, csp); @@ -2155,26 +2171,26 @@ struct CargoesField { int dx = 0; const CargoSpec *csp = CargoSpec::Get(this->u.cargo.vertical_cargoes[col]); for (; col < this->u.cargo.num_cargoes - 1; col++) { - int lf = cargo_base + (col + 1) * HOR_CARGO_WIDTH + col * HOR_CARGO_SPACE; - DrawHorConnection(lf + dx - 1, lf + HOR_CARGO_SPACE - 1, ypos, csp); + int lf = cargo_base + (col + 1) * CargoesField::cargo_line.width + col * CargoesField::cargo_space.width; + DrawHorConnection(lf + dx - 1, lf + CargoesField::cargo_space.width - 1, ypos, csp); dx = 1; } - DrawHorConnection(cargo_base + col * HOR_CARGO_SPACE + (col + 1) * HOR_CARGO_WIDTH - 1 + dx, xpos + CargoesField::cargo_field_width - 1, ypos, csp); + DrawHorConnection(cargo_base + col * CargoesField::cargo_space.width + (col + 1) * CargoesField::cargo_line.width - 1 + dx, xpos + CargoesField::cargo_field_width - 1, ypos, csp); } - ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + ypos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height; } break; } case CFT_CARGO_LABEL: - ypos += VERT_CARGO_EDGE + VERT_INTER_INDUSTRY_SPACE / 2; + ypos += CargoesField::cargo_border.height + VERT_INTER_INDUSTRY_SPACE / 2; for (uint i = 0; i < MAX_CARGOES; i++) { if (this->u.cargo_label.cargoes[i] != INVALID_CARGO) { const CargoSpec *csp = CargoSpec::Get(this->u.cargo_label.cargoes[i]); DrawString(xpos + WD_FRAMERECT_LEFT, xpos + industry_width - 1 - WD_FRAMERECT_RIGHT, ypos, csp->name, TC_WHITE, (this->u.cargo_label.left_align) ? SA_LEFT : SA_RIGHT); } - ypos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + ypos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height; } break; @@ -2199,17 +2215,17 @@ struct CargoesField { uint col; for (col = 0; col < this->u.cargo.num_cargoes; col++) { if (pt.x < cpos) break; - if (pt.x < cpos + CargoesField::HOR_CARGO_WIDTH) return this->u.cargo.vertical_cargoes[col]; - cpos += CargoesField::HOR_CARGO_WIDTH + CargoesField::HOR_CARGO_SPACE; + if (pt.x < cpos + (int)CargoesField::cargo_line.width) return this->u.cargo.vertical_cargoes[col]; + cpos += CargoesField::cargo_line.width + CargoesField::cargo_space.width; } /* col = 0 -> left of first col, 1 -> left of 2nd col, ... this->u.cargo.num_cargoes right of last-col. */ - int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; + int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + CargoesField::cargo_border.width; uint row; for (row = 0; row < MAX_CARGOES; row++) { if (pt.y < vpos) return INVALID_CARGO; if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; - vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + vpos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.width; } if (row == MAX_CARGOES) return INVALID_CARGO; @@ -2251,12 +2267,12 @@ struct CargoesField { { assert(this->type == CFT_CARGO_LABEL); - int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + VERT_CARGO_EDGE; + int vpos = VERT_INTER_INDUSTRY_SPACE / 2 + CargoesField::cargo_border.height; uint row; for (row = 0; row < MAX_CARGOES; row++) { if (pt.y < vpos) return INVALID_CARGO; if (pt.y < vpos + FONT_HEIGHT_NORMAL) break; - vpos += FONT_HEIGHT_NORMAL + VERT_CARGO_SPACE; + vpos += FONT_HEIGHT_NORMAL + CargoesField::cargo_space.height; } if (row == MAX_CARGOES) return INVALID_CARGO; return this->u.cargo_label.cargoes[row]; @@ -2273,14 +2289,20 @@ private: static void DrawHorConnection(int left, int right, int top, const CargoSpec *csp) { GfxDrawLine(left, top, right, top, CARGO_LINE_COLOUR); - GfxFillRect(left, top + 1, right, top + FONT_HEIGHT_NORMAL - 2, csp->legend_colour, FILLRECT_OPAQUE); - GfxDrawLine(left, top + FONT_HEIGHT_NORMAL - 1, right, top + FONT_HEIGHT_NORMAL - 1, CARGO_LINE_COLOUR); + GfxFillRect(left, top + 1, right, top + CargoesField::cargo_line.height - 2, csp->legend_colour, FILLRECT_OPAQUE); + GfxDrawLine(left, top + CargoesField::cargo_line.height - 1, right, top + CargoesField::cargo_line.height - 1, CARGO_LINE_COLOUR); } }; static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, produced_cargo)); static_assert(MAX_CARGOES >= cpp_lengthof(IndustrySpec, accepts_cargo)); +Dimension CargoesField::legend; ///< Dimension of the legend blob. +Dimension CargoesField::cargo_border; ///< Dimensions of border between cargo lines and industry boxes. +Dimension CargoesField::cargo_line; ///< Dimensions of cargo lines. +Dimension CargoesField::cargo_space; ///< Dimensions of space between cargo lines. +Dimension CargoesField::cargo_stub; ///< Dimensions of cargo stub (unconnected cargo line.) + int CargoesField::small_height; ///< Height of the header row. int CargoesField::normal_height; ///< Height of the non-header rows. int CargoesField::industry_width; ///< Width of an industry field. @@ -2288,16 +2310,7 @@ int CargoesField::cargo_field_width; ///< Width of a cargo field. uint CargoesField::max_cargoes; ///< Largest number of cargoes actually on any industry. const int CargoesField::VERT_INTER_INDUSTRY_SPACE = 6; ///< Amount of space between two industries in a column. -const int CargoesField::HOR_CARGO_BORDER_SPACE = 15; ///< Amount of space between the left/right edge of a #CFT_CARGO field, and the left/right most vertical cargo. -const int CargoesField::CARGO_STUB_WIDTH = 10; ///< Width of a cargo not carried in the column (should be less than #HOR_CARGO_BORDER_SPACE). -const int CargoesField::HOR_CARGO_WIDTH = 15; ///< Width of a vertical cargo column (inclusive the border line). -const int CargoesField::HOR_CARGO_SPACE = 5; ///< Amount of horizontal space between two vertical cargoes. -const int CargoesField::VERT_CARGO_EDGE = 4; ///< Amount of vertical space between top/bottom and the top/bottom connected cargo at an industry. -const int CargoesField::VERT_CARGO_SPACE = 4; ///< Amount of vertical space between two connected cargoes at an industry. - const int CargoesField::BLOB_DISTANCE = 5; ///< Distance of the industry legend colour from the edge of the industry box. -const int CargoesField::BLOB_WIDTH = 12; ///< Width of the industry legend colour, including border. -const int CargoesField::BLOB_HEIGHT = 9; ///< Height of the industry legend colour, including border const int CargoesField::INDUSTRY_LINE_COLOUR = PC_YELLOW; ///< Line colour of the industry type box. const int CargoesField::CARGO_LINE_COLOUR = PC_YELLOW; ///< Line colour around the cargo. @@ -2468,6 +2481,26 @@ struct IndustryCargoesWindow : public Window { d.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; CargoesField::small_height = d.height; + /* Size of the legend blob -- slightly larger than the smallmap legend blob. */ + CargoesField::legend.height = FONT_HEIGHT_SMALL; + CargoesField::legend.width = CargoesField::legend.height * 8 / 5; + + /* Size of cargo lines. */ + CargoesField::cargo_line.width = FONT_HEIGHT_NORMAL; + CargoesField::cargo_line.height = CargoesField::cargo_line.width; + + /* Size of border between cargo lines and industry boxes. */ + CargoesField::cargo_border.width = CargoesField::cargo_line.width * 3 / 2; + CargoesField::cargo_border.height = CargoesField::cargo_line.width / 2; + + /* Size of space between cargo lines. */ + CargoesField::cargo_space.width = CargoesField::cargo_line.width / 2; + CargoesField::cargo_space.height = CargoesField::cargo_line.height / 2; + + /* Size of cargo stub (unconnected cargo line.) */ + CargoesField::cargo_stub.width = CargoesField::cargo_line.width / 2; + CargoesField::cargo_stub.height = CargoesField::cargo_line.height; /* Unused */ + /* Decide about the size of the box holding the text of an industry type. */ this->ind_textsize.width = 0; this->ind_textsize.height = 0; @@ -2496,21 +2529,23 @@ struct IndustryCargoesWindow : public Window { d.width += 2 * HOR_TEXT_PADDING; /* Ensure the height is enough for the industry type text, for the horizontal connections, and for the cargo labels. */ - uint min_ind_height = CargoesField::VERT_CARGO_EDGE * 2 + CargoesField::max_cargoes * FONT_HEIGHT_NORMAL + (CargoesField::max_cargoes - 1) * CargoesField::VERT_CARGO_SPACE; + uint min_ind_height = CargoesField::cargo_border.height * 2 + CargoesField::max_cargoes * FONT_HEIGHT_NORMAL + (CargoesField::max_cargoes - 1) * CargoesField::cargo_space.height; d.height = std::max(d.height + 2 * VERT_TEXT_PADDING, min_ind_height); CargoesField::industry_width = d.width; CargoesField::normal_height = d.height + CargoesField::VERT_INTER_INDUSTRY_SPACE; /* Width of a #CFT_CARGO field. */ - CargoesField::cargo_field_width = CargoesField::HOR_CARGO_BORDER_SPACE * 2 + CargoesField::HOR_CARGO_WIDTH * CargoesField::max_cargoes + CargoesField::HOR_CARGO_SPACE * (CargoesField::max_cargoes - 1); + CargoesField::cargo_field_width = CargoesField::cargo_border.width * 2 + CargoesField::cargo_line.width * CargoesField::max_cargoes + CargoesField::cargo_space.width * (CargoesField::max_cargoes - 1); } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_IC_PANEL: + resize->height = CargoesField::normal_height; size->width = WD_FRAMETEXT_LEFT + CargoesField::industry_width * 3 + CargoesField::cargo_field_width * 2 + WD_FRAMETEXT_RIGHT; + size->height = WD_FRAMETEXT_TOP + CargoesField::small_height + 2 * resize->height + WD_FRAMETEXT_BOTTOM; break; case WID_IC_IND_DROPDOWN: @@ -2763,8 +2798,7 @@ struct IndustryCargoesWindow : public Window { this->ShortenCargoColumn(1, 1, num_indrows); this->ShortenCargoColumn(3, 1, num_indrows); - const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); - this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); + this->vscroll->SetCount(num_indrows); this->SetDirty(); this->NotifySmallmap(); } @@ -2831,8 +2865,7 @@ struct IndustryCargoesWindow : public Window { } this->ShortenCargoColumn(1, 1, num_indrows); - const NWidgetBase *nwp = this->GetWidget(WID_IC_PANEL); - this->vscroll->SetCount(CeilDiv(WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM + CargoesField::small_height + num_indrows * CargoesField::normal_height, nwp->resize_y)); + this->vscroll->SetCount(num_indrows); this->SetDirty(); this->NotifySmallmap(); } @@ -3079,7 +3112,7 @@ struct IndustryCargoesWindow : public Window { void OnResize() override { - this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL); + this->vscroll->SetCapacityFromWidget(this, WID_IC_PANEL, WD_FRAMERECT_TOP + CargoesField::small_height); } }; diff --git a/src/ini.cpp b/src/ini.cpp index c6864a5b28..46721e118b 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -53,7 +53,7 @@ bool IniFile::SaveToDisk(const std::string &filename) std::string file_new{ filename }; file_new.append(".new"); - std::ofstream os(OTTD2FS(file_new.c_str())); + std::ofstream os(OTTD2FS(file_new).c_str()); if (os.fail()) return false; for (const IniGroup *group = this->group; group != nullptr; group = group->next) { @@ -94,8 +94,8 @@ bool IniFile::SaveToDisk(const std::string &filename) #if defined(_WIN32) /* Allocate space for one more \0 character. */ wchar_t tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; - wcsncpy(tfilename, OTTD2FS(filename.c_str()), MAX_PATH); - wcsncpy(tfile_new, OTTD2FS(file_new.c_str()), MAX_PATH); + wcsncpy(tfilename, OTTD2FS(filename).c_str(), MAX_PATH); + wcsncpy(tfile_new, OTTD2FS(file_new).c_str(), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; tfile_new[MAX_PATH - 1] = '\0'; diff --git a/src/landscape.cpp b/src/landscape.cpp index 9c524bf6c1..6ea3af75b6 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1400,7 +1400,7 @@ static void CalculateSnowLine() static uint8 CalculateDesertLine() { /* CalculateCoverageLine() runs from top to bottom, so we need to invert the coverage. */ - return _settings_game.game_creation.snow_line_height = CalculateCoverageLine(100 - _settings_game.game_creation.desert_coverage, 4); + return CalculateCoverageLine(100 - _settings_game.game_creation.desert_coverage, 4); } void GenerateLandscape(byte mode) diff --git a/src/lang/CMakeLists.txt b/src/lang/CMakeLists.txt index f3aedca4b4..1acf27588f 100644 --- a/src/lang/CMakeLists.txt +++ b/src/lang/CMakeLists.txt @@ -11,6 +11,7 @@ set(LANG_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/brazilian_portuguese.txt ${CMAKE_CURRENT_SOURCE_DIR}/bulgarian.txt ${CMAKE_CURRENT_SOURCE_DIR}/catalan.txt + ${CMAKE_CURRENT_SOURCE_DIR}/chuvash.txt ${CMAKE_CURRENT_SOURCE_DIR}/croatian.txt ${CMAKE_CURRENT_SOURCE_DIR}/czech.txt ${CMAKE_CURRENT_SOURCE_DIR}/danish.txt @@ -22,13 +23,16 @@ set(LANG_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/faroese.txt ${CMAKE_CURRENT_SOURCE_DIR}/finnish.txt ${CMAKE_CURRENT_SOURCE_DIR}/french.txt + ${CMAKE_CURRENT_SOURCE_DIR}/frisian.txt ${CMAKE_CURRENT_SOURCE_DIR}/gaelic.txt ${CMAKE_CURRENT_SOURCE_DIR}/galician.txt ${CMAKE_CURRENT_SOURCE_DIR}/german.txt ${CMAKE_CURRENT_SOURCE_DIR}/greek.txt ${CMAKE_CURRENT_SOURCE_DIR}/hebrew.txt + ${CMAKE_CURRENT_SOURCE_DIR}/hindi.txt ${CMAKE_CURRENT_SOURCE_DIR}/hungarian.txt ${CMAKE_CURRENT_SOURCE_DIR}/icelandic.txt + ${CMAKE_CURRENT_SOURCE_DIR}/ido.txt ${CMAKE_CURRENT_SOURCE_DIR}/indonesian.txt ${CMAKE_CURRENT_SOURCE_DIR}/irish.txt ${CMAKE_CURRENT_SOURCE_DIR}/italian.txt @@ -38,9 +42,13 @@ set(LANG_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/latvian.txt ${CMAKE_CURRENT_SOURCE_DIR}/lithuanian.txt ${CMAKE_CURRENT_SOURCE_DIR}/luxembourgish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/macedonian.txt ${CMAKE_CURRENT_SOURCE_DIR}/malay.txt + ${CMAKE_CURRENT_SOURCE_DIR}/maltese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/marathi.txt ${CMAKE_CURRENT_SOURCE_DIR}/norwegian_bokmal.txt ${CMAKE_CURRENT_SOURCE_DIR}/norwegian_nynorsk.txt + ${CMAKE_CURRENT_SOURCE_DIR}/persian.txt ${CMAKE_CURRENT_SOURCE_DIR}/polish.txt ${CMAKE_CURRENT_SOURCE_DIR}/portuguese.txt ${CMAKE_CURRENT_SOURCE_DIR}/romanian.txt @@ -56,6 +64,7 @@ set(LANG_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/thai.txt ${CMAKE_CURRENT_SOURCE_DIR}/traditional_chinese.txt ${CMAKE_CURRENT_SOURCE_DIR}/turkish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/urdu.txt ${CMAKE_CURRENT_SOURCE_DIR}/ukrainian.txt ${CMAKE_CURRENT_SOURCE_DIR}/vietnamese.txt ${CMAKE_CURRENT_SOURCE_DIR}/welsh.txt diff --git a/src/lang/afrikaans.txt b/src/lang/afrikaans.txt index 873d68c150..51a3a5f58d 100644 --- a/src/lang/afrikaans.txt +++ b/src/lang/afrikaans.txt @@ -990,6 +990,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Kies die STR_GAME_OPTIONS_RESOLUTION_OTHER :ander + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK} Koppelvlak groote STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK} Kies die koppelvlak element groote om te gebruik @@ -1914,6 +1915,7 @@ STR_FACE_TIE :Das: STR_FACE_EARRING :Oorbel: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Verander das of oorbel + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multispeler STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Speler naam: @@ -1972,10 +1974,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Die spel STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Stel wagwoord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskerm jou spel met 'n wagwoord as jy wil dit nie publieke toepassing laat wees nie -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Openbaar -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Kies tussen 'n openbare (internet) of 'n plaaslike (LAN) spel -STR_NETWORK_START_SERVER_UNADVERTISED :Nee -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Klient{P "" e} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimum aantal kliënte: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Kies die maksimum aantal kliënte. Alle posisies hoef nie vol te wees nie @@ -1990,46 +1988,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Ander sp STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Tik 'n naam in vir die netwerk speeletjie -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Enige -STR_NETWORK_LANG_ENGLISH :Engels -STR_NETWORK_LANG_GERMAN :Duits -STR_NETWORK_LANG_FRENCH :Frans -STR_NETWORK_LANG_BRAZILIAN :Brazilian -STR_NETWORK_LANG_BULGARIAN :Bulgarian -STR_NETWORK_LANG_CHINESE :Chinese -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Danish -STR_NETWORK_LANG_DUTCH :Dutch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnish -STR_NETWORK_LANG_HUNGARIAN :Hungarian -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :Italian -STR_NETWORK_LANG_JAPANESE :Japanese -STR_NETWORK_LANG_KOREAN :Korean -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :Norwegian -STR_NETWORK_LANG_POLISH :Polish -STR_NETWORK_LANG_PORTUGUESE :Portuguese -STR_NETWORK_LANG_ROMANIAN :Romanian -STR_NETWORK_LANG_RUSSIAN :Russian -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :Spanish -STR_NETWORK_LANG_SWEDISH :Swedish -STR_NETWORK_LANG_TURKISH :Turkish -STR_NETWORK_LANG_UKRAINIAN :Ukrainian -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatian -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Grieks -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multispeler spel tuiste @@ -2077,19 +2035,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Loskoppe STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Verskaffer is beskerm. Voer wagwoord in STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Maatskappy is beskerm. Voer wagwoord in -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Kliëntelys # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klient Lys -STR_NETWORK_COMPANY_LIST_SPECTATE :Toeskou -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nuwe maatskapy # Network client list -STR_NETWORK_CLIENTLIST_KICK :Skop -STR_NETWORK_CLIENTLIST_BAN :Verbod -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Praat met almal -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Praat met maatskappy -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privaate boodskap + + STR_NETWORK_SERVER :Verskaffer STR_NETWORK_CLIENT :Klient diff --git a/src/lang/arabic_egypt.txt b/src/lang/arabic_egypt.txt index 7fd9ed67f7..2298115146 100644 --- a/src/lang/arabic_egypt.txt +++ b/src/lang/arabic_egypt.txt @@ -965,6 +965,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}تسري STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}حدد هذا المربع للسماح لـ OpenTTD بمحاولة استخدام تسريع الأجهزة. سيتم تطبيق الإعداد الذي تم تغييره فقط عند إعادة تشغيل اللعبة STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}لن يعمل الإعداد إلا بعد إعادة تشغيل اللعبة + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}حجم اللوحة STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}حدد العنصر المطلوب @@ -1610,6 +1611,7 @@ STR_FACE_TIE :الربطة: STR_FACE_EARRING :أقراط الأذان: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}غير الربطة أو أقراط الأذن + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}تعدد اللاعبين STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}أسم اللاعب @@ -1682,46 +1684,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}اللا STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}أدخل أسم اللعبة للشبكة -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :أي -STR_NETWORK_LANG_ENGLISH :إنجليزي -STR_NETWORK_LANG_GERMAN :ألماني -STR_NETWORK_LANG_FRENCH :فرنسي -STR_NETWORK_LANG_BRAZILIAN :برازيلي -STR_NETWORK_LANG_BULGARIAN :بلغاري -STR_NETWORK_LANG_CHINESE :صيني -STR_NETWORK_LANG_CZECH :شيكي -STR_NETWORK_LANG_DANISH :دانماركي -STR_NETWORK_LANG_DUTCH :هولندي -STR_NETWORK_LANG_ESPERANTO :اسبرانتو -STR_NETWORK_LANG_FINNISH :الفنلندية -STR_NETWORK_LANG_HUNGARIAN :هنغاري -STR_NETWORK_LANG_ICELANDIC :الأيسلاندية -STR_NETWORK_LANG_ITALIAN :إيطالي -STR_NETWORK_LANG_JAPANESE :يابانية -STR_NETWORK_LANG_KOREAN :كورية -STR_NETWORK_LANG_LITHUANIAN :اللتوانية -STR_NETWORK_LANG_NORWEGIAN :نرويجية -STR_NETWORK_LANG_POLISH :البولندية -STR_NETWORK_LANG_PORTUGUESE :برتغالية -STR_NETWORK_LANG_ROMANIAN :رومانية -STR_NETWORK_LANG_RUSSIAN :روسية -STR_NETWORK_LANG_SLOVAK :السلوفاكية -STR_NETWORK_LANG_SLOVENIAN :السلوفانية -STR_NETWORK_LANG_SPANISH :أسبانية -STR_NETWORK_LANG_SWEDISH :سويدية -STR_NETWORK_LANG_TURKISH :تركية -STR_NETWORK_LANG_UKRAINIAN :الأوكرانية -STR_NETWORK_LANG_AFRIKAANS :الأفريقية -STR_NETWORK_LANG_CROATIAN :كرواتية -STR_NETWORK_LANG_CATALAN :الكاتالوينية -STR_NETWORK_LANG_ESTONIAN :الأستونية -STR_NETWORK_LANG_GALICIAN :الجاليكية -STR_NETWORK_LANG_GREEK :اليونانية -STR_NETWORK_LANG_LATVIAN :اللاتفية -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}ردهة تعدد اللاعبين @@ -1772,15 +1734,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}الشر # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :قائمة العملاء -STR_NETWORK_COMPANY_LIST_SPECTATE :شاهد -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :شركة جديدة # Network client list -STR_NETWORK_CLIENTLIST_KICK :اطرد -STR_NETWORK_CLIENTLIST_BAN :بان -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :تحدث مع الكل -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :تحدث لشركة -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :رسالة خاصة + + STR_NETWORK_SERVER :خادم STR_NETWORK_CLIENT :عميل diff --git a/src/lang/basque.txt b/src/lang/basque.txt index b2edb2195b..0b597aa1b8 100644 --- a/src/lang/basque.txt +++ b/src/lang/basque.txt @@ -961,6 +961,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Pantaila STR_GAME_OPTIONS_RESOLUTION_OTHER :besteak + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interfaze tamaina STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normala @@ -1789,6 +1790,7 @@ STR_FACE_TIE :Korbata: STR_FACE_EARRING :Belarritakoak: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Aldatu korbata eta belarritakoak + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijokalaria STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Jokalariaren izena: @@ -1847,8 +1849,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Jokoaren STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Pasahitza ezarri STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Babestu zure jokoa pasahitz batekin ez baduzu nahi publikoa izatea -STR_NETWORK_START_SERVER_UNADVERTISED :Ez -STR_NETWORK_START_SERVER_ADVERTISED :Bai STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Bezero STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Gehienezko bezeroak: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Gehienezko bezero kopurua aukeratu. Ez da beharrezkoa guztia betetzea @@ -1863,46 +1863,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Beste jo STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Sare joko batentzako izena sartu -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Edozein -STR_NETWORK_LANG_ENGLISH :Ingelera -STR_NETWORK_LANG_GERMAN :Alemaniera -STR_NETWORK_LANG_FRENCH :Frantsesa -STR_NETWORK_LANG_BRAZILIAN :Brasilera -STR_NETWORK_LANG_BULGARIAN :Bulgariera -STR_NETWORK_LANG_CHINESE :Txinera -STR_NETWORK_LANG_CZECH :Txekiera -STR_NETWORK_LANG_DANISH :Danimarkiera -STR_NETWORK_LANG_DUTCH :Holandera -STR_NETWORK_LANG_ESPERANTO :Esperantoa -STR_NETWORK_LANG_FINNISH :Finlandera -STR_NETWORK_LANG_HUNGARIAN :Hungariera -STR_NETWORK_LANG_ICELANDIC :Islandiera -STR_NETWORK_LANG_ITALIAN :Italiera -STR_NETWORK_LANG_JAPANESE :Japoniera -STR_NETWORK_LANG_KOREAN :Koreera -STR_NETWORK_LANG_LITHUANIAN :Lituaniera -STR_NETWORK_LANG_NORWEGIAN :Norbegiera -STR_NETWORK_LANG_POLISH :Poloniera -STR_NETWORK_LANG_PORTUGUESE :Portugesa -STR_NETWORK_LANG_ROMANIAN :Errumaniera -STR_NETWORK_LANG_RUSSIAN :Errusiera -STR_NETWORK_LANG_SLOVAK :Eslabiera -STR_NETWORK_LANG_SLOVENIAN :Eslobeniera -STR_NETWORK_LANG_SPANISH :Gaztelera -STR_NETWORK_LANG_SWEDISH :Suediera -STR_NETWORK_LANG_TURKISH :Turkiera -STR_NETWORK_LANG_UKRAINIAN :Ukrainera -STR_NETWORK_LANG_AFRIKAANS :Afrikaanera -STR_NETWORK_LANG_CROATIAN :Kroatiera -STR_NETWORK_LANG_CATALAN :Katalana -STR_NETWORK_LANG_ESTONIAN :Estoniera -STR_NETWORK_LANG_GALICIAN :Galiziera -STR_NETWORK_LANG_GREEK :Greziera -STR_NETWORK_LANG_LATVIAN :Letoniera -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multijokalari joko itxia @@ -1953,15 +1913,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Konpaini # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Bezero zerrenda -STR_NETWORK_COMPANY_LIST_SPECTATE :Ikusle -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Konpainia berria # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kanporatu -STR_NETWORK_CLIENTLIST_BAN :Debekatu -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Guztiei hitz egin -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Konpainiari hitz egin -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mezu pribatua + + STR_NETWORK_SERVER :Zerbitzaria STR_NETWORK_CLIENT :Bezeroa diff --git a/src/lang/belarusian.txt b/src/lang/belarusian.txt index 3117632c8b..98f2c8710e 100644 --- a/src/lang/belarusian.txt +++ b/src/lang/belarusian.txt @@ -1299,6 +1299,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Выба STR_GAME_OPTIONS_RESOLUTION_OTHER :Iншае + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Памер элементаў інтэрфейсу STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Выберыце памер элементаў інтэрфейсу @@ -2224,6 +2225,7 @@ STR_FACE_TIE :Гальшту STR_FACE_EARRING :Завушніца: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Зьмяніць гальштук або завушніцу + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Сеткавая гульня STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Імя гульца: @@ -2282,10 +2284,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Назв STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Усталяваць пароль STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Абараніце вашу гульню паролем, калі ня хочаце рабіць яе публічна даступнай -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Інтэрнэт -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Выберыце паміж гульнёй праз Інтэрнэт або ў лакальнай сетцы -STR_NETWORK_START_SERVER_UNADVERTISED :Не -STR_NETWORK_START_SERVER_ADVERTISED :Так STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клiент{P "" ы аў} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. колькасьць клiентаў: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Выбар максымальнай колькасьці кліентаў. Ня ўсе месцы павінны быць занятыя @@ -2300,46 +2298,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Іншы STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Увядзіце назву сеткавай гульні -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Любая -STR_NETWORK_LANG_ENGLISH :Анґельская -STR_NETWORK_LANG_GERMAN :Нямецкая -STR_NETWORK_LANG_FRENCH :Француская -STR_NETWORK_LANG_BRAZILIAN :Бразыльская -STR_NETWORK_LANG_BULGARIAN :Балґарская -STR_NETWORK_LANG_CHINESE :Кітайская -STR_NETWORK_LANG_CZECH :Чэская -STR_NETWORK_LANG_DANISH :Дацкая -STR_NETWORK_LANG_DUTCH :Нідэрляндзкая -STR_NETWORK_LANG_ESPERANTO :Эспэранта -STR_NETWORK_LANG_FINNISH :Фінская -STR_NETWORK_LANG_HUNGARIAN :Вугорская -STR_NETWORK_LANG_ICELANDIC :Ісьляндзкая -STR_NETWORK_LANG_ITALIAN :Італьянская -STR_NETWORK_LANG_JAPANESE :Японская -STR_NETWORK_LANG_KOREAN :Карэйская -STR_NETWORK_LANG_LITHUANIAN :Летувіская -STR_NETWORK_LANG_NORWEGIAN :Нарвэская -STR_NETWORK_LANG_POLISH :Польская -STR_NETWORK_LANG_PORTUGUESE :Партуґальская -STR_NETWORK_LANG_ROMANIAN :Румынская -STR_NETWORK_LANG_RUSSIAN :Расейская -STR_NETWORK_LANG_SLOVAK :Славацкая -STR_NETWORK_LANG_SLOVENIAN :Славенская -STR_NETWORK_LANG_SPANISH :Гішпанская -STR_NETWORK_LANG_SWEDISH :Швэдзкая -STR_NETWORK_LANG_TURKISH :Турэцкая -STR_NETWORK_LANG_UKRAINIAN :Украінская -STR_NETWORK_LANG_AFRIKAANS :Афрыкаанс -STR_NETWORK_LANG_CROATIAN :Харвацкая -STR_NETWORK_LANG_CATALAN :Каталёнская -STR_NETWORK_LANG_ESTONIAN :Эстонская -STR_NETWORK_LANG_GALICIAN :Ґалісійская -STR_NETWORK_LANG_GREEK :Грэцкая -STR_NETWORK_LANG_LATVIAN :Латыская -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Вітальня сеткавай гульні @@ -2387,19 +2345,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Адлу STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Сэрвэр абаронены. Увядзіце пароль STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Кампанія абароненая. Увядзіце пароль -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Сьпіс кліентаў # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Сьпіс кліентаў -STR_NETWORK_COMPANY_LIST_SPECTATE :Назіраць -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Новая кампанія # Network client list -STR_NETWORK_CLIENTLIST_KICK :Выкінуць гульца -STR_NETWORK_CLIENTLIST_BAN :Бан -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Пагутарыць з усімі -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Пагутарыць з кампаніяй -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Прыватнае паведамленьне + + STR_NETWORK_SERVER :Сэрвэр STR_NETWORK_CLIENT :Кліент diff --git a/src/lang/brazilian_portuguese.txt b/src/lang/brazilian_portuguese.txt index db02affc69..b326554e48 100644 --- a/src/lang/brazilian_portuguese.txt +++ b/src/lang/brazilian_portuguese.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Dirigem na esquerda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Dirigem na direita -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das cidades +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nome das cidades: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selecionar o estilo dos nomes das cidades ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :A cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecionar o idioma da interface do jogo +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% concluído) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Tela cheia STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marcar esta caixa para jogar OpenTTD modo de tela cheia @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Marque esta caixa para permitir que o OpenTTD tente usar a aceleração de hardware. Qualquer mudança nesta configuração só será aplicada após reiniciar o jogo. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}A configuração só terá efeito após reiniciar o jogo +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Marque esta caixa para habilitar o v-sync na tela. Qualquer mudança nesta configuração só será aplicada após reiniciar o jogo. Só funciona com a aceleração de hardware habilitada + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamanho da interface STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Selecione o tamanho de elemento de interface a ser usado @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configur STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtro: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Maximizar tudo STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Minimizar tudo +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Redefinir todos os parâmetros STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(não há explicação disponível) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valor padrão: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Tipo de config.: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Config. do jogo STR_CONFIG_SETTING_TYPE_GAME_INGAME :Config. do jogo (guardado no savegame; afeta apenas jogo atual) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Config. da companhia (guardado no savegame; afeta apenas novos jogos) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Config. da companhia (guardado no savegame; afeta apenas a comp. atual) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Cuidado! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Essa ação irá restaurar todas as configurações para os valores padrão.{}Tem certeza que deseja continuar? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipo: @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Gravata: STR_FACE_EARRING :Brinco: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Alterar gravata ou brinco +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multi-jogador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nome: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}O nome d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Definir senha STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteja o jogo com uma senha se não desejar que seja publicamente acessível -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :[BLACK}Publicado -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Selecione entre um jogo publicado (internet) ou não publicado (Rede de Área Local, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Não -STR_NETWORK_START_SERVER_ADVERTISED :Sim +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidade +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se outras pessoas podem ver seu servidor na lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Num máx de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Escolha o número máximo de clientes. Não é necessário estarem todos preenchidos @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Outros j STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Coloque o nome para o jogo em rede -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Qualquer -STR_NETWORK_LANG_ENGLISH :Inglês -STR_NETWORK_LANG_GERMAN :Alemão -STR_NETWORK_LANG_FRENCH :Francês -STR_NETWORK_LANG_BRAZILIAN :Brasileiro -STR_NETWORK_LANG_BULGARIAN :Búlgaro -STR_NETWORK_LANG_CHINESE :Chinês -STR_NETWORK_LANG_CZECH :Checo -STR_NETWORK_LANG_DANISH :Dinamarquês -STR_NETWORK_LANG_DUTCH :Holandês -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finlandês -STR_NETWORK_LANG_HUNGARIAN :Húngaro -STR_NETWORK_LANG_ICELANDIC :Islandês -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Japonês -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Norueguês -STR_NETWORK_LANG_POLISH :Polandês -STR_NETWORK_LANG_PORTUGUESE :Português -STR_NETWORK_LANG_ROMANIAN :Romeno -STR_NETWORK_LANG_RUSSIAN :Russo -STR_NETWORK_LANG_SLOVAK :Eslovaco -STR_NETWORK_LANG_SLOVENIAN :Esloveno -STR_NETWORK_LANG_SPANISH :Espanhol -STR_NETWORK_LANG_SWEDISH :Sueco -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraniano -STR_NETWORK_LANG_AFRIKAANS :Africano -STR_NETWORK_LANG_CROATIAN :Croata -STR_NETWORK_LANG_CATALAN :Catalão -STR_NETWORK_LANG_ESTONIAN :Estoniano -STR_NETWORK_LANG_GALICIAN :Galego -STR_NETWORK_LANG_GREEK :Grego -STR_NETWORK_LANG_LATVIAN :Letão -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sala de espera do jogo @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desconec STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor está protegido. Digite a senha STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa está protegida. Digite a senha -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista de clientes # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes -STR_NETWORK_COMPANY_LIST_SPECTATE :Assistir -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova Companhia +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jogadores online # Network client list -STR_NETWORK_CLIENTLIST_KICK :Banir -STR_NETWORK_CLIENTLIST_BAN :Banir -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Falar com todos -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Falar com a empresa -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mensagem privada +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijogador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nome do servidor que você está jogando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edita o nome do seu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nome do servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidade +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se outras pessoas podem ver seu servidor na lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Edita seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Seu nome de jogador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Ações administrativas a serem executadas para esse cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Ações administrativas a serem executadas para essa empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Junta-se a essa empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envia uma mensagem a esse jogador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envia uma mensagem a todos os jogadores dessa empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envia uma mensagem a todos os espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Cria uma nova empresa e se une a ela +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Esse é você +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Esse é o hospedeiro do jogo + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Banir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Excluir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Desbloqueio com senha + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Ação de administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Você tem certeza que quer expulsar o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Você tem certeza que quer banir o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Você tem certeza que quer excluir a empresa '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Você tem certeza que quer restaurar a senha da empresa '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Não foi STR_NETWORK_ERROR_CLIENT_START :{WHITE}Não foi possível estabelecer conexão STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tempo de espera esgotado na conexão #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Ocorreu um erro de protocolo e a conexão foi encerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Seu nome de jogador não foi definido. O nome pode ser definido no topo da janela de Multijogador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}A versão deste cliente não condiz com a versão do servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Senha incorreta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}O servidor está cheio @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Você de STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Seu computador é lento demais para acompanhar o servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Seu computador demorou demais para baixar o mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Seu computador demorou demais para entrar no servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Seu nome de jogador não é válido ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erro geral @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :não recebeu se STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :tempo esgotado STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :a baixa do mapa demorou demais STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :o processamento do mapa demorou demais +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nome de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possível perda de conexão @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construi STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Posicione a bóia, que pode ser usada como ponto de rota. Shift altera construção/preço estimado STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Construir aqueduto. Shift altera construção/preço estimado STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define área com água.{}Faz um canal, a menos se CTRL for pressionado ao nível do mar, neste caso inundará ao redor -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Criar rios +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Criar rios. Ctrl seleciona a área na diagonal # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orientação do Depósito Naval @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atenção: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erro: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Erro Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Um erro de NewGRF fatal ocorreu:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Um erro NewGRF ocorreu:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} não irá funcionar com a versão do TTDPatch encontrada pelo OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} funciona na versão {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} é projetado para ser usado com {STRING} diff --git a/src/lang/bulgarian.txt b/src/lang/bulgarian.txt index 343c8fd42d..f175c91715 100644 --- a/src/lang/bulgarian.txt +++ b/src/lang/bulgarian.txt @@ -969,6 +969,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Избо STR_GAME_OPTIONS_RESOLUTION_OTHER :друго + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Интерфейс размер STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Изберете размера на интерфейс елемент за използване @@ -1835,6 +1836,7 @@ STR_FACE_TIE :Вратовр STR_FACE_EARRING :Oбица: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cмени вратовръзкатa или oбицатa + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Онлайн играчи STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Име на играч: @@ -1893,10 +1895,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Имет STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Поставяне на парола STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Защитаване на вашата игра с парола за да не е публично достъпна -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Рекламирана -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Избери игра измежду рекламирана през интернет или нерекламирана през Локален интернет хост или ЛАН -STR_NETWORK_START_SERVER_UNADVERTISED :Не -STR_NETWORK_START_SERVER_ADVERTISED :Да STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клиент{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. брой играчи: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Избор на максималния брой клиенти. Не всички слотове трябва да се попълнят @@ -1911,46 +1909,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Друг STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Въведете име за мрежовата игра -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Всеки -STR_NETWORK_LANG_ENGLISH :Английски -STR_NETWORK_LANG_GERMAN :Немски -STR_NETWORK_LANG_FRENCH :Френски -STR_NETWORK_LANG_BRAZILIAN :Бразилски -STR_NETWORK_LANG_BULGARIAN :Български -STR_NETWORK_LANG_CHINESE :Китайски -STR_NETWORK_LANG_CZECH :Чешки -STR_NETWORK_LANG_DANISH :Датски -STR_NETWORK_LANG_DUTCH :Холандски -STR_NETWORK_LANG_ESPERANTO :Eсперанто -STR_NETWORK_LANG_FINNISH :Финландски -STR_NETWORK_LANG_HUNGARIAN :Унгарски -STR_NETWORK_LANG_ICELANDIC :Исландски -STR_NETWORK_LANG_ITALIAN :Италиански -STR_NETWORK_LANG_JAPANESE :Японски -STR_NETWORK_LANG_KOREAN :Корейски -STR_NETWORK_LANG_LITHUANIAN :Литовски -STR_NETWORK_LANG_NORWEGIAN :Норвежки -STR_NETWORK_LANG_POLISH :Полски -STR_NETWORK_LANG_PORTUGUESE :Португалски -STR_NETWORK_LANG_ROMANIAN :Румънски -STR_NETWORK_LANG_RUSSIAN :Руски -STR_NETWORK_LANG_SLOVAK :Словашки -STR_NETWORK_LANG_SLOVENIAN :Словенски -STR_NETWORK_LANG_SPANISH :Испански -STR_NETWORK_LANG_SWEDISH :Шведски -STR_NETWORK_LANG_TURKISH :Турски -STR_NETWORK_LANG_UKRAINIAN :Украински -STR_NETWORK_LANG_AFRIKAANS :Африкаанс -STR_NETWORK_LANG_CROATIAN :Хърватски -STR_NETWORK_LANG_CATALAN :Каталонски -STR_NETWORK_LANG_ESTONIAN :Естонски -STR_NETWORK_LANG_GALICIAN :Галиматия -STR_NETWORK_LANG_GREEK :Гръцки -STR_NETWORK_LANG_LATVIAN :Латвийски -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Преддверие на мрежовите игри @@ -2001,15 +1959,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Комп # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Списък с играчите -STR_NETWORK_COMPANY_LIST_SPECTATE :Наблюдавай -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Нова фирма # Network client list -STR_NETWORK_CLIENTLIST_KICK :Изгони -STR_NETWORK_CLIENTLIST_BAN :Бан -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Кажи на всички -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Кажи на компания -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Лично съобщение + + STR_NETWORK_SERVER :Сървър STR_NETWORK_CLIENT :Клиент diff --git a/src/lang/catalan.txt b/src/lang/catalan.txt index 3b9df8b37f..f46cf68995 100644 --- a/src/lang/catalan.txt +++ b/src/lang/catalan.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit (MYR) STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conducció per l'esquerra STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conducció per la dreta -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Estil dels noms de poblacions +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Estil dels noms de les poblacions: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selecciona l'estil dels noms de poblacions ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 mesos STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecciona l'idioma de la interfície +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% completed) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marqueu la casella per mostrar l'OpenTTD a pantalla completa. @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Accelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Seleccioneu aquesta opció per permetre que l'OpenTTD provi d'usar acceleració per maquinari. Si es canvia l'opció, s'aplicarà quan es reiniciï el programa. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}La configuració tindrà efecte quan es reiniciï el programa. +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Selecciona aquesta casella per activar la sincronització vertical de la pantalla. Els canvis s'aplicaran quan es reiniciï el programa. Només funciona si s'activa l'acceleració per maquinari. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Mida de la interfície STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Escull la mida dels elements de la interfície @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configur STR_CONFIG_SETTING_FILTER_TITLE :{G=Femenin}{BLACK}Cadena de filtrat: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Desplega-ho tot STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Plega-ho tot +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Restableix tots els valors STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(cap explicació disponible) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valor per defecte: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Tipus de paràmetre: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Paràmetre de l STR_CONFIG_SETTING_TYPE_GAME_INGAME :Paràmetre de la partida (emmagatzemat a la partida actual; només afecta la partida actual) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Paràmetre de la companyia (emmagatzemat a les partides; només afectarà les partides noves) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Paràmetre de la companyia (emmagatzemat a la partida actual; només afecta la companyia actual) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Avís! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Aquesta acció restablirà la configuració de la partida als seus valors per defecte.{}Esteu segur que voleu fer-ho? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipus: @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Arracades: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Canvia la corbata o les arracades +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privada +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Pública + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nom del jugador: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}El nom d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Posa una contrasenya STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protegeix la teva partida amb una contrasenya si no vols que sigui accessible a desconeguts -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Anunciat -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Escull entre una partida anunciada (internet) i una partida no anunciada (xarxa d'àrea local, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Sí +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilitat +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Permet establir si altres persones poden veure el vostre servidor a la llista pública. STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Màxim nombre de clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Tria el nombre màxim de clients. No és necessari omplir tots els llocs. @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Els altr STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Posa el nom de la partida en xarxa -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Qualsevol -STR_NETWORK_LANG_ENGLISH :Anglès -STR_NETWORK_LANG_GERMAN :Alemany -STR_NETWORK_LANG_FRENCH :Francès -STR_NETWORK_LANG_BRAZILIAN :Brasiler -STR_NETWORK_LANG_BULGARIAN :Búlgar -STR_NETWORK_LANG_CHINESE :Xinès -STR_NETWORK_LANG_CZECH :Txec -STR_NETWORK_LANG_DANISH :Danès -STR_NETWORK_LANG_DUTCH :Holandès -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finès -STR_NETWORK_LANG_HUNGARIAN :Hongarès -STR_NETWORK_LANG_ICELANDIC :Islandès -STR_NETWORK_LANG_ITALIAN :Italià -STR_NETWORK_LANG_JAPANESE :Japonès -STR_NETWORK_LANG_KOREAN :Coreà -STR_NETWORK_LANG_LITHUANIAN :Lituà -STR_NETWORK_LANG_NORWEGIAN :Noruec -STR_NETWORK_LANG_POLISH :Polonès -STR_NETWORK_LANG_PORTUGUESE :Portuguès -STR_NETWORK_LANG_ROMANIAN :Romanès -STR_NETWORK_LANG_RUSSIAN :Rus -STR_NETWORK_LANG_SLOVAK :Eslovac -STR_NETWORK_LANG_SLOVENIAN :Eslovè -STR_NETWORK_LANG_SPANISH :Espanyol -STR_NETWORK_LANG_SWEDISH :Suec -STR_NETWORK_LANG_TURKISH :Turc -STR_NETWORK_LANG_UKRAINIAN :Ucraïnès -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croat -STR_NETWORK_LANG_CATALAN :Català -STR_NETWORK_LANG_ESTONIAN :Estonià -STR_NETWORK_LANG_GALICIAN :Gallec -STR_NETWORK_LANG_GREEK :Grec -STR_NETWORK_LANG_LATVIAN :Letó -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Lobby de partida multijugador @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desconne STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor protegit: escriviu-ne la contrasenya STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Companyia protegida: escriviu-ne la contrasenya -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Llista de clients # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Llista de clients -STR_NETWORK_COMPANY_LIST_SPECTATE :Espectador -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova companyia +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadors en línia # Network client list -STR_NETWORK_CLIENTLIST_KICK :Breu -STR_NETWORK_CLIENTLIST_BAN :Prohibit -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Parla a tothom -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Parla amb la companyia -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Missatge Privat +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nom del servidor on esteu jugant +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Editeu el nom del vostre servidor. +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nom del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilitat +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Permet establir si altres persones poden veure el vostre servidor a la llista pública. +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}El vostre nom de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Editeu el vostre nom de jugador. +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :El vostre nom de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Accions d'administració que s'han de realitzar per a aquest client. +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Accions d'administració que s'han de realitzar per a aquesta companyia. +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Uniu-vos a aquesta companyia. +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envia un missatge a aquest jugador. +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envia un missatge a tots els jugadors de la companyia. +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envieu un missatge a tots els espectadors. +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadors +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Companyia nova) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una companyia nova i uniu-vos. +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Aquest ets tu. +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Aquest és l'hoste de la partida. + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Treu +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Expulsa +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Esborra +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Desbloca la contrasenya + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acció de l'administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Esteu segur que voleu treure el jugador «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Esteu segur que voleu expulsar el jugador «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Esteu segur que voleu esborrar la companyia «{COMPANY}»? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Esteu segur que voleu restablir la contrasenya de la companyia «{COMPANY}»? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Client @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}No s'ha STR_NETWORK_ERROR_CLIENT_START :{WHITE}No s'ha pogut connectar STR_NETWORK_ERROR_TIMEOUT :{WHITE}La connexió #{NUM} ha esgotat el temps d'espera STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}S'ha obtingut un error de protocol i s'ha tancat la connexió +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}No s'ha escollit un nom per al vostre jugador. El nom es pot establir a la part superior de la finestra de mode multijugador. STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La revisió d'aquest client no concorda amb la revisió del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contrasenya incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor està ple @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Has tard STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}El teu ordinador és massa lent per mantenir-se connectat al servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}El teu ordinador ha tardat massa a descarregar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}El teu ordinador ha tardat massa a unir-se al servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}El vostre nom de jugador no és vàlid. ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :no s'ha rebut l STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :temps d'espera general esgotat STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :la descàrrega del mapa ha tardat massa STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :el processat del mapa ha tardat massa +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nom de client no vàlid ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible pèrdua de connexió @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construe STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Situa una boia que pot ser útil per fer punts de control addicionals. Shift commuta construeix/mostra el cost estimat STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK} Construeix aqüeducte. Shift commuta construeix/mostra el cost estimat STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Defineix caselles com a canals d'aigua.{}Amb Ctrl+Clic a nivell de mar, es defineix una casella de mar i s'inundaran els seus voltants. -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Crea rius i caselles d'aigua. +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Crea rius i caselles d'aigua. Ctrl selecciona l'àrea diagonalment. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Drassanes @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Alerta: {S STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}S'ha produït un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}S'ha produït un error relacionat amb els NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionarà amb la versió TTDPatch informada per l'OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} és per la versió {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} està dissenyat per ser utilitzat amb {STRING} diff --git a/src/lang/unfinished/chuvash.txt b/src/lang/chuvash.txt similarity index 99% rename from src/lang/unfinished/chuvash.txt rename to src/lang/chuvash.txt index e70e1b774c..37567cefc0 100644 --- a/src/lang/unfinished/chuvash.txt +++ b/src/lang/chuvash.txt @@ -520,6 +520,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :расна + # Custom currency window @@ -725,6 +726,7 @@ STR_FACE_COLLAR :Ҫуха: STR_FACE_TIE :Галстук: STR_FACE_EARRING :Алка: + # Network server list STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Вӑйӑҫӑ ят: @@ -768,10 +770,6 @@ STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Вырн -# Network game languages -############ Leave those lines in this order!! -############ End of leave-in-this-order - # Network game lobby @@ -791,6 +789,8 @@ STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Вырн # Network client list + + # Network set password # Network company info join/password diff --git a/src/lang/croatian.txt b/src/lang/croatian.txt index 6c16eeebab..e98abcac4a 100644 --- a/src/lang/croatian.txt +++ b/src/lang/croatian.txt @@ -1086,6 +1086,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Odaberi STR_GAME_OPTIONS_RESOLUTION_OTHER :ostalo + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Veličina sučelja STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Odaberite koju ćete veličinu elementa sučelja koristiti @@ -2019,6 +2020,7 @@ STR_FACE_TIE :Kravata: STR_FACE_EARRING :Naušnica: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Promijeni kravatu ili naušnicu + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Više igrača STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ime igrača: @@ -2077,10 +2079,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Ime igre STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Postavi zaporku STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Zaštiti svoju igru pomoću zaporke ukoliko ne želiš da bude javno dostupna -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Sa oglasima -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Odaberi između igre s oglasima (internet) i bez oglasa (Local Area Network, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Ne -STR_NETWORK_START_SERVER_ADVERTISED :Da STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klijen{P t ta ata} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Najveći broj klijenata: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Odaberi najveći broj klijenata. Ne moraju sva mjesta biti popunjena. @@ -2095,46 +2093,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Drugi ig STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Upišite ime mrežne igre -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Bilo koji -STR_NETWORK_LANG_ENGLISH :Engleski -STR_NETWORK_LANG_GERMAN :Njemački -STR_NETWORK_LANG_FRENCH :Francuski -STR_NETWORK_LANG_BRAZILIAN :Brazilski -STR_NETWORK_LANG_BULGARIAN :Bugarski -STR_NETWORK_LANG_CHINESE :Kineski -STR_NETWORK_LANG_CZECH :Češki -STR_NETWORK_LANG_DANISH :Danski -STR_NETWORK_LANG_DUTCH :Nizozemski -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finski -STR_NETWORK_LANG_HUNGARIAN :Mađarski -STR_NETWORK_LANG_ICELANDIC :Islandski -STR_NETWORK_LANG_ITALIAN :Talijanski -STR_NETWORK_LANG_JAPANESE :Japanski -STR_NETWORK_LANG_KOREAN :Korejski -STR_NETWORK_LANG_LITHUANIAN :Litavski -STR_NETWORK_LANG_NORWEGIAN :Norveški -STR_NETWORK_LANG_POLISH :Poljski -STR_NETWORK_LANG_PORTUGUESE :Portugalski -STR_NETWORK_LANG_ROMANIAN :Rumunjski -STR_NETWORK_LANG_RUSSIAN :Ruski -STR_NETWORK_LANG_SLOVAK :Slovački -STR_NETWORK_LANG_SLOVENIAN :Slovenski -STR_NETWORK_LANG_SPANISH :Španjolski -STR_NETWORK_LANG_SWEDISH :Švedski -STR_NETWORK_LANG_TURKISH :Turski -STR_NETWORK_LANG_UKRAINIAN :Ukrajinski -STR_NETWORK_LANG_AFRIKAANS :afrikaanski -STR_NETWORK_LANG_CROATIAN :hrvatski -STR_NETWORK_LANG_CATALAN :katalonski -STR_NETWORK_LANG_ESTONIAN :estonski -STR_NETWORK_LANG_GALICIAN :galicijski -STR_NETWORK_LANG_GREEK :Grčki -STR_NETWORK_LANG_LATVIAN :Latvijski -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Predvorje igre za više igrača @@ -2182,19 +2140,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Odspoji STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Poslužitelj je zaštićen. Unesite zaporku STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Tvrtka je zaštićena. Unesite zaporku -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Popis klijenata # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Popis klijenata -STR_NETWORK_COMPANY_LIST_SPECTATE :Promatraj -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova tvrtka # Network client list -STR_NETWORK_CLIENTLIST_KICK :Izbaci -STR_NETWORK_CLIENTLIST_BAN :Zabrana -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Razgovaraj sa svima -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Razgovaraj s tvrtkom -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatna poruka + + STR_NETWORK_SERVER :Poslužitelj STR_NETWORK_CLIENT :Klijent diff --git a/src/lang/czech.txt b/src/lang/czech.txt index a134f84f42..0d9c4cd4b2 100644 --- a/src/lang/czech.txt +++ b/src/lang/czech.txt @@ -1093,6 +1093,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardwaro STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Zaškrtni, pokud chceš OpenTTD povolit použití hardwarové akcelerace. Změněné nastavení bude aplikováno po restartu hry STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Nastavení vstoupí v platnost pouze po restartu hry + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Velikost rozhraní STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Zvolit velikost prvků uživatelského rozhraní @@ -2071,6 +2072,7 @@ STR_FACE_TIE :Kravata: STR_FACE_EARRING :Náušnice: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Změnit kravatu nebo náušnice + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Jméno hráče: @@ -2133,10 +2135,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Jméno h STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Nastavit heslo STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Svoji hru si můžeš ochránit heslem, když nechceš, aby se ti do ni hlásili jiní lidé -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Vypsané -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Vyber mezi propagovanou (internet) a nepropagovanou (Místní síť, LAN) hrou -STR_NETWORK_START_SERVER_UNADVERTISED :Ne -STR_NETWORK_START_SERVER_ADVERTISED :Ano STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" i ů} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Nejvyšší počet hráčů: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Zvol nejvyšší počet hráčů. Může se jich připojit i méně @@ -2151,46 +2149,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aby osta STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Zadej jméno této síťové hry -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :jakýkoli -STR_NETWORK_LANG_ENGLISH :angličtina -STR_NETWORK_LANG_GERMAN :němčina -STR_NETWORK_LANG_FRENCH :francouzština -STR_NETWORK_LANG_BRAZILIAN :brazilská portugalština -STR_NETWORK_LANG_BULGARIAN :bulharština -STR_NETWORK_LANG_CHINESE :čínština -STR_NETWORK_LANG_CZECH :čeština -STR_NETWORK_LANG_DANISH :dánština -STR_NETWORK_LANG_DUTCH :nizozemština -STR_NETWORK_LANG_ESPERANTO :esperanto -STR_NETWORK_LANG_FINNISH :finština -STR_NETWORK_LANG_HUNGARIAN :maďarština -STR_NETWORK_LANG_ICELANDIC :islandština -STR_NETWORK_LANG_ITALIAN :italština -STR_NETWORK_LANG_JAPANESE :japonština -STR_NETWORK_LANG_KOREAN :korejština -STR_NETWORK_LANG_LITHUANIAN :litevština -STR_NETWORK_LANG_NORWEGIAN :norština -STR_NETWORK_LANG_POLISH :polština -STR_NETWORK_LANG_PORTUGUESE :portugalština -STR_NETWORK_LANG_ROMANIAN :rumunština -STR_NETWORK_LANG_RUSSIAN :ruština -STR_NETWORK_LANG_SLOVAK :slovenština -STR_NETWORK_LANG_SLOVENIAN :slovinština -STR_NETWORK_LANG_SPANISH :španělština -STR_NETWORK_LANG_SWEDISH :švédština -STR_NETWORK_LANG_TURKISH :turečtina -STR_NETWORK_LANG_UKRAINIAN :ukrajinština -STR_NETWORK_LANG_AFRIKAANS :afrikánština -STR_NETWORK_LANG_CROATIAN :chorvatština -STR_NETWORK_LANG_CATALAN :katalánština -STR_NETWORK_LANG_ESTONIAN :estonština -STR_NETWORK_LANG_GALICIAN :galicijština -STR_NETWORK_LANG_GREEK :řečtina -STR_NETWORK_LANG_LATVIAN :lotyština -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Vstupní místnost do hry více hráčů @@ -2238,19 +2196,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Odpojit STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server je chráněný. Napiš heslo STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Společnost je chráněná. Napiš heslo -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :Seznam klientů # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Seznam hráčů -STR_NETWORK_COMPANY_LIST_SPECTATE :Pozorovat -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nová společnost # Network client list -STR_NETWORK_CLIENTLIST_KICK :Vyhodit -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Napsat všem -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Napsat společnosti -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Soukromá zpráva + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klient diff --git a/src/lang/danish.txt b/src/lang/danish.txt index 1cd8a1c7a9..59191a23b1 100644 --- a/src/lang/danish.txt +++ b/src/lang/danish.txt @@ -991,6 +991,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :andet STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware-acceleration + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}grænseflade størrelse STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vælg den grænseflade størrelse du ønsker at benytte @@ -1928,6 +1929,7 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Ørering: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Ændre slips eller ørering + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Netværksspil STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spiller navn: @@ -1986,10 +1988,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Navnet v STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Sæt kodeord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskyt dit spil med et kodeord hvis du ikke vil have fremmede med -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Offentlig -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Vælg mellem et offentligt (internet) og et ikke offentligt (lokalnetværk, LAN) spil -STR_NETWORK_START_SERVER_UNADVERTISED :Nej -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimalt antal tilladte klienter: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Vælg det maksimale antal klienter. Det er ikke nødvendigt at fylde dem alle @@ -2004,46 +2002,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Andre sp STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Skriv et navn for netværksspillet -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Hvilket som helst -STR_NETWORK_LANG_ENGLISH :Engelsk -STR_NETWORK_LANG_GERMAN :Tysk -STR_NETWORK_LANG_FRENCH :Fransk -STR_NETWORK_LANG_BRAZILIAN :Brasiliansk -STR_NETWORK_LANG_BULGARIAN :Bulgarsk -STR_NETWORK_LANG_CHINESE :Kinesisk -STR_NETWORK_LANG_CZECH :Tjekkisk -STR_NETWORK_LANG_DANISH :Dansk -STR_NETWORK_LANG_DUTCH :Hollandsk -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finsk -STR_NETWORK_LANG_HUNGARIAN :Ungarsk -STR_NETWORK_LANG_ICELANDIC :Islandsk -STR_NETWORK_LANG_ITALIAN :Italiensk -STR_NETWORK_LANG_JAPANESE :Japansk -STR_NETWORK_LANG_KOREAN :Koreansk -STR_NETWORK_LANG_LITHUANIAN :Litauisk -STR_NETWORK_LANG_NORWEGIAN :Norsk -STR_NETWORK_LANG_POLISH :Polsk -STR_NETWORK_LANG_PORTUGUESE :Portugisisk -STR_NETWORK_LANG_ROMANIAN :Rumænsk -STR_NETWORK_LANG_RUSSIAN :Russisk -STR_NETWORK_LANG_SLOVAK :Slovakisk -STR_NETWORK_LANG_SLOVENIAN :Slovensk -STR_NETWORK_LANG_SPANISH :Spansk -STR_NETWORK_LANG_SWEDISH :Svensk -STR_NETWORK_LANG_TURKISH :Tyrkisk -STR_NETWORK_LANG_UKRAINIAN :Ukrainsk -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatisk -STR_NETWORK_LANG_CATALAN :Catalansk -STR_NETWORK_LANG_ESTONIAN :Estisk -STR_NETWORK_LANG_GALICIAN :Galicisk -STR_NETWORK_LANG_GREEK :Græsk -STR_NETWORK_LANG_LATVIAN :Lettisk -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Netværksspils lobby @@ -2091,19 +2049,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Afbryd f STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Serveren er beskyttet. Indtast kodeord STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Selskabet er beskyttet. Indtast kodeord -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Klientliste # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klient liste -STR_NETWORK_COMPANY_LIST_SPECTATE :Tilslut som tilskuer -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nyt firma # Network client list -STR_NETWORK_CLIENTLIST_KICK :Smid ud -STR_NETWORK_CLIENTLIST_BAN :Ban (Forvis spiller) -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Tal til alle -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Tal til selskab -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privat besked + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klient diff --git a/src/lang/dutch.txt b/src/lang/dutch.txt index f659c8f5cb..c920bf0ada 100644 --- a/src/lang/dutch.txt +++ b/src/lang/dutch.txt @@ -953,7 +953,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Maleisische Rin STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Links rijden STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Rechts rijden -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Plaatsnamen +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Plaatsnamen: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Stijl voor plaatsnamen kiezen ############ start of townname region @@ -993,6 +993,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Iedere 12 maand STR_GAME_OPTIONS_LANGUAGE :{BLACK}Taal STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Taal selecteren voor gebruikersscherm +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% voltooid) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Volledig scherm STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Vink dit vakje aan om OpenTTD in het volledige scherm te spelen @@ -1006,6 +1007,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Selecteer dit vakje om OpenTTD hardwareversnelling te laten gebruiken. De gewijzigde instelling wordt pas van kracht nadat het spel opnieuw is gestart. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}De instelling wordt pas van kracht als het spel opnieuw is gestart +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Selecteer dit vakje om het scherm verticaal te synchroniseren. De wijziging gaat pas in nadat je het spel opnieuw hebt opgestart. Werkt alleen als hardwareversnelling is ingeschakeld + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Menupuntgrootte STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Kiest de grootte van bedieningselementen @@ -1138,6 +1142,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Instelli STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtertekst: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Alles uitvouwen STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Alles inklappen +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Alle waarden terugstellen STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(geen uitleg beschikbaar) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standaardwaarde: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Instellingstype: {ORANGE}{STRING} @@ -1146,6 +1151,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Spelinstellinge STR_CONFIG_SETTING_TYPE_GAME_INGAME :Spelinstellingen (opgeslagen in bestand; alleen van invloed op huidig spel) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Bedrijfsinstellingen (opgeslagen in bestand; alleen van invloed op nieuwe spellen) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Bedrijfsinstellingen (opgeslagen in bestand; alleen van invloed op huidig bedrijf) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Voorzichtig! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Met deze actie herstel je alle spelinstellingen naar hun standaardwaarden.{}Weet je zeker dat je wilt doorgaan? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categorie: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: @@ -1984,6 +1991,9 @@ STR_FACE_TIE :Stropdas: STR_FACE_EARRING :Oorbel: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Verander das of oorbel +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privé +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Openbaar + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Netwerkspel STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spelersnaam: @@ -2039,17 +2049,15 @@ STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Vul je n STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Voer het IP-adres van de server in # Start new multiplayer server -STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start nieuw multiplayerspel +STR_NETWORK_START_SERVER_CAPTION :{WHITE}Nieuw spel met meerdere spelers starten STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spelnaam: -STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}De spelnaam wordt weergegeven aan andere spelers in het multiplayerspelselectiemenu +STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}De spelnaam wordt weergegeven aan andere spelers in het spelselectiemenu voor meerdere spelers STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Wachtwoord instellen STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beveilig je spel met een wachtwoord als je niet wilt dat dit algemeen toegankelijk is -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Openbaar -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Kies tussen een openbaar (internet) en een niet-openbaar (Local Area Network, LAN) spel -STR_NETWORK_START_SERVER_UNADVERTISED :Nee -STR_NETWORK_START_SERVER_ADVERTISED :Ja +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Zichtbaarheid +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Bepaalt of andere mensen je server kunnen zien in de openbare lijst STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} speler{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximumaantal spelers: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Kies het maximaal aantal toegestane spelers. Niet alle posities hoeven gebruikt te worden. @@ -2064,46 +2072,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Andere s STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Geef de naam van het netwerkspel -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Elke -STR_NETWORK_LANG_ENGLISH :Engels -STR_NETWORK_LANG_GERMAN :Duits -STR_NETWORK_LANG_FRENCH :Frans -STR_NETWORK_LANG_BRAZILIAN :Braziliaans -STR_NETWORK_LANG_BULGARIAN :Bulgaars -STR_NETWORK_LANG_CHINESE :Chinees -STR_NETWORK_LANG_CZECH :Tsjechisch -STR_NETWORK_LANG_DANISH :Deens -STR_NETWORK_LANG_DUTCH :Nederlands -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fins -STR_NETWORK_LANG_HUNGARIAN :Hongaars -STR_NETWORK_LANG_ICELANDIC :IJslands -STR_NETWORK_LANG_ITALIAN :Italiaans -STR_NETWORK_LANG_JAPANESE :Japans -STR_NETWORK_LANG_KOREAN :Koreaans -STR_NETWORK_LANG_LITHUANIAN :Litouws -STR_NETWORK_LANG_NORWEGIAN :Noors -STR_NETWORK_LANG_POLISH :Pools -STR_NETWORK_LANG_PORTUGUESE :Portugees -STR_NETWORK_LANG_ROMANIAN :Roemeens -STR_NETWORK_LANG_RUSSIAN :Russisch -STR_NETWORK_LANG_SLOVAK :Slowaaks -STR_NETWORK_LANG_SLOVENIAN :Sloveens -STR_NETWORK_LANG_SPANISH :Spaans -STR_NETWORK_LANG_SWEDISH :Zweeds -STR_NETWORK_LANG_TURKISH :Turks -STR_NETWORK_LANG_UKRAINIAN :Oekraïens -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatisch -STR_NETWORK_LANG_CATALAN :Catalaans -STR_NETWORK_LANG_ESTONIAN :Estisch -STR_NETWORK_LANG_GALICIAN :Galiciaans -STR_NETWORK_LANG_GREEK :Grieks -STR_NETWORK_LANG_LATVIAN :Lets -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Verzamelkamer voor netwerkspellen @@ -2151,19 +2119,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Verbindi STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is beveiligd. Voer wachtwoord in STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Bedrijf is beveiligd. Voer wachtwoord in -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Spelerslijst # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spelerslijst -STR_NETWORK_COMPANY_LIST_SPECTATE :Toekijken -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nieuw bedrijf +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spelers online # Network client list -STR_NETWORK_CLIENTLIST_KICK :Uit het spel schoppen -STR_NETWORK_CLIENTLIST_BAN :Verbannen -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Met iedereen praten -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Met bedrijf praten -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privébericht +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Meerdere spelers +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Naam +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}De naam van de server waar je speelt +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}De naam van je server bewerken +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Servernaam +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Zichtbaarheid +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Bepaalt of andere mensen je server kunnen zien in de openbare lijst +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Speler +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Naam +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Je spelernaam +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Je spelernaam bewerken +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Je spelernaam +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Beheeracties die nodig zijn voor deze client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Beheeracties die nodig zijn voor dit bedrijf +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Meedoen met dit bedrijf +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Een bericht sturen naar deze speler +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Een bericht versturen naar alle spelers van dit bedrijf +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Een bericht sturen naar alle toeschouwers +STR_NETWORK_CLIENT_LIST_SPECTATORS :Toeschouwers +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nieuw bedrijf) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Een nieuw bedrijf maken en meedoen +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dit ben jij +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dit is de host van het spel + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Eruit schoppen +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bannen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Verwijderen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Wachtwoord ontgrendelen + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Beheeractie +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Weet je zeker dat je de speler '{STRING}' eruit wilt schoppen? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Weet je zeker dat je de speler '{STRING}' wilt bannen? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Weet je zeker dat je het bedrijf '{COMPANY}' wilt verwijderen? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Weet je zeker dat je het wachtwoord voor bedrijf '{COMPANY}' wilt terugstellen? STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Speler @@ -2208,6 +2203,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Kan serv STR_NETWORK_ERROR_CLIENT_START :{WHITE}Kan geen verbinding maken STR_NETWORK_ERROR_TIMEOUT :{WHITE}Verbinding nr. {NUM} kostte te veel tijd STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Er is een protocolfout gedetecteerd en de verbinding werd gesloten +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Je spelernaam is nog niet ingesteld. Je stelt de naam in bovenin het venster Meerdere spelers STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}De revisie van deze client komt niet overeen met de revisie van de server STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Ongeldig wachtwoord STR_NETWORK_ERROR_SERVER_FULL :{WHITE}De server is vol @@ -2220,6 +2216,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Het invo STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Uw computer is te traag om de server bij te houden STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Uw computer deed er te lang over om de kaart te downloaden STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Uw computer deed er te lang over om met de server te verbinden +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Je spelernaam is niet geldig ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :algemene fout @@ -2242,6 +2239,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :wachtwoord niet STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :algemene time-out STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloaden van de kaart duurde te lang STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :verwerken van de kaart duurde te lang +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :ongeldige clientnaam ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Mogelijk verbinding verbroken @@ -2531,7 +2529,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Haven bo STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Boei plaatsen, deze kan gebruikt worden voor extra tussenstops. Shift schakelt tussen bouwen/inschatting van de kosten STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Aquaduct bouwen. Shift schakelt tussen bouwen/inschatting van de kosten. STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Hiermee plaats je watermassa's.{}Maakt een kanaal, tenzij je Ctrl vasthoudt op zeeniveau, dan overstroomt de omgeving. -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Hiermee maak je rivieren +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Hiermee maak je rivieren. Ctrl selecteert het gebied diagonaal # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Richting van dok @@ -3081,6 +3079,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Waarschuwi STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fout: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatale fout: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Een fatale NewGRF-fout is ontstaan:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Er is een NewGRF-fout opgetreden:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} werkt niet met de TTDPatch-versie die is opgegeven door OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} is voor versie {STRING} van TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} is ontwikkeld voor {STRING} diff --git a/src/lang/english.txt b/src/lang/english.txt index 4f1bbfca0a..935560241b 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -949,7 +949,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Drive on right -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Select style of town names ############ start of townname region @@ -989,6 +989,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{RAW_STRING} ({NUM}% completed) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode @@ -1002,6 +1003,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Check this box to allow OpenTTD to try to use hardware acceleration. A changed setting will only be applied upon game restart STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}The setting will only take effect after a game restart +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Check this box to v-sync the screen. A changed setting will only be applied upon game restart. Only works with hardware acceleration enabled + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interface size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface element size to use @@ -1134,6 +1138,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Settings STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expand all STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Collapse all +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Reset all values STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no explanation available) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Default value: {ORANGE}{STRING1} STR_CONFIG_SETTING_TYPE :{LTBLUE}Setting type: {ORANGE}{STRING} @@ -1142,6 +1147,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Game setting (s STR_CONFIG_SETTING_TYPE_GAME_INGAME :Game setting (stored in save; affects only current game) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Company setting (stored in saves; affects only new games) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Company setting (stored in save; affects only current company) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Caution! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}This action will reset all game settings to their default values.{}Are you sure you want to proceed? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Category: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: @@ -2000,6 +2007,9 @@ STR_FACE_TIE :Tie: STR_FACE_EARRING :Earring: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Private +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: @@ -2062,10 +2072,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Advertised -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Yes +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibility +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximum number of clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled @@ -2080,46 +2088,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other pl STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Any -STR_NETWORK_LANG_ENGLISH :English -STR_NETWORK_LANG_GERMAN :German -STR_NETWORK_LANG_FRENCH :French -STR_NETWORK_LANG_BRAZILIAN :Brazilian -STR_NETWORK_LANG_BULGARIAN :Bulgarian -STR_NETWORK_LANG_CHINESE :Chinese -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Danish -STR_NETWORK_LANG_DUTCH :Dutch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnish -STR_NETWORK_LANG_HUNGARIAN :Hungarian -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :Italian -STR_NETWORK_LANG_JAPANESE :Japanese -STR_NETWORK_LANG_KOREAN :Korean -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :Norwegian -STR_NETWORK_LANG_POLISH :Polish -STR_NETWORK_LANG_PORTUGUESE :Portuguese -STR_NETWORK_LANG_ROMANIAN :Romanian -STR_NETWORK_LANG_RUSSIAN :Russian -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :Spanish -STR_NETWORK_LANG_SWEDISH :Swedish -STR_NETWORK_LANG_TURKISH :Turkish -STR_NETWORK_LANG_UKRAINIAN :Ukrainian -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatian -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Greek -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby @@ -2167,19 +2135,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconne STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Client list # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Client list -STR_NETWORK_COMPANY_LIST_SPECTATE :Spectate -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :New company +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Online players # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kick -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multiplayer +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Name of the server you are playing on +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edit the name of your server +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name of the server +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibility +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Player +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Your player name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Edit your player name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Your player name +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Administrative actions to perform for this client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Administrative actions to perform for this company +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Join this company +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send a message to this player +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send a message to all players of this company +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send a message to all spectators +STR_NETWORK_CLIENT_LIST_SPECTATORS :Spectators +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(New company) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company and join it +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is you +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Kick +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Ban +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Delete +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Password unlock + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Admin action +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Are you sure you want to kick player '{RAW_STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Are you sure you want to ban player '{RAW_STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Are you sure you want to delete company '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Are you sure you want to reset the password of company '{COMPANY}'? STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client @@ -2224,6 +2219,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Could no STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Your player name has not been set. The name can be set at the top of the Multiplayer window STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full @@ -2236,6 +2232,8 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your player name is not valid +STR_NETWORK_ERROR_SERVER_TOO_OLD :{WHITE}The queried server is too old for this client ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :general error @@ -2258,6 +2256,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no pas STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :invalid client name ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss @@ -2547,7 +2546,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Build sh STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Place a buoy which can be used as a waypoint. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Build aqueduct. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define water area.{}Make a canal, unless Ctrl is held down at sea level, when it will flood the surroundings instead -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers. Ctrl selects the area diagonally # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ship Depot Orientation @@ -3116,6 +3115,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: { STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{RAW_STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred: {}{STRING5} +STR_NEWGRF_ERROR_POPUP :{WHITE}A NewGRF error has occurred: {}{STRING5} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:RAW_STRING} will not work with the TTDPatch version reported by OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:RAW_STRING} is for the {RAW_STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:RAW_STRING} is designed to be used with {RAW_STRING} diff --git a/src/lang/english_AU.txt b/src/lang/english_AU.txt index beee277396..637f958998 100644 --- a/src/lang/english_AU.txt +++ b/src/lang/english_AU.txt @@ -966,6 +966,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :other + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base graphics set STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Select the base graphics set to use STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} @@ -1845,6 +1846,7 @@ STR_FACE_TIE :Tie: STR_FACE_EARRING :Earring: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: @@ -1903,10 +1905,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Advertised -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Yes STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximum number of clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled @@ -1921,46 +1919,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other pl STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Any -STR_NETWORK_LANG_ENGLISH :English -STR_NETWORK_LANG_GERMAN :German -STR_NETWORK_LANG_FRENCH :French -STR_NETWORK_LANG_BRAZILIAN :Brazilian -STR_NETWORK_LANG_BULGARIAN :Bulgarian -STR_NETWORK_LANG_CHINESE :Chinese -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Danish -STR_NETWORK_LANG_DUTCH :Dutch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnish -STR_NETWORK_LANG_HUNGARIAN :Hungarian -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :Italian -STR_NETWORK_LANG_JAPANESE :Japanese -STR_NETWORK_LANG_KOREAN :Korean -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :Norwegian -STR_NETWORK_LANG_POLISH :Polish -STR_NETWORK_LANG_PORTUGUESE :Portuguese -STR_NETWORK_LANG_ROMANIAN :Romanian -STR_NETWORK_LANG_RUSSIAN :Russian -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :Spanish -STR_NETWORK_LANG_SWEDISH :Swedish -STR_NETWORK_LANG_TURKISH :Turkish -STR_NETWORK_LANG_UKRAINIAN :Ukrainian -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatian -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Greek -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby @@ -2011,15 +1969,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Client list -STR_NETWORK_COMPANY_LIST_SPECTATE :Spectate -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :New company # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kick -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client diff --git a/src/lang/english_US.txt b/src/lang/english_US.txt index f2f40f2c03..3c1d6860aa 100644 --- a/src/lang/english_US.txt +++ b/src/lang/english_US.txt @@ -953,7 +953,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Drive on left STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Drive on right -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Town names: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Select style of town names ############ start of townname region @@ -993,6 +993,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Every 12 months STR_GAME_OPTIONS_LANGUAGE :{BLACK}Language STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Select the interface language to use +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completed) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullscreen STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Check this box to play OpenTTD fullscreen mode @@ -1006,6 +1007,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Check this box to allow OpenTTD to try to use hardware acceleration. A changed setting will only be applied upon game restart STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}The setting will only take effect after a game restart +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Check this box to v-sync the screen. A changed setting will only be applied upon game restart. Only works with hardware acceleration enabled + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interface size STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Select the interface element size to use @@ -1138,6 +1142,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Settings STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filter string: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expand all STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Collapse all +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Reset all values STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no explanation available) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Default value: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Setting type: {ORANGE}{STRING} @@ -1146,6 +1151,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Game setting (s STR_CONFIG_SETTING_TYPE_GAME_INGAME :Game setting (stored in save; affects only current game) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Company setting (stored in saves; affects only new games) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Company setting (stored in save; affects only current company) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Caution! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}This action will reset all game settings to their default values.{}Are you sure you want to proceed? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Category: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: @@ -1984,6 +1991,9 @@ STR_FACE_TIE :Tie: STR_FACE_EARRING :Earring: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Change tie or earring +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Private +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Player name: @@ -2046,10 +2056,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}The game STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set password STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Advertised -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Choose between an advertised (internet) and a not advertised (Local Area Network, LAN) game -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Yes +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibility +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximum number of clients: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choose the maximum number of clients. Not all slots need to be filled @@ -2064,46 +2072,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Other pl STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Any -STR_NETWORK_LANG_ENGLISH :English -STR_NETWORK_LANG_GERMAN :German -STR_NETWORK_LANG_FRENCH :French -STR_NETWORK_LANG_BRAZILIAN :Brazilian -STR_NETWORK_LANG_BULGARIAN :Bulgarian -STR_NETWORK_LANG_CHINESE :Chinese -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Danish -STR_NETWORK_LANG_DUTCH :Dutch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnish -STR_NETWORK_LANG_HUNGARIAN :Hungarian -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :Italian -STR_NETWORK_LANG_JAPANESE :Japanese -STR_NETWORK_LANG_KOREAN :Korean -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :Norwegian -STR_NETWORK_LANG_POLISH :Polish -STR_NETWORK_LANG_PORTUGUESE :Portuguese -STR_NETWORK_LANG_ROMANIAN :Romanian -STR_NETWORK_LANG_RUSSIAN :Russian -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :Spanish -STR_NETWORK_LANG_SWEDISH :Swedish -STR_NETWORK_LANG_TURKISH :Turkish -STR_NETWORK_LANG_UKRAINIAN :Ukrainian -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatian -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Greek -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer game lobby @@ -2151,19 +2119,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconne STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server is protected. Enter password STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Company is protected. Enter password -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Client list # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Client list -STR_NETWORK_COMPANY_LIST_SPECTATE :Spectate -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :New company +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Online players # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kick -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Speak to all -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Speak to company -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private message +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multiplayer +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Name of the server you are playing on +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Edit the name of your server +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name of the server +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibility +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Whether other people can see your server in the public listing +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Player +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Your player name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Edit your player name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Your player name +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Administrative actions to perform for this client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Administrative actions to perform for this company +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Join this company +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send a message to this player +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send a message to all players of this company +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send a message to all spectators +STR_NETWORK_CLIENT_LIST_SPECTATORS :Spectators +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(New company) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Create a new company and join it +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}This is you +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}This is the host of the game + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Kick +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Ban +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Delete +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Password unlock + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Admin action +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Are you sure you want to kick player '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Are you sure you want to ban player '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Are you sure you want to delete company '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Are you sure you want to reset the password of company '{COMPANY}'? STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client @@ -2208,6 +2203,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Could no STR_NETWORK_ERROR_CLIENT_START :{WHITE}Could not connect STR_NETWORK_ERROR_TIMEOUT :{WHITE}Connection #{NUM} timed out STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}A protocol error was detected and the connection was closed +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Your player name has not been set. The name can be set at the top of the Multiplayer window STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}The revision of this client does not match the server's revision STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong password STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full @@ -2220,6 +2216,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Your computer is too slow to keep up with the server STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Your computer took too long to download the map STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Your computer took too long to join the server +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Your player name is not valid ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :general error @@ -2242,6 +2239,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :received no pas STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :general timeout STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :downloading map took too long STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :processing map took too long +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :invalid client name ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible connection loss @@ -2531,7 +2529,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Build sh STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Place a buoy which can be used as a waypoint. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Build aqueduct. Shift toggles building/showing cost estimate STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Define water area.{}Make a canal. If Ctrl is held down at sea level, it will flood the surroundings instead -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Place rivers. Ctrl selects the area diagonally # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ship Depot Orientation @@ -3081,6 +3079,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warning: { STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}A fatal NewGRF error has occurred:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}A NewGRF error has occurred:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} will not work with the TTDPatch version reported by OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} is for the {STRING} version of TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} is designed to be used with {STRING} diff --git a/src/lang/esperanto.txt b/src/lang/esperanto.txt index 98d9452e54..9b25ed0e6c 100644 --- a/src/lang/esperanto.txt +++ b/src/lang/esperanto.txt @@ -953,6 +953,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Elektu u STR_GAME_OPTIONS_RESOLUTION_OTHER :alia + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interfacgrandeco STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normala @@ -1529,6 +1530,7 @@ STR_FACE_TIE :Kravato: STR_FACE_EARRING :Orelringo: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Ŝanĝi kravaton aŭ orelringon. + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Pluraj ludantoj STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ludantnomo: @@ -1601,46 +1603,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aliaj lu STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Tajpu nomon por la retludo -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Ajna -STR_NETWORK_LANG_ENGLISH :Angla -STR_NETWORK_LANG_GERMAN :Germana -STR_NETWORK_LANG_FRENCH :Franca -STR_NETWORK_LANG_BRAZILIAN :Brazila -STR_NETWORK_LANG_BULGARIAN :Bulgara -STR_NETWORK_LANG_CHINESE :Ĉina -STR_NETWORK_LANG_CZECH :Ĉeĥa -STR_NETWORK_LANG_DANISH :Dana -STR_NETWORK_LANG_DUTCH :Nederlanda -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finna -STR_NETWORK_LANG_HUNGARIAN :Hungara -STR_NETWORK_LANG_ICELANDIC :Islanda -STR_NETWORK_LANG_ITALIAN :Itala -STR_NETWORK_LANG_JAPANESE :Japana -STR_NETWORK_LANG_KOREAN :Korea -STR_NETWORK_LANG_LITHUANIAN :Litova -STR_NETWORK_LANG_NORWEGIAN :Norveĝa -STR_NETWORK_LANG_POLISH :Pola -STR_NETWORK_LANG_PORTUGUESE :Portugala -STR_NETWORK_LANG_ROMANIAN :Romana -STR_NETWORK_LANG_RUSSIAN :Rusa -STR_NETWORK_LANG_SLOVAK :Slovaka -STR_NETWORK_LANG_SLOVENIAN :Slovena -STR_NETWORK_LANG_SPANISH :Hispana -STR_NETWORK_LANG_SWEDISH :Sveda -STR_NETWORK_LANG_TURKISH :Turka -STR_NETWORK_LANG_UKRAINIAN :Ukraina -STR_NETWORK_LANG_AFRIKAANS :Afrikansa -STR_NETWORK_LANG_CROATIAN :Kroata -STR_NETWORK_LANG_CATALAN :Kataluna -STR_NETWORK_LANG_ESTONIAN :Estona -STR_NETWORK_LANG_GALICIAN :Galica -STR_NETWORK_LANG_GREEK :Greka -STR_NETWORK_LANG_LATVIAN :Latva -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Atendejo por plurludantaj ludoj @@ -1691,15 +1653,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Kompanio # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klientlisto -STR_NETWORK_COMPANY_LIST_SPECTATE :Spekti -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova kompanio # Network client list -STR_NETWORK_CLIENTLIST_KICK :Forbatu -STR_NETWORK_CLIENTLIST_BAN :Bari -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Parolu al ĉiuj -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Parolu al kompanio -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privata mesaĝo + + STR_NETWORK_SERVER :Servilo STR_NETWORK_CLIENT :Kliento diff --git a/src/lang/estonian.txt b/src/lang/estonian.txt index f6eb2910bd..99c01168a8 100644 --- a/src/lang/estonian.txt +++ b/src/lang/estonian.txt @@ -1063,6 +1063,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Riistvar STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Märkides selle ruudu, lubad OpenTTD-l üritada kasutada riistvarakiirendust. Muudetud seade omab mõju pärast mängu taaskäivitust STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Seade omab mõju alles pärast mängu taaskäivitust + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Liidese suurus STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vali kasutatav liideseelementide suurus @@ -2041,6 +2042,7 @@ STR_FACE_TIE :Lips: STR_FACE_EARRING :Kõrvarõngas: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Vaheta kraed või kõrvarõngast + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mitmikmäng STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Mängija nimi: @@ -2103,10 +2105,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Serveril STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Määra salasõna STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Et server ei oleks avalik, kaitse oma mäng salasõnaga -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Reklaami -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Valib reklaamitava (internet) või mittereklaamitava (kohtvõrk, LAN) mängu -STR_NETWORK_START_SERVER_UNADVERTISED :Ei -STR_NETWORK_START_SERVER_ADVERTISED :Jah STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" i} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Kliente kuni: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS.in :sees @@ -2122,46 +2120,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Teavitab STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Sisesta mitmikmängu nimi -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Suvaline -STR_NETWORK_LANG_ENGLISH :Inglise keel -STR_NETWORK_LANG_GERMAN :Saksa keel -STR_NETWORK_LANG_FRENCH :Prantsuse keel -STR_NETWORK_LANG_BRAZILIAN :Brasiilia -STR_NETWORK_LANG_BULGARIAN :Bulgaaria -STR_NETWORK_LANG_CHINESE :Hiina -STR_NETWORK_LANG_CZECH :Tšehhi -STR_NETWORK_LANG_DANISH :Taani -STR_NETWORK_LANG_DUTCH :Hollandi -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Soome -STR_NETWORK_LANG_HUNGARIAN :Ungari -STR_NETWORK_LANG_ICELANDIC :Islandi -STR_NETWORK_LANG_ITALIAN :Itaalia -STR_NETWORK_LANG_JAPANESE :Jaapani -STR_NETWORK_LANG_KOREAN :Korea -STR_NETWORK_LANG_LITHUANIAN :Leedu -STR_NETWORK_LANG_NORWEGIAN :Norra -STR_NETWORK_LANG_POLISH :Poola -STR_NETWORK_LANG_PORTUGUESE :Portugali -STR_NETWORK_LANG_ROMANIAN :Rumeenia -STR_NETWORK_LANG_RUSSIAN :Vene -STR_NETWORK_LANG_SLOVAK :Slovakkia -STR_NETWORK_LANG_SLOVENIAN :Sloveenia -STR_NETWORK_LANG_SPANISH :Hispaania -STR_NETWORK_LANG_SWEDISH :Rootsi -STR_NETWORK_LANG_TURKISH :Türgi -STR_NETWORK_LANG_UKRAINIAN :Ukraina -STR_NETWORK_LANG_AFRIKAANS :Afrikaani -STR_NETWORK_LANG_CROATIAN :Horvaadi -STR_NETWORK_LANG_CATALAN :Katalaani -STR_NETWORK_LANG_ESTONIAN :Eesti -STR_NETWORK_LANG_GALICIAN :Galeegi -STR_NETWORK_LANG_GREEK :Kreeka -STR_NETWORK_LANG_LATVIAN :Läti -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Mitmikmängu jututuba @@ -2209,19 +2167,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Katkesta STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server on kaitstud. Sisesta salasõna STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Ettevõte on kaitstud. Sisesta salasõna -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Klientide nimekiri # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klientide nimekiri -STR_NETWORK_COMPANY_LIST_SPECTATE :Jälgi -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Uus ettevõte # Network client list -STR_NETWORK_CLIENTLIST_KICK :Viska välja -STR_NETWORK_CLIENTLIST_BAN :Bänn -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Räägi kõigiga -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Räägi ettevõttega -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privaatne sõnum + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klient @@ -2589,7 +2541,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Ehita la STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Paigalda poi, mis on kasutatav teemärgisena. Shift valib ehitamise/hinna kuvamise režiimi STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Ehita veesild. Shift valib ehitamise/hinna kuvamise režiimi STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Määratle veealad.{}Ehita kanal. Veekõrgusel Ctrl-klahvi all hoidmine ujutab ümbruskonna üle -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Jõgede paigutamine +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Jõgede paigutamine. Ctrl valib ala põiki # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Laevaremonditehase suund diff --git a/src/lang/faroese.txt b/src/lang/faroese.txt index 6652c19ce4..b9acc13a76 100644 --- a/src/lang/faroese.txt +++ b/src/lang/faroese.txt @@ -947,6 +947,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :annað + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Base grafikk sett STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Vel ta base grafikk setti tú vil brúka STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} vantandi/oyðiløgd fíl{P a ir} @@ -1695,6 +1696,7 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Oyraringur: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Broyt slips ella oyraring + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Hópspæl STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spælara navn: @@ -1753,8 +1755,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Aðrir s STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Áset loyniorð STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Verj títt spæl við einum loyniorðið um tú ikki vil at ta skal verða opi fyri almenninginum -STR_NETWORK_START_SERVER_UNADVERTISED :Nei -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" ar} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Mest loyvdir klientar: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Vel mest loyvda tali av klientum. Ta er ikki neyðugt at fylla øll plássini @@ -1769,46 +1769,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aðrir s STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Gev netverks spælinum eitt navn -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Hvat sum helst -STR_NETWORK_LANG_ENGLISH :Enskt -STR_NETWORK_LANG_GERMAN :Týskt -STR_NETWORK_LANG_FRENCH :Franskt -STR_NETWORK_LANG_BRAZILIAN :Brasilienskt -STR_NETWORK_LANG_BULGARIAN :Bulgariskt -STR_NETWORK_LANG_CHINESE :Kinverskt -STR_NETWORK_LANG_CZECH :Tjekkiskt -STR_NETWORK_LANG_DANISH :Danskt -STR_NETWORK_LANG_DUTCH :Niðurlendskt -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finskt -STR_NETWORK_LANG_HUNGARIAN :Ungarskt -STR_NETWORK_LANG_ICELANDIC :Íslenskt -STR_NETWORK_LANG_ITALIAN :Italienskt -STR_NETWORK_LANG_JAPANESE :Japanskt -STR_NETWORK_LANG_KOREAN :Koreanskt -STR_NETWORK_LANG_LITHUANIAN :Litauiskt -STR_NETWORK_LANG_NORWEGIAN :Norskt -STR_NETWORK_LANG_POLISH :Polskt -STR_NETWORK_LANG_PORTUGUESE :Portugisiskt -STR_NETWORK_LANG_ROMANIAN :Rumenskt -STR_NETWORK_LANG_RUSSIAN :Russiskt -STR_NETWORK_LANG_SLOVAK :Slovakiskt -STR_NETWORK_LANG_SLOVENIAN :Slovenskt -STR_NETWORK_LANG_SPANISH :Spanskt -STR_NETWORK_LANG_SWEDISH :Svenskt -STR_NETWORK_LANG_TURKISH :Turkiskt -STR_NETWORK_LANG_UKRAINIAN :Ukrainskt -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatiskt -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estoniskt -STR_NETWORK_LANG_GALICIAN :Galisiskt -STR_NETWORK_LANG_GREEK :Grikskt -STR_NETWORK_LANG_LATVIAN :Latviskt -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Hópspæls forhøll @@ -1859,15 +1819,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Fyritøk # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Listi yvir klientar -STR_NETWORK_COMPANY_LIST_SPECTATE :Eygleið -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nýggja fyritøku # Network client list -STR_NETWORK_CLIENTLIST_KICK :Sparka -STR_NETWORK_CLIENTLIST_BAN :Bannað -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Tosa við øll -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Tosa við fyritøku -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Persónligt boð + + STR_NETWORK_SERVER :Servari STR_NETWORK_CLIENT :Klient diff --git a/src/lang/finnish.txt b/src/lang/finnish.txt index 3ce434cc26..3db7184a32 100644 --- a/src/lang/finnish.txt +++ b/src/lang/finnish.txt @@ -953,7 +953,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malesian ringgi STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Vasemmanpuolinen liikenne STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Oikeanpuolinen liikenne -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Kuntien nimet +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Kuntien nimet: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Valitse kuntien nimien tyyli ############ start of townname region @@ -993,6 +993,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Kerran vuodessa STR_GAME_OPTIONS_LANGUAGE :{BLACK}Kieli STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Valitse käyttöliittymän kieli +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% valmiina) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Koko näyttö STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Valitse tämä pelataksesi kokoruututilassa @@ -1006,6 +1007,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Laitteis STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Valitse tämä, jos haluat, että OpenTTD yrittää käyttää laitteistokiihdytystä. Muutettu asetus tulee voimaan vasta pelin uudelleenkäynnistyksen jälkeen. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Asetus tulee voimaan vasta pelin uudelleenkäynnistyksen jälkeen +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Pystytahdistus +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Valitse tämä ottaaksesi käyttöön näytön pystytahdistuksen. Muutettu asetus tulee voimaan vasta pelin uudelleenkäynnistyksen jälkeen. Edellyttää, että laitteistokiihdytys on käytössä. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Käyttöliittymän koko STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Valitse käyttöliittymäelementtien koko @@ -1138,6 +1142,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Asetukse STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Suodatinteksti: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Avaa kaikki STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Sulje kaikki +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Palauta oletukset STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(selitystä ei saatavilla) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Oletusarvo: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Asetuksen tyyppi: {ORANGE}{STRING} @@ -1146,6 +1151,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Pelin asetus (t STR_CONFIG_SETTING_TYPE_GAME_INGAME :Pelin asetus (tallennetaan tallenteeseen; vaikuttaa vain nykyiseen peliin) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Yhtiön asetus (tallennetaan tallenteisiin; vaikuttaa vain uusiin peleihin) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Yhtiön asetus (tallennetaan tallennukseen; vaikuttaa vain nykyiseen yhtiöön) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Varoitus! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Tämä toiminto palauttaa pelin kaikki asetukset oletusarvoihinsa.{}Haluatko varmasti jatkaa? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tyyppi: @@ -1984,6 +1991,9 @@ STR_FACE_TIE :Solmio: STR_FACE_EARRING :Korvakoru: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Vaihda solmio tai korvakoru +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Yksityinen +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Julkinen + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Moninpeli STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Pelaajan nimi @@ -2046,10 +2056,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Nimi nä STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Aseta salasana STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Jos peliin ei halua ulkopuolisia, voi sen suojata salasanalla -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Mainostettu -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Valitse mainostettu (internet) tai ei-mainostettu (paikallisverkko, LAN) peli -STR_NETWORK_START_SERVER_UNADVERTISED :Ei -STR_NETWORK_START_SERVER_ADVERTISED :Kyllä +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Näkyvyys +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Näkyykö palvelimesi muille julkisessa listauksessa STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} asiakas{P "" ta} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Pelaajien enimmäismäärä: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Pelaajien enimmäismäärä. Pelissä voi olla myös vähemmän pelaajia @@ -2064,46 +2072,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Toiset p STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Syötä nimi verkkopelille -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :mikä tahansa -STR_NETWORK_LANG_ENGLISH :englanti -STR_NETWORK_LANG_GERMAN :saksa -STR_NETWORK_LANG_FRENCH :ranska -STR_NETWORK_LANG_BRAZILIAN :brasilianportugali -STR_NETWORK_LANG_BULGARIAN :bulgaria -STR_NETWORK_LANG_CHINESE :kiina -STR_NETWORK_LANG_CZECH :tšekki -STR_NETWORK_LANG_DANISH :tanska -STR_NETWORK_LANG_DUTCH :hollanti -STR_NETWORK_LANG_ESPERANTO :esperanto -STR_NETWORK_LANG_FINNISH :suomi -STR_NETWORK_LANG_HUNGARIAN :unkari -STR_NETWORK_LANG_ICELANDIC :islanti -STR_NETWORK_LANG_ITALIAN :italia -STR_NETWORK_LANG_JAPANESE :japani -STR_NETWORK_LANG_KOREAN :korea -STR_NETWORK_LANG_LITHUANIAN :liettua -STR_NETWORK_LANG_NORWEGIAN :norja -STR_NETWORK_LANG_POLISH :puola -STR_NETWORK_LANG_PORTUGUESE :portugali -STR_NETWORK_LANG_ROMANIAN :romania -STR_NETWORK_LANG_RUSSIAN :venäjä -STR_NETWORK_LANG_SLOVAK :slovakia -STR_NETWORK_LANG_SLOVENIAN :sloveeni -STR_NETWORK_LANG_SPANISH :espanja -STR_NETWORK_LANG_SWEDISH :ruotsi -STR_NETWORK_LANG_TURKISH :turkki -STR_NETWORK_LANG_UKRAINIAN :ukraina -STR_NETWORK_LANG_AFRIKAANS :afrikaans -STR_NETWORK_LANG_CROATIAN :kroatia -STR_NETWORK_LANG_CATALAN :katalaani -STR_NETWORK_LANG_ESTONIAN :viro -STR_NETWORK_LANG_GALICIAN :galego -STR_NETWORK_LANG_GREEK :kreikka -STR_NETWORK_LANG_LATVIAN :latvia -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Moninpeliaula @@ -2151,19 +2119,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Pura yht STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Palvelin on suojattu. Anna salasana STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Yhtiö on suojattu. Anna salasana -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Asiakaslista # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Asiakaslista -STR_NETWORK_COMPANY_LIST_SPECTATE :Katsele -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Uusi yhtiö +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Kytkeytyneet pelaajat # Network client list -STR_NETWORK_CLIENTLIST_KICK :Potkaise -STR_NETWORK_CLIENTLIST_BAN :Kiellä -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Puhu kaikille -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Puhu yhtiölle -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Yksityinen viesti +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Moninpeli +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Palvelin +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nimi +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Sen palvelimen nimi, jolla pelaat +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Muokkaa palvelimesi nimeä +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Palvelimen nimi +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Näkyvyys +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Näkyykö palvelimesi muille julkisessa listauksessa +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Pelaaja +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nimi +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Pelaajanimesi +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Muokkaa pelaajanimeäsi +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Pelaajanimesi +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Tähän asiakkaaseen kohdistettavat ylläpitotoiminnot +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Tähän yhtiöön kohdistettavat ylläpitotoiminnot +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Liity tähän yhtiöön +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Lähetä tälle pelaajalle viesti +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Lähetä viesti kaikille tämän yhtiön pelaajille +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Lähetä viesti kaikille katsojille +STR_NETWORK_CLIENT_LIST_SPECTATORS :Katsojat +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Uusi yhtiö) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Perusta uusi yhtiö ja liity siihen +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Tämä olet sinä +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Tämä on pelin ylläpitäjä + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Potki +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Estä +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Poista +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Poista salasanalukitus + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Ylläpitäjän toiminta +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Haluatko varmasti potkia pelaajan ”{STRING}” pelistä? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Haluatko varmasti estää pelaajan ”{STRING}”? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Haluatko varmasti poistaa yhtiön ”{COMPANY}”? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Haluatko varmasti nollata yhtiön ”{COMPANY}” salasanan? STR_NETWORK_SERVER :Palvelin STR_NETWORK_CLIENT :Pelaaja @@ -2208,6 +2203,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Palvelin STR_NETWORK_ERROR_CLIENT_START :{WHITE}Yhdistäminen ei onnistunut STR_NETWORK_ERROR_TIMEOUT :{WHITE}Yhteys nro {NUM} aikakatkaistiin STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Protokollavirhe tapahtui ja yhteys suljettiin +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Et ole asettanut pelaajanimeäsi. Nimen voi asettaa moninpeli-ikkunan ylälaidassa. STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Tämän asiakkaan versio ei vastaa palvelimen versiota STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Väärä salasana STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Palvelin on täynnä @@ -2220,6 +2216,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Käytit STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Tietokoneesi on liian hidas pysyäkseen palvelimen tahdissa STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Kartan lataus kesti liian kauan STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Palvelimelle liittyminen kesti liian kauan +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Pelaajanimesi ei kelpaa ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :yleinen virhe @@ -2242,6 +2239,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :salasanaa ei va STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :yleinen aikakatkaisu STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :kartan lataaminen kesti liian kauan STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :kartan käsittely kesti liian kauan +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :Epäkelpo asiakasnimi ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Mahdollinen yhteyden menetys @@ -2531,7 +2529,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Rakenna STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Sijoita poiju, jota voi käyttää reittipisteenä. Shift vaihtaa rakennustilan ja kustannusarvion välillä STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Rakenna akvedukti. Shift vaihtaa rakennustilan ja kustannusarvion välillä STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Määrittele vesialue.{}Tee kanava, paitsi jos Ctrl on painettuna merenpinnalla. Tällöin meri laajenee ympäristöön -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Sijoita jokia +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Sijoita jokia. Ctrl valitsee alueen vinottain. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Telakan suunta @@ -3081,6 +3079,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Varoitus: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Virhe: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Virhe: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Vakava NewGRF-virhe on tapahtunut:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF-virhe on tapahtunut:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} ei toimi OpenTTD:n ilmoittaman TTDPatch-version kanssa STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} on TTD:n {STRING}-versiota varten STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ja {STRING} on suunniteltu toimimaan yhdessä @@ -4464,7 +4463,7 @@ STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Ei voi r STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Satamaa ei voi rakentaa tähän... STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Lentokenttää ei voi rakentaa... -STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Liitä yhteen useampi asema/lastausalue. +STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Vieressä on useampi kuin yksi olemassaoleva asema tai kuormausalue. STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... asema liian levittäytynyt STR_ERROR_TOO_MANY_STATIONS_LOADING :{WHITE}Liian monta asemaa ja lastausaluetta. STR_ERROR_TOO_MANY_STATION_SPECS :{WHITE}Rautatieasema on jakautunut liian moneen osaan @@ -4497,7 +4496,7 @@ STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Satama p STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST :{WHITE}Lentokenttä pitää tuhota ensin. # Waypoint related errors -STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Liittää useamman kuin yhden reittipisteen +STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Vieressä on useampi kuin yksi olemassaoleva reittipiste. STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Liian lähellä toista reittipistettä STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Junien reittipistettä ei voi rakentaa tähän... diff --git a/src/lang/french.txt b/src/lang/french.txt index 50e1b9b901..dfd01cf07a 100644 --- a/src/lang/french.txt +++ b/src/lang/french.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysian Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conduite à gauche STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conduite à droite -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Noms des villes +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nom des villes{NBSP}: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Sélectionner la nationalité des noms des villes ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Tous les 12 moi STR_GAME_OPTIONS_LANGUAGE :{BLACK}Langue STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Sélectionner la langue à utiliser pour l'interface +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}{NBSP}% terminé{P "" s}) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Plein écran STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Cocher cette case pour jouer à OpenTTD en plein écran @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK} Accél STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Cochez cette case permet à OpenTTD d'utiliser l'accélération matérielle, si possible. Un paramètre modifié ne sera pris en compte qu'au redémarrage du jeu STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Les paramètres ne prendront effet qu'après le redémarrage du jeu +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Cochez cette case pour activer la synchronisation verticale de l'écran. La modification de ce paramètres ne sera effective qu'après le redémarrage du jeu. Fonctionne uniquement si l’accélération matérielle est active + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Taille d'interface STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Choisir la taille d'élément d'interface à utiliser @@ -1023,7 +1027,7 @@ STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Taille double STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :Taille quadruple -STR_GAME_OPTIONS_GRAPHICS :Graphiques {BLACK} +STR_GAME_OPTIONS_GRAPHICS :{BLACK} Graphiques STR_GAME_OPTIONS_REFRESH_RATE :{BLACK} Taux de rafraîchissement de l'affichage STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :{BLACK} Sélectionnez la fréquence de rafraîchissement à utiliser @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Paramèt STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtre{NBSP}: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Tout développer STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Tout réduire +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Réinitialiser tous les réglages STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(pas d'explication disponible) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valeur par défaut{NBSP}: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Type de paramètre{NBSP}: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Paramètre de j STR_CONFIG_SETTING_TYPE_GAME_INGAME :Paramètre de jeu (enregistré dans la sauvegarde{NBSP}; affecte uniquement la partie actuelle) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Paramètre de compagnie (enregistré dans les sauvegardes{NBSP}; affecte uniquement les nouvelles parties) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Paramètre de compagnie (enregistré dans la sauvegarde{NBSP}; affecte uniquement la compagnie actuelle) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Attention{NBSP}! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Par cette action, toues les réglages seront réinitialisés aux valeurs par défaut.{}Êtes-vous sûr de vouloir continuer{NBSP}? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Catégorie{NBSP}: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type{NBSP}: @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Cravate{NBSP}: STR_FACE_EARRING :Boucle d'oreille{NBSP}: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Modifier la cravate ou la boucle d'oreille +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privé +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Public + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijoueurs STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nom du joueur{NBSP}: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Les autr STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Choisir le mot de passe STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protégez votre partie avec un mot de passe si vous ne souhaitez pas que d'autres l'utilisent -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Publiée -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Choisir entre une partie publiée (internet) et une partie non publiée (Réseau local, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Non -STR_NETWORK_START_SERVER_ADVERTISED :Oui +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilité +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Possibilité pour les autres personnes de vous voir dans la liste publique STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Nombre de clients maximum{NBSP}: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Choisir un nombre maximum de clients. Tous les emplacements n'auront pas besoin d'être remplis @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Les autr STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Entrer un nom pour la partie en réseau -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Aucune -STR_NETWORK_LANG_ENGLISH :Anglais -STR_NETWORK_LANG_GERMAN :Allemand -STR_NETWORK_LANG_FRENCH :Français -STR_NETWORK_LANG_BRAZILIAN :Brésilien -STR_NETWORK_LANG_BULGARIAN :Bulgare -STR_NETWORK_LANG_CHINESE :Chinois -STR_NETWORK_LANG_CZECH :Tchèque -STR_NETWORK_LANG_DANISH :Danois -STR_NETWORK_LANG_DUTCH :Néerlandais -STR_NETWORK_LANG_ESPERANTO :Espéranto -STR_NETWORK_LANG_FINNISH :Finlandais -STR_NETWORK_LANG_HUNGARIAN :Hongrois -STR_NETWORK_LANG_ICELANDIC :Islandais -STR_NETWORK_LANG_ITALIAN :Italien -STR_NETWORK_LANG_JAPANESE :Japonais -STR_NETWORK_LANG_KOREAN :Coréen -STR_NETWORK_LANG_LITHUANIAN :Lituanien -STR_NETWORK_LANG_NORWEGIAN :Norvégien -STR_NETWORK_LANG_POLISH :Polonais -STR_NETWORK_LANG_PORTUGUESE :Portugais -STR_NETWORK_LANG_ROMANIAN :Roumain -STR_NETWORK_LANG_RUSSIAN :Russe -STR_NETWORK_LANG_SLOVAK :Slovaque -STR_NETWORK_LANG_SLOVENIAN :Slovène -STR_NETWORK_LANG_SPANISH :Espagnol -STR_NETWORK_LANG_SWEDISH :Suédois -STR_NETWORK_LANG_TURKISH :Turc -STR_NETWORK_LANG_UKRAINIAN :Ukrainien -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croate -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonien -STR_NETWORK_LANG_GALICIAN :Galicien -STR_NETWORK_LANG_GREEK :Grec -STR_NETWORK_LANG_LATVIAN :Letton -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Préparation de la partie @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Déconne STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Le serveur est protégé. Entrez le mot de passe STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}La compagnie est protégée. Entrez le mot de passe -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Liste des clients # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste des clients -STR_NETWORK_COMPANY_LIST_SPECTATE :Spectateur -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nouvelle compagnie +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Joueurs en ligne # Network client list -STR_NETWORK_CLIENTLIST_KICK :Exclure -STR_NETWORK_CLIENTLIST_BAN :Bannir -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Parler à tous -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Parler à la compagnie -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Message privé +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijoueur +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Serveur +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nom du serveur sur lequel vous jouez +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Éditer le nom de votre serveur +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nom du serveur +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilité +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Possibilité pour les autres personnes de voir votre serveur dans la liste publique +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Joueur +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Votre nom de jeu +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Éditer votre nom +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Votre nom de jeu +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Actions administratives à accomplir pour ce client +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Actions administratives à accomplir pour cette compagnie +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Rejoindre cette compagnie +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Envoyer un message à cette personne +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Envoyer un message à tous les joueurs de cette compagnie +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Envoyer un message à tous les spectateurs +STR_NETWORK_CLIENT_LIST_SPECTATORS :Spectateurs +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nouvelle compagnie) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Créer une nouvelle compagnie et la rejoindre +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}C'est vous +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}C'est l'hôte du jeu + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Exclure +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bannir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Supprimer +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Débloquer le mot de passe + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Action administrative +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Êtes-vous sûr de vouloir exclure '{STRING}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Êtes-vous sûr de vouloir bannir '{STRING}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Êtes-vous sûr de vouloir supprimer la compagnie '{COMPANY}'{NBSP}? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Êtes-vous sûr de vouloir réinitialiser le mot de passe de la compagnie '{COMPANY}'? STR_NETWORK_SERVER :Serveur STR_NETWORK_CLIENT :Client @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Le serve STR_NETWORK_ERROR_CLIENT_START :{WHITE}Échec de la connexion STR_NETWORK_ERROR_TIMEOUT :{WHITE}La connexion n°{NBSP}{NUM} a dépassé le temps d'attente STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Une erreur de protocole a été détectée et la connexion a été fermée +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Vous n'avez pas de nom. Il doit être entré en haut de la fenêtre Multijoueur STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Le numéro de version/révision de ce client ne correspond pas à celui du serveur STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Mot de passe incorrect STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Le serveur est complet @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Vous ave STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Votre ordinateur est trop lent pour suivre le serveur STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Votre ordinateur a mis trop de temps pour télécharger la carte STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Votre ordinateur a mis trop de temps pour rejoindre le serveur +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Votre nom n'est pas valide ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erreur générale @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :aucun mot de pa STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :délai dépassé STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :télécharger la carte a pris trop de temps STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :le traitement de la carte a pris trop de temps +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nom client invalide ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possible perte de connexion @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construi STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Placer une bouée pouvant servir de guide aux navires.{}Shift pour afficher seulement le coût estimé. STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Construire un aqueduc.{}Shift pour afficher seulement le coût estimé. STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Définir une zone d'eau.{}Construire un canal, sauf si Ctrl est enfoncé au niveau de la mer{NBSP}: dans ce cas, le voisinage sera inondé. -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Placer des rivières +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Placer des rivières. Presser Ctrl pour sélectionner en diagonale # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orientation du dépôt @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Attention{ STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erreur{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Erreur fatale{NBSP}: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Une erreur NewGRF fatale est survenue{NBSP}:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Une erreur NewGRF est survenue{NBSP}:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} ne fonctionnera pas avec la version de TTDPatch rapportée par OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} est conçu pour la version {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} est conçu pour être utilisé avec {STRING} @@ -3437,7 +3436,7 @@ STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}Déména STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}Reconstruire ailleurs le siège de la compagnie pour le prix de 1{NBSP}% de sa valeur.{}Shift-clic pour afficher seulement le coût estimé. STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}Détails STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}Afficher le détail des calculs d'infrastructure -STR_COMPANY_VIEW_GIVE_MONEY_BUTTON :Donner de l’argent +STR_COMPANY_VIEW_GIVE_MONEY_BUTTON :{BLACK}Donner de l’argent STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP :{BLACK}Donner de l’argent à cette compagnie STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}Nouveau visage diff --git a/src/lang/unfinished/frisian.txt b/src/lang/frisian.txt similarity index 98% rename from src/lang/unfinished/frisian.txt rename to src/lang/frisian.txt index dbbb6905ee..6bceed5a1a 100644 --- a/src/lang/unfinished/frisian.txt +++ b/src/lang/frisian.txt @@ -969,6 +969,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Selektea STR_GAME_OPTIONS_RESOLUTION_OTHER :oars + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interfacegrutte STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normaal @@ -1794,6 +1795,7 @@ STR_FACE_TIE :Strik: STR_FACE_EARRING :Earbel: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Feroarje strik of earbel + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Namme fan spieler: @@ -1840,10 +1842,6 @@ STR_NETWORK_START_SERVER_CAPTION :{WHITE}Start in STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}Spulnamme: STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Wachtwurd ynstelle -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Advertearre -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Kies tusken in advertearre (ynternet) of in net-advertearre (LAN) spul -STR_NETWORK_START_SERVER_UNADVERTISED :Nee -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} kliïnt{P "" en} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimaal oantal kliïnten: STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} bedriuw{P "" en} @@ -1854,46 +1852,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Sprutsen STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Fier in namme yn foar it networkspul -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Alle -STR_NETWORK_LANG_ENGLISH :Ingelsk -STR_NETWORK_LANG_GERMAN :Dútsk -STR_NETWORK_LANG_FRENCH :Frânsk -STR_NETWORK_LANG_BRAZILIAN :Braziliaansk -STR_NETWORK_LANG_BULGARIAN :Bulgaarsk -STR_NETWORK_LANG_CHINESE :Sinees -STR_NETWORK_LANG_CZECH :Tsjechysk -STR_NETWORK_LANG_DANISH :Deensk -STR_NETWORK_LANG_DUTCH :Nederlânsk -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finsk -STR_NETWORK_LANG_HUNGARIAN :Hongaarsk -STR_NETWORK_LANG_ICELANDIC :Yslânsk -STR_NETWORK_LANG_ITALIAN :Italjaansk -STR_NETWORK_LANG_JAPANESE :Japansk -STR_NETWORK_LANG_KOREAN :Koreaansk -STR_NETWORK_LANG_LITHUANIAN :Litousk -STR_NETWORK_LANG_NORWEGIAN :Noarsk -STR_NETWORK_LANG_POLISH :Poalsk -STR_NETWORK_LANG_PORTUGUESE :Portegeesk -STR_NETWORK_LANG_ROMANIAN :Roemeensk -STR_NETWORK_LANG_RUSSIAN :Russysk -STR_NETWORK_LANG_SLOVAK :Slowaaksk -STR_NETWORK_LANG_SLOVENIAN :Sloveensk -STR_NETWORK_LANG_SPANISH :Spaansk -STR_NETWORK_LANG_SWEDISH :Sweedsk -STR_NETWORK_LANG_TURKISH :Turksk -STR_NETWORK_LANG_UKRAINIAN :Oekraynsk -STR_NETWORK_LANG_AFRIKAANS :Afrikaansk -STR_NETWORK_LANG_CROATIAN :Kroätysk -STR_NETWORK_LANG_CATALAN :Katalaansk -STR_NETWORK_LANG_ESTONIAN :Estlânsk -STR_NETWORK_LANG_GALICIAN :Galisysk -STR_NETWORK_LANG_GREEK :Gryksk -STR_NETWORK_LANG_LATVIAN :Letsk -############ End of leave-in-this-order - # Network game lobby @@ -1937,14 +1895,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Bedriuw # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}Client lyst -STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}Taskôgje -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}Nei Bedriuw # Network client list -STR_NETWORK_CLIENTLIST_KICK :Skoppe -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Tsjin elkenien prate -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Praat mei bedriuw -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Priveeberjocht + + STR_NETWORK_SERVER :Tsjinner STR_NETWORK_CLIENT :Kliïnt diff --git a/src/lang/gaelic.txt b/src/lang/gaelic.txt index 1556cc5faa..98513e081d 100644 --- a/src/lang/gaelic.txt +++ b/src/lang/gaelic.txt @@ -1174,6 +1174,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Tagh dù STR_GAME_OPTIONS_RESOLUTION_OTHER :Gnàthaichte + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Meud na h-eadar-aghaidh STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Tagh am meud airson rud san eadar-aghaidh @@ -2080,6 +2081,7 @@ STR_FACE_TIE :Tàidh: STR_FACE_EARRING :Fàinne-chluaise: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Atharraich an tàidh no an fhàinne-chluaise + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Ioma-chluicheadair STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ainm cluicheadair: @@ -2138,10 +2140,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Thèid a STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Suidhich facal-faire STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Dìon an geama agad le facal-faire ach nach eil e ri fhaighinn gu poblach -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Sanasaichte -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Dèan taghadh eadar geama sanasaichte (eadar-lìon) no gun sanasachadh (lìonra ionadail, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Chan eil -STR_NETWORK_START_SERVER_ADVERTISED :Tha STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} {P chliant chliant cliantan cliant} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Cliantan air a char as motha: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Tagh an àireamh as motha dhe chliantan. Cha leig thu leas a h-uile slot a lìonadh @@ -2156,46 +2154,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Bidh fio STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Cuir a-steach ainm airson a' gheama lìonraidh -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Cànan sam bith -STR_NETWORK_LANG_ENGLISH :Beurla -STR_NETWORK_LANG_GERMAN :Gearmailtis -STR_NETWORK_LANG_FRENCH :Fraingis -STR_NETWORK_LANG_BRAZILIAN :Portagailis Bhraisileach -STR_NETWORK_LANG_BULGARIAN :Bulgarais -STR_NETWORK_LANG_CHINESE :Sìnis -STR_NETWORK_LANG_CZECH :Seacais -STR_NETWORK_LANG_DANISH :Danmhairgis -STR_NETWORK_LANG_DUTCH :Duitsis -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fionnlannais -STR_NETWORK_LANG_HUNGARIAN :Ungairis -STR_NETWORK_LANG_ICELANDIC :Tìlis -STR_NETWORK_LANG_ITALIAN :Eadailtis -STR_NETWORK_LANG_JAPANESE :Seapanais -STR_NETWORK_LANG_KOREAN :Coirèanais -STR_NETWORK_LANG_LITHUANIAN :Liotuainis -STR_NETWORK_LANG_NORWEGIAN :Nirribhis -STR_NETWORK_LANG_POLISH :Pòlainnis -STR_NETWORK_LANG_PORTUGUESE :Portagailis -STR_NETWORK_LANG_ROMANIAN :Romàinis -STR_NETWORK_LANG_RUSSIAN :Ruisis -STR_NETWORK_LANG_SLOVAK :Slòbhacais -STR_NETWORK_LANG_SLOVENIAN :Slòbhainis -STR_NETWORK_LANG_SPANISH :Spàinntis -STR_NETWORK_LANG_SWEDISH :Suainis -STR_NETWORK_LANG_TURKISH :Turcais -STR_NETWORK_LANG_UKRAINIAN :Ucràinis -STR_NETWORK_LANG_AFRIKAANS :Afraganais -STR_NETWORK_LANG_CROATIAN :Cròthaisis -STR_NETWORK_LANG_CATALAN :Catalanais -STR_NETWORK_LANG_ESTONIAN :Eastoinis -STR_NETWORK_LANG_GALICIAN :Gailìsis -STR_NETWORK_LANG_GREEK :Greugais -STR_NETWORK_LANG_LATVIAN :Laitbheis -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Lobaidh nan geamannan ioma-chluicheadair @@ -2246,15 +2204,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Tha a' c # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liosta nan cliant -STR_NETWORK_COMPANY_LIST_SPECTATE :Coimhead air -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Companaidh ùr # Network client list -STR_NETWORK_CLIENTLIST_KICK :Thoir a bhròg dha -STR_NETWORK_CLIENTLIST_BAN :Toirmisg -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Bruidhinn ris a h-uile duine -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Bruidhinn ris a' chompanaidh -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Teachdaireachd phrìobhaideach + + STR_NETWORK_SERVER :Frithealaiche STR_NETWORK_CLIENT :Cliant diff --git a/src/lang/galician.txt b/src/lang/galician.txt index 26197cf18c..f396db22ea 100644 --- a/src/lang/galician.txt +++ b/src/lang/galician.txt @@ -989,6 +989,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Seleccio STR_GAME_OPTIONS_RESOLUTION_OTHER :outra + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamaño da interface STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Seleciona o tamaño de elementos da interface a usar @@ -1916,6 +1917,7 @@ STR_FACE_TIE :Garavata: STR_FACE_EARRING :Pendentes: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambia-la garavata ou os pendentes + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multixogador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nome do xogador: @@ -1974,10 +1976,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}O nome d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Establecer contrasinal STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protexe a túa partida cun contrasinal se non queres ser accesible públicamente -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Anunciado -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Escolle entre unha partida con anuncios (internet) ou sen eles (LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Non -STR_NETWORK_START_SERVER_ADVERTISED :Si STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Escolle o máximo número de clientes. Non tódolos ocos teñen que estar cubertos @@ -1992,46 +1990,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Outros x STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Escribe un nome para a partida en rede -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Calquera -STR_NETWORK_LANG_ENGLISH :Inglés -STR_NETWORK_LANG_GERMAN :Alemán -STR_NETWORK_LANG_FRENCH :Francés -STR_NETWORK_LANG_BRAZILIAN :Brasileiro -STR_NETWORK_LANG_BULGARIAN :Búlgaro -STR_NETWORK_LANG_CHINESE :Chinés -STR_NETWORK_LANG_CZECH :Checo -STR_NETWORK_LANG_DANISH :Danés -STR_NETWORK_LANG_DUTCH :Holandés -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finés -STR_NETWORK_LANG_HUNGARIAN :Húngaro -STR_NETWORK_LANG_ICELANDIC :Islandés -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Xaponés -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Noruegués -STR_NETWORK_LANG_POLISH :Polaco -STR_NETWORK_LANG_PORTUGUESE :Portugués -STR_NETWORK_LANG_ROMANIAN :Rumano -STR_NETWORK_LANG_RUSSIAN :Ruso -STR_NETWORK_LANG_SLOVAK :Eslovaco -STR_NETWORK_LANG_SLOVENIAN :Esloveno -STR_NETWORK_LANG_SPANISH :Español -STR_NETWORK_LANG_SWEDISH :Sueco -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraniano -STR_NETWORK_LANG_AFRIKAANS :Africano -STR_NETWORK_LANG_CROATIAN :Croata -STR_NETWORK_LANG_CATALAN :Catalán -STR_NETWORK_LANG_ESTONIAN :Estonio -STR_NETWORK_LANG_GALICIAN :Galego -STR_NETWORK_LANG_GREEK :Grego -STR_NETWORK_LANG_LATVIAN :Letón -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sala de espera de partida multixogador @@ -2079,19 +2037,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desconec STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}O servidor está protexido. Introduce o contrasinal STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}A compañía está protexida. Introduce o contrasinal -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista de clientes # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes -STR_NETWORK_COMPANY_LIST_SPECTATE :Observar -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova compañía # Network client list -STR_NETWORK_CLIENTLIST_KICK :Chimpar -STR_NETWORK_CLIENTLIST_BAN :Bloquear -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Falar a todos -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Falar con compañía -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mensaxe privada + + STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente diff --git a/src/lang/german.txt b/src/lang/german.txt index 17eba21e01..bb6c428c37 100644 --- a/src/lang/german.txt +++ b/src/lang/german.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysische Rin STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Linksverkehr STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Rechtsverkehr -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Städtenamen +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Städtenamen: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Wähle die Sprache für die Städtenamen aus ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Alle 12 Monate STR_GAME_OPTIONS_LANGUAGE :{BLACK}Sprache STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Sprache für die Spieloberfläche auswählen +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% abgeschlossen) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Vollbild STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD im Vollbildmodus spielen @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Dieses Kästchen ankreuzen, um OpenTTD zu erlauben, die Hardwarebeschleunigung zu verwenden. Eine geänderte Einstellung wird nur beim Spielneustart wirksam STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Die Einstellung tritt nur nach einem Neustart des Spiels in Kraft +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Dieses Kästchen ankreuzen, um VSync zu aktivieren. Eine geänderte Einstellung wird nur beim Spielneustart wirksam. Funktioniert nur mit aktivierter Hardwarebeschleunigung + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Größe der Bedienelemente STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Wähle die Größe der Bedienelemente @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Einstell STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Suchtext: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Alles ausklappen STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Alles einklappen +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Alle Werte zurücksetzen STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(keine Erklärung verfügbar) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standardwert: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Art der Einstellung: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Karten-Einstell STR_CONFIG_SETTING_TYPE_GAME_INGAME :Karten-Einstellung (im Spielstand gespeichert; beeinflusst nur aktuelles Spiel) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Firmen-Einstellung (in Spielständen gespeichert; beeinflusst nur neue Spiele) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Firmen-Einstellung (im Spielstand gespeichert; beeinflusst nur aktuelle Firma) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Achtung! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Diese Aktion setzt alle Spieleinstellungen auf ihre Standardwerte zurück.{}Sind Sie sicher, dass Sie fortfahren möchten? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategorie: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Art: @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Krawatte: STR_FACE_EARRING :Ohrring: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Krawatte oder Ohrring ändern +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privat +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Öffentlich + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mehrspieler STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spielername: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Der Name STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Passwort setzen STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Ein Passwort verhindert, dass unbefugte Leute beitreten -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Angekündigt -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Zwischen öffentlich angekündigtem (Internet) und nicht angekündigtem (Local Area Network, LAN) Spiel wählen -STR_NETWORK_START_SERVER_UNADVERTISED :Nein -STR_NETWORK_START_SERVER_ADVERTISED :Ja +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Sichtbarkeit +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Ob andere Personen Ihren Server in der öffentlichen Liste sehen können STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Teilnehmer STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximale Teilnehmeranzahl: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Auswahl der maximal erlaubten Anzahl von Teilnehmern. Nicht alle Slots müssen belegt werden @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Damit an STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Namen für das Netzwerkspiel eingeben -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Egal -STR_NETWORK_LANG_ENGLISH :Englisch -STR_NETWORK_LANG_GERMAN :Deutsch -STR_NETWORK_LANG_FRENCH :Französisch -STR_NETWORK_LANG_BRAZILIAN :Brasilianisch -STR_NETWORK_LANG_BULGARIAN :Bulgarisch -STR_NETWORK_LANG_CHINESE :Chinesisch -STR_NETWORK_LANG_CZECH :Tschechisch -STR_NETWORK_LANG_DANISH :Dänisch -STR_NETWORK_LANG_DUTCH :Niederländisch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnisch -STR_NETWORK_LANG_HUNGARIAN :Ungarisch -STR_NETWORK_LANG_ICELANDIC :Isländisch -STR_NETWORK_LANG_ITALIAN :Italienisch -STR_NETWORK_LANG_JAPANESE :Japanisch -STR_NETWORK_LANG_KOREAN :Koreanisch -STR_NETWORK_LANG_LITHUANIAN :Litauisch -STR_NETWORK_LANG_NORWEGIAN :Norwegisch -STR_NETWORK_LANG_POLISH :Polnisch -STR_NETWORK_LANG_PORTUGUESE :Portugiesisch -STR_NETWORK_LANG_ROMANIAN :Rumänisch -STR_NETWORK_LANG_RUSSIAN :Russisch -STR_NETWORK_LANG_SLOVAK :Slowakisch -STR_NETWORK_LANG_SLOVENIAN :Slowenisch -STR_NETWORK_LANG_SPANISH :Spanisch -STR_NETWORK_LANG_SWEDISH :Schwedisch -STR_NETWORK_LANG_TURKISH :Türkisch -STR_NETWORK_LANG_UKRAINIAN :Ukrainisch -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatisch -STR_NETWORK_LANG_CATALAN :Katalanisch -STR_NETWORK_LANG_ESTONIAN :Estnisch -STR_NETWORK_LANG_GALICIAN :Galizisch -STR_NETWORK_LANG_GREEK :Griechisch -STR_NETWORK_LANG_LATVIAN :Lettisch -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Mehrspielerlobby @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Trennen STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server ist geschützt. Passwort eingeben: STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firma ist geschützt. Passwort eingeben: -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Teilnehmerliste # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Teilnehmerliste -STR_NETWORK_COMPANY_LIST_SPECTATE :Zuschauen -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Neue Firma +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Online-Spieler # Network client list -STR_NETWORK_CLIENTLIST_KICK :Hinauswerfen -STR_NETWORK_CLIENTLIST_BAN :Sperren -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Mit allen sprechen -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Mit Firma sprechen -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Private Nachricht +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Mehrspieler +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Name des Servers auf dem Sie spielen +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Ihren Servernamen bearbeiten +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Name des Servers +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Sichtbarkeit +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Ob andere Personen Ihren Server in der öffentlichen Liste sehen können +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Spieler +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Name +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Ihr Spielername +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Ihren Spielernamen bearbeiten +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Ihr Spielername +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Auszuübende administrative Aktionen für diesen Teilnehmer +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Auszuübende administrative Aktionen für diese Firma +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Dieser Firma beitreten +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Eine Nachricht an diesen Spieler schicken +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Eine Nachricht an alle Spieler dieser Firma schicken +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Eine Nachricht an alle Zuschauer schicken +STR_NETWORK_CLIENT_LIST_SPECTATORS :Zuschauer +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Neue Firma) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Eine neue Firma gründen und beitreten +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Das sind Sie +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dies ist der Host des Spiels + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Hinauswerfen +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bannen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Löschen +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Passwort entsperren + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Admin-Aktion +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Sind Sie sicher, dass Sie Spieler '{STRING}' hinauswerfen möchten? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Sind Sie sicher, dass Sie Spieler '{STRING}' bannen möchten? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Sind Sie sicher, dass Sie die Firma '{COMPANY}' löschen möchten? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Sind Sie sicher, dass Sie das Passwort der Firma '{COMPANY}' zurücksetzen möchten? STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Teilnehmer @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Server k STR_NETWORK_ERROR_CLIENT_START :{WHITE}Verbindung konnte nicht hergestellt werden STR_NETWORK_ERROR_TIMEOUT :{WHITE}Verbindung #{NUM} hat das Zeitlimit überschritten STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Protokollfehler: Die Verbindung musste getrennt werden +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Ihr Spielername wurde nicht gesetzt. Der Name kann im Mehrspielerfenster oben gesetzt werden STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Diese Version des Spiels entspricht nicht der des Servers STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Falsches Passwort STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Der Server ist voll @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Zeit fü STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Dieser Computer ist sehr langsam, sodass er nicht mit dem Server mithalten kann STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Das Herunterladen der Karte dauerte zu lange STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Der Beitritt zum Server dauerte zu lange +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Ihr Spielername ist ungültig ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :Allgemeiner Fehler @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :Zeitüberschrei STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :Allgemeine Zeitüberschreitung STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :das Herunterladen der Karte dauerte zu lange STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :Verarbeitung der Karte dauerte zu lange +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :Ungültiger Teilnehmername ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Möglicher Verbindungsabbruch @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Hafen ba STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Positionsboje, wird als Wegpunkt benötigt. Umschalt schaltet zwischen Bauen und Kostenvoranschlag um STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Aquädukt bauen. Umschalt schaltet zwischen Bauen und Kostenvoranschlag um STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Wasser erzeugen.{}Baut einen Kanal. Auf Meereshöhe wird bei gedrückter Strg-Taste ein Wasserfeld erzeugt, welches umliegendes Land flutet -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Flüsse platzieren +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Flüsse platzieren. Strg wählt das Gebiet diagonal # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ausrichtung der Werft @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Warnung: { STR_NEWGRF_ERROR_MSG_ERROR :{RED}Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Schwerer Fehler: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ein schwerer NewGRF-Fehler ist aufgetreten:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ein NewGRF-Fehler ist aufgetreten:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} funktioniert nicht im Zusammenhang mit der von OpenTTD ermittelten TTDPatch-Version STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} ist für die {STRING}-Version von TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} ist für die Nutzung mit {STRING} vorgesehen diff --git a/src/lang/greek.txt b/src/lang/greek.txt index 6ce53a6b39..e5069e4d94 100644 --- a/src/lang/greek.txt +++ b/src/lang/greek.txt @@ -1101,6 +1101,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Διαλ STR_GAME_OPTIONS_RESOLUTION_OTHER :άλλη + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Μέγεθος διεπαφής STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Επιλέξτε το μέγεθος στοιχείου διεπαφής @@ -2036,6 +2037,7 @@ STR_FACE_TIE :Γραβάτα: STR_FACE_EARRING :Σκουλαρίκι: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Αλλαγή γραβάτας ή σκουλαρικιού + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Παιχνίδι πολλών παικτών STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Όνομα παίκτη: @@ -2095,10 +2097,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Το ό STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Θέση κωδικού STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Προστατέψτε το παιχνίδι με έναν κωδικό εάν δε θέλετε να είναι δημοσίως προσβάσιμο -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Διαφημιζόμενο -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Επιλογή ανάμεσα σε ένα διαφημιζόμενο (διαδίκτυο) ή μη διαφημιζόμενο (Τοπικό Δίκτυο/LAN) παιχνίδι -STR_NETWORK_START_SERVER_UNADVERTISED :Όχι -STR_NETWORK_START_SERVER_ADVERTISED :Ναι STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} συμπαίκτ{P ης ες} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Μέγιστος αριθμός συμμετεχόντων: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Επιλέξτε τον μέγιστο αριθμό συμμετεχόντων. Δεν είναι ανάγκη να γεμίσουν όλες οι θέσεις @@ -2113,46 +2111,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Οι υ STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Εισάγετε το όνομα του δικτυακού παιχνιδιού -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Οποιαδήποτε -STR_NETWORK_LANG_ENGLISH :Αγγλικά -STR_NETWORK_LANG_GERMAN :Γερμανικά -STR_NETWORK_LANG_FRENCH :Γαλλικά -STR_NETWORK_LANG_BRAZILIAN :Βραζιλιάνικα -STR_NETWORK_LANG_BULGARIAN :Βουλγαρικά -STR_NETWORK_LANG_CHINESE :Κινέζικα -STR_NETWORK_LANG_CZECH :Τσεχικά -STR_NETWORK_LANG_DANISH :Δανικά -STR_NETWORK_LANG_DUTCH :Ολλανδικά -STR_NETWORK_LANG_ESPERANTO :Εσπεράντο -STR_NETWORK_LANG_FINNISH :Φιλανδικά -STR_NETWORK_LANG_HUNGARIAN :Ουγγρικά -STR_NETWORK_LANG_ICELANDIC :Ισλανδικά -STR_NETWORK_LANG_ITALIAN :Ιταλικά -STR_NETWORK_LANG_JAPANESE :Ιαπωνικά -STR_NETWORK_LANG_KOREAN :Κορεατικά -STR_NETWORK_LANG_LITHUANIAN :Λιθουανικά -STR_NETWORK_LANG_NORWEGIAN :Νορβηγικά -STR_NETWORK_LANG_POLISH :Πολωνικά -STR_NETWORK_LANG_PORTUGUESE :Πορτογαλικά -STR_NETWORK_LANG_ROMANIAN :Ρουμανικά -STR_NETWORK_LANG_RUSSIAN :Ρωσικά -STR_NETWORK_LANG_SLOVAK :Σλοβακικά -STR_NETWORK_LANG_SLOVENIAN :Σλοβενικά -STR_NETWORK_LANG_SPANISH :Ισπανικά -STR_NETWORK_LANG_SWEDISH :Σουηδικά -STR_NETWORK_LANG_TURKISH :Τουρκικά -STR_NETWORK_LANG_UKRAINIAN :Ουκρανικά -STR_NETWORK_LANG_AFRIKAANS :Αφρικάνς -STR_NETWORK_LANG_CROATIAN :Κροατικά -STR_NETWORK_LANG_CATALAN :Καταλανικά -STR_NETWORK_LANG_ESTONIAN :Εσθονικά -STR_NETWORK_LANG_GALICIAN :Γαλικιανά -STR_NETWORK_LANG_GREEK :Ελληνικά -STR_NETWORK_LANG_LATVIAN :Λετονικά -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Αίθουσα παιχνιδιού για πολλούς παίκτες @@ -2200,19 +2158,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Αποσ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Η πρόσβαση στον διακομιστή προστατεύεται. Εισάγετε τον κωδικό STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Η εταιρεία προστατεύεται από κωδικό. Εισάγετε κωδικό -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Λίστα συμμετεχόντων # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Λίστα συμμετεχόντων -STR_NETWORK_COMPANY_LIST_SPECTATE :Παρακολούθηση -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Νέα εταιρεία # Network client list -STR_NETWORK_CLIENTLIST_KICK :Εκδίωξη -STR_NETWORK_CLIENTLIST_BAN :Απαγόρευση -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Μιλήστε σε όλους -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Μιλήστε στην εταιρεία -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Προσωπικό μήνυμα + + STR_NETWORK_SERVER :Διακομιστής STR_NETWORK_CLIENT :Πελάτης diff --git a/src/lang/hebrew.txt b/src/lang/hebrew.txt index d4f9a835c1..e27bb6261a 100644 --- a/src/lang/hebrew.txt +++ b/src/lang/hebrew.txt @@ -988,6 +988,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}בחר STR_GAME_OPTIONS_RESOLUTION_OTHER :אחר + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}גודל ממשק STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}בחר את ממשק גודל העצם לשימוש @@ -1894,6 +1895,7 @@ STR_FACE_TIE ::עניבה STR_FACE_EARRING ::עגילים STR_FACE_TIE_EARRING_TOOLTIP :{BLACK} שנה עניבה/עגילים + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}משחק רשת STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK} :שם השחקן @@ -1952,10 +1954,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}השם STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}קבע סיסמה STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}הגן על המשחק שלך עם סיסמה אם אתה לא רוצה שהוא יהיה זמין לכולם -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}מפורסם -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}בחר בין משחק מפורסם (אינטרנטי) ומשחק לא מפורסם (רשת מקומית, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :לא -STR_NETWORK_START_SERVER_ADVERTISED :כן STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} לקוח{P "" "ות"} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}מספר מקסימלי של לקוחות: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK} :מספר משתתפים מירבי @@ -1970,46 +1968,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}שחקנ STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}הזן שם למשחק רשת -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :כלשהו -STR_NETWORK_LANG_ENGLISH :אנגלית -STR_NETWORK_LANG_GERMAN :גרמנית -STR_NETWORK_LANG_FRENCH :צרפתית -STR_NETWORK_LANG_BRAZILIAN :ברזילאית -STR_NETWORK_LANG_BULGARIAN :בולגרית -STR_NETWORK_LANG_CHINESE :סינית -STR_NETWORK_LANG_CZECH :צ'כית -STR_NETWORK_LANG_DANISH :דנית -STR_NETWORK_LANG_DUTCH :הולנדית -STR_NETWORK_LANG_ESPERANTO :אספרנטו -STR_NETWORK_LANG_FINNISH :פינית -STR_NETWORK_LANG_HUNGARIAN :הונגרית -STR_NETWORK_LANG_ICELANDIC :איסלנדית -STR_NETWORK_LANG_ITALIAN :איטלקית -STR_NETWORK_LANG_JAPANESE :יפנית -STR_NETWORK_LANG_KOREAN :קוריאנית -STR_NETWORK_LANG_LITHUANIAN :לטבית -STR_NETWORK_LANG_NORWEGIAN :נורבגית -STR_NETWORK_LANG_POLISH :פולנית -STR_NETWORK_LANG_PORTUGUESE :פורטוגזית -STR_NETWORK_LANG_ROMANIAN :רומנית -STR_NETWORK_LANG_RUSSIAN :רוסית -STR_NETWORK_LANG_SLOVAK :סלובקית -STR_NETWORK_LANG_SLOVENIAN :סלובנית -STR_NETWORK_LANG_SPANISH :ספרדית -STR_NETWORK_LANG_SWEDISH :שבדית -STR_NETWORK_LANG_TURKISH :טורקית -STR_NETWORK_LANG_UKRAINIAN :אוקראינית -STR_NETWORK_LANG_AFRIKAANS :אפריקנית -STR_NETWORK_LANG_CROATIAN :קרואטית -STR_NETWORK_LANG_CATALAN :קטלונית -STR_NETWORK_LANG_ESTONIAN :אסטונית -STR_NETWORK_LANG_GALICIAN :גליציאנית -STR_NETWORK_LANG_GREEK :יוונית -STR_NETWORK_LANG_LATVIAN :לטבית -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}לובי של משחק רשת @@ -2060,15 +2018,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}חברה # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :רשימת משתתפים -STR_NETWORK_COMPANY_LIST_SPECTATE :צפה -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :חברה חדשה # Network client list -STR_NETWORK_CLIENTLIST_KICK :בעט -STR_NETWORK_CLIENTLIST_BAN :חסימה -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :דבר לכולם -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :דבר לחברה -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :הודעה פרטית + + STR_NETWORK_SERVER :שרת STR_NETWORK_CLIENT :לקוח diff --git a/src/lang/hindi.txt b/src/lang/hindi.txt new file mode 100644 index 0000000000..220e584b4c --- /dev/null +++ b/src/lang/hindi.txt @@ -0,0 +1,1059 @@ +##name Hindi +##ownname हिन्दी +##isocode hi_IN +##plural 0 +##textdir ltr +##digitsep , +##digitsepcur , +##decimalsep . +##winlangid 0x0439 +##grflangid 0x17 + + +# This file is part of OpenTTD. +# OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. +# OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + + +##id 0x0000 +STR_NULL : +STR_EMPTY : + +# Cargo related strings +# Plural cargo name +STR_CARGO_PLURAL_NOTHING : +STR_CARGO_PLURAL_COAL :कोयला + +# Singular cargo name +STR_CARGO_SINGULAR_NOTHING : +STR_CARGO_SINGULAR_MAIZE :मक्का +STR_CARGO_SINGULAR_SWEETS :मिठाई + +# Quantity of cargo +STR_QUANTITY_NOTHING : + +# Two letter abbreviation of cargo name +STR_ABBREV_NOTHING : + +# 'Mode' of transport for cargoes + +# Colours, do not shuffle +STR_COLOUR_PINK :गुलाबी + +# Units used in OpenTTD + + + + + + + + +# Common window strings + + + +# Show engines button + + +# Query window + +# On screen keyboard window + +# Measurement tooltip + + +# These are used in buttons +STR_SORT_BY_CAPTION_DATE :{BLACK}दिनाँक +# These are used in dropdowns +STR_SORT_BY_PRODUCTION :उत्पादन +STR_SORT_BY_PROFIT_LAST_YEAR :पिछले वर्ष का लाभ +STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :इस वर्ष का कुल लाभ +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :पिछले वर्ष का औसत लाभ + +# Group by options for vehicle list + +# Tooltips for the main toolbar + +# Extra tooltips for the scenario editor toolbar + +############ range for SE file menu starts +STR_SCENEDIT_FILE_MENU_SEPARATOR : +############ range for SE file menu starts + +############ range for settings menu starts +############ range ends here + +############ range for file menu starts +STR_FILE_MENU_SEPARATOR : +############ range ends here + +# map menu + +############ range for town menu starts +############ range ends here + +############ range for subsidies menu starts +############ range ends here + +############ range for graph menu starts +############ range ends here + +############ range for company league menu starts +############ range ends here + +############ range for industry menu starts +############ range ends here + +############ range for railway construction menu starts +############ range ends here + +############ range for road construction menu starts +############ range ends here + +############ range for waterways construction menu starts +############ range ends here + +############ range for airport construction menu starts +############ range ends here + +############ range for landscaping menu starts +############ range ends here + +############ range for music menu starts +############ range ends here + +############ range for message menu starts +############ range ends here + +############ range for about menu starts +STR_ABOUT_MENU_SEPARATOR : +############ range ends here + +############ range for ordinal numbers used for the place in the highscore window +STR_ORDINAL_NUMBER_2ND :द्वितीय +############ range for ordinal numbers ends + +############ range for days starts +############ range for days ends + +############ range for months starts +STR_MONTH_ABBREV_JAN :जन +STR_MONTH_ABBREV_NOV :नव + +############ range for months ends + +# Graph window +STR_GRAPH_X_LABEL_MONTH :{TINY_FONT}{STRING} +STR_GRAPH_Y_LABEL :{TINY_FONT}{STRING} +STR_GRAPH_Y_LABEL_NUMBER :{TINY_FONT}{COMMA} + + +STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING} + + +# Graph key window + +# Company league window + +# Performance detail window +############ Those following lines need to be in this order!! +STR_PERFORMANCE_DETAIL_VEHICLES :{BLACK}वाहन: +############ End of order list + +# Music window +STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} + +# Playlist window + +# Highscore window + +# Smallmap window + + + +STR_SMALLMAP_LINKSTATS :{TINY_FONT}{STRING} +STR_SMALLMAP_COMPANY :{TINY_FONT}{COMPANY} +STR_SMALLMAP_TOWN :{TINY_FONT}{WHITE}{TOWN} + +# Status bar messages + +# News message history + +STR_NEWS_CUSTOM_ITEM :{BIG_FONT}{BLACK}{STRING} + + + + + + + + + + + +# Order review system / warnings + + + +STR_NEWS_NEW_VEHICLE_TYPE :{BIG_FONT}{BLACK}{ENGINE} + + + + + +# Extra view window + +# Game options window + +############ start of currency region +STR_GAME_OPTIONS_CURRENCY_HKD :हाँग काँग डॉलर (एचकेडी) +############ end of currency region + +STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :दाईं ओर वाहन चलाएँ + + +############ start of townname region +STR_GAME_OPTIONS_TOWN_NAME_FRENCH :फ़्रेंच +STR_GAME_OPTIONS_TOWN_NAME_POLISH :पोलिश +STR_GAME_OPTIONS_TOWN_NAME_TURKISH :तुर्की +STR_GAME_OPTIONS_TOWN_NAME_ITALIAN :इटैलियन +############ end of townname region + + +############ start of autosave dropdown +STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :प्रत्येक माह +############ end of autosave dropdown + + + + + + + + + + + + + + + + +# Custom currency window + + + + + + + + + +STR_AI_SPEED_SLOW :धीमा + + + + + + + + +# Settings tree window + + + + +STR_CONFIG_SETTING_COMPANIES_OFF :बन्द + + + + +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE :{NUM} + + + +STR_CONFIG_SETTING_ORDER_REVIEW_OFF :नहीं + + + + + + + + +STR_CONFIG_SETTING_SOUND_NEWS :समाचार पत्र: {STRING} + + + + + + + + +STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM} + + + +STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} +STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_IN_2X :२x + + + + + + + + + + + + +# Config errors + +# Video initalization errors + +# Intro window + + + + + + + +# Quit window +STR_QUIT_YES :{BLACK}हाँ + +# Abandon game + +# Cheat window + +# Livery window + + + +# Face selection window + + + +# Network server list + +STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x{COMMA} + + + + + + +# Start new multiplayer server + + + + +# Network game lobby + + +STR_NETWORK_GAME_LOBBY_INAUGURATION_YEAR :{SILVER}उद्घाटन: {WHITE}{NUM} + + + +# Network connecting window + +############ Leave those lines in this order!! + +############ End of leave-in-this-order + + + +# Network company list added strings + +# Network client list + + + + +# Network set password + +# Network company info join/password + +# Network chat + + +# Network messages + +############ Leave those lines in this order!! +############ End of leave-in-this-order + + +# Network related errors +############ Leave those lines in this order!! +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :खेल अभी भी ठहरा हुआ है ({STRING}, {STRING}, {STRING}) +############ End of leave-in-this-order + +# Content downloading window + +# Order of these is important! + +# Content downloading progress window + +# Content downloading error messages + + + +# Transparency settings window + +# Linkgraph legend window + +# Linkgraph legend window and linkgraph legend in smallmap + +# Base for station construction window(s) + +# Join station window + + +# Generic toolbar + +# Rail construction toolbar + + + +# Rail depot construction window + +# Rail waypoint construction window + +# Rail station construction window + + + +# Signal window + +# Bridge selection window + + +# Road construction toolbar + + +# Road depot construction window + +# Road vehicle station construction window + +# Waterways toolbar (last two for SE only) + +# Ship depot construction window + +# Dock construction window + +# Airport toolbar + +# Airport construction window + + + + +# Landscaping toolbar + +# Object construction window + + +# Tree planting window (last eight for SE only) + +# Land generation window (SE) + + +# Town generation window (SE) + + +STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON :{BLACK}लघु +STR_FOUND_TOWN_CITY :{BLACK}शहर + + +# Fund new industry window + +# Industry cargoes window + +# Land area window + +# Description of land area of different tiles + + + +# Houses come directly from their building names + + + + +# Industries come directly from their industry names + + + + + + +# About OpenTTD window + +# Framerate display window +STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} +############ Leave those lines in this order!! +############ End of leave-in-this-order +############ Leave those lines in this order!! +############ End of leave-in-this-order + + +# Save/load game/scenario + + +# World generation + +# Strings for map borders at game generation +STR_MAPGEN_BORDER_WATER :{BLACK}जल + + + +# SE Map generation + + +# Map generation progress +STR_GENERATION_PROGRESS_NUM :{BLACK}{NUM} / {NUM} + +# NewGRF settings + + + + + +# NewGRF save preset window + +# NewGRF parameters window + +# NewGRF inspect window + + + +# Sprite aligner window + + +# NewGRF (self) generated warnings/errors +STR_NEWGRF_ERROR_MSG_INFO :{SILVER}{STRING} + +# NewGRF related 'general' warnings + + + +# NewGRF status + +# NewGRF 'it's broken' warnings + + +# 'User removed essential NewGRFs'-placeholders for stuff without specs + +# Placeholders for other invalid stuff, e.g. vehicles that have gone (Game Script). + +# NewGRF scanning window + +# Sign list window + +# Sign window + + +# Town directory window + +# Town view window +STR_TOWN_VIEW_TOWN_CAPTION :{WHITE}{TOWN} +STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}स्थानीय प्राधिकारी के बारे में जानकारी दिखाएँ + +STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}फैलाएँ + + +# Town local authority window + + + +# Goal window +STR_GOALS_TEXT :{ORANGE}{STRING} +STR_GOALS_PROGRESS :{ORANGE}{STRING} +STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} + +# Goal question window + +############ Start of Goal Question button list +############ End of Goal Question button list + +# Subsidies window + +# Story book window +STR_STORY_BOOK_TITLE :{YELLOW}{STRING} +STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}अगले पृष्ठ पर जाएँ + +# Station list window +STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} +STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} + +# Station view window +STR_STATION_VIEW_CAPTION :{WHITE}{STATION} {STATION_FEATURES} +STR_STATION_VIEW_WAITING_CARGO :{WHITE}{CARGO_LONG} + + + + + + +############ range for rating starts +############ range for rating ends + + + + + +# Waypoint/buoy view window +STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} + + +# Finances window +STR_FINANCES_YEAR :{WHITE}{NUM} +STR_FINANCES_POSITIVE_INCOME :{BLACK}+{CURRENCY_LONG} +STR_FINANCES_TOTAL_CURRENCY :{BLACK}{CURRENCY_LONG} +STR_FINANCES_BORROW_BUTTON :{BLACK}{CURRENCY_LONG} उधार + +# Company view +STR_COMPANY_VIEW_CAPTION :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM} +STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE :{WHITE}{PRESIDENT_NAME}{}{GOLD}(प्रबन्धक) + + + + + + + +# Company infrastructure window + +# Industry directory +STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}उद्योग +STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} +STR_INDUSTRY_DIRECTORY_ITEM_PROD1 :{ORANGE}{INDUSTRY} {STRING} + +# Industry view +STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} + + +STR_INDUSTRY_VIEW_ACCEPT_CARGO :{YELLOW}{STRING}{BLACK}{3:STRING} + + +# Vehicle lists + + + + + + + + +# Group window + + + + + + + + +# Build vehicle window + + +############ range for vehicle availability starts +############ range for vehicle availability ends + + + + + + + + + + + + + +# Depot window +STR_DEPOT_CAPTION :{WHITE}{DEPOT} + + +STR_DEPOT_VEHICLE_TOOLTIP :{BLACK}{ENGINE}{STRING} + + + + + + + + + + + + + + + +# Engine preview window + + + +STR_ENGINE_PREVIEW_SHIP :जहाज + + +# Autoreplace window + + + +STR_REPLACE_VEHICLES_STOP :वाहन प्रतिस्थापित करना बन्द करें + + + + + +# Vehicle view +STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} + + + + + + + + + + + +# Messages in the start stop button in the vehicle view + + +# Vehicle stopped/started animations + +# Vehicle details + + +# The next two need to stay in this order + + + + + + + + +# Extra buttons for train details windows + + + + + +# Vehicle refit + + + + +# Order view + +STR_ORDER_TEXT :{STRING} {STRING} {STRING} + + +# Order bottom buttons + + + + + + +# Conditional order variables, must follow order of OrderConditionVariable enum + +STR_ORDER_CONDITIONAL_COMPARATOR_EQUALS :के बराबर है + + + + + + +# String parts to build the order string + + +STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} {STRING} {STRING} +STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT} + + +STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} + + + + + + + + + +# Time table window + + + + + + + + + + + + + + + +# Date window (for timetable) +STR_DATE_MONTH_TOOLTIP :{BLACK}महीना चुनें + + +# AI debug window +STR_AI_DEBUG_NAME_AND_VERSION :{BLACK}{STRING} (v{NUM}) + + +# AI configuration window + + + +STR_AI_CONFIG_CHANGE_NONE : + +# Available AIs window + + + + +# AI Parameters + + +# Textfile window + + +# Vehicle loading indicators + +# Income 'floats' +STR_INCOME_FLOAT_COST :{RED}मूल्य: {CURRENCY_LONG} + +# Saveload messages + +# Map generation messages + + + + + +# Soundset messages + +# Screenshot related messages + + +# Error message titles +STR_ERROR_MESSAGE_CAPTION :{YELLOW}सन्देश + +# Generic construction errors + +# Local authority errors + +# Levelling errors +STR_ERROR_TOO_HIGH :{WHITE}... बहुत ऊँचा + +# Company related errors + + +# Town related errors + +# Industry related errors + + +# Station construction related errors + + +# Station destruction related errors + + +# Waypoint related errors + + + +# Depot related errors + + + + + + +# Autoreplace related errors + +# Rail construction errors + + +# Road construction errors + +# Waterway construction errors + +# Tree related errors + +# Bridge related errors + +# Tunnel related errors + +# Object related errors + +# Group related errors + +# Generic vehicle errors + + +STR_ERROR_CAN_T_RENAME_SHIP :{WHITE}जहाज का नामकरण नहीं कर सकते... + + + + + + + + + + +# Specific vehicle errors + + + +# Order related errors + + +# Timetable related errors + +# Sign related errors + +# Translatable comment for OpenTTD's desktop shortcut + +# Translatable descriptions in media/baseset/*.ob* files + +##id 0x2000 +# Town building names + +##id 0x4800 +# industry names +STR_INDUSTRY_NAME_POWER_STATION :बिजलीघर +STR_INDUSTRY_NAME_BANK_TROPIC_ARCTIC :बैंक + +############ WARNING, using range 0x6000 for strings that are stored in the savegame +############ These strings may never get a new id, or savegames will break! +##id 0x6000 +STR_SV_EMPTY : + +STR_SV_STNAME :{STRING} +STR_SV_STNAME_AIRPORT :{STRING} हवाई अड्डा +STR_SV_STNAME_BUOY :{STRING} +STR_SV_STNAME_WAYPOINT :{STRING} +##id 0x6020 +############ end of savegame specific region! + +##id 0x8000 +# Vehicle names +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_COAL_CAR :कोयला वाहन +STR_VEHICLE_NAME_TRAIN_WAGON_RAIL_FRUIT_TRUCK :फल वाहन +STR_VEHICLE_NAME_TRAIN_WAGON_MAGLEV_BUBBLE_VAN :बबल वैन +STR_VEHICLE_NAME_ROAD_VEHICLE_PLODDYPHUT_MKIII_BUS :प्लॉडीपीहट एमके३ बस +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_COTSWALD_LB_3 :बेकवेल कॉट्सवॉल्ड एलबी-३ +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_9 :बेकवेल लकेट एलबी-९ +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB80 :बेकवेल लकेट एलबी८० +STR_VEHICLE_NAME_AIRCRAFT_BAKEWELL_LUCKETT_LB_11 :बेकवेल लकेट एलबी-११ +STR_VEHICLE_NAME_AIRCRAFT_DARWIN_600 :डार्विन ‌६०० + +##id 0x8800 +# Formatting of some strings +STR_FORMAT_DATE_SHORT :{STRING} {NUM} +STR_FORMAT_DATE_LONG :{STRING} {STRING} {NUM} + +STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} + + + + +# Viewport strings +STR_VIEWPORT_TOWN :{WHITE}{TOWN} +STR_VIEWPORT_TOWN_TINY_BLACK :{TINY_FONT}{BLACK}{TOWN} +STR_VIEWPORT_TOWN_TINY_WHITE :{TINY_FONT}{WHITE}{TOWN} + +STR_VIEWPORT_SIGN_SMALL_BLACK :{TINY_FONT}{BLACK}{SIGN} +STR_VIEWPORT_SIGN_SMALL_WHITE :{TINY_FONT}{WHITE}{SIGN} + +STR_VIEWPORT_STATION :{STATION} {STATION_FEATURES} +STR_VIEWPORT_STATION_TINY :{TINY_FONT}{STATION} + +STR_VIEWPORT_WAYPOINT :{WAYPOINT} +STR_VIEWPORT_WAYPOINT_TINY :{TINY_FONT}{WAYPOINT} + +# Simple strings to get specific types of data +STR_COMPANY_NAME :{COMPANY} +STR_COMPANY_NAME_COMPANY_NUM :{COMPANY} {COMPANY_NUM} +STR_DEPOT_NAME :{DEPOT} +STR_ENGINE_NAME :{ENGINE} +STR_GROUP_NAME :{GROUP} +STR_INDUSTRY_NAME :{INDUSTRY} +STR_PRESIDENT_NAME :{PRESIDENT_NAME} +STR_SIGN_NAME :{SIGN} +STR_STATION_NAME :{STATION} +STR_TOWN_NAME :{TOWN} +STR_VEHICLE_NAME :{VEHICLE} +STR_WAYPOINT_NAME :{WAYPOINT} + +STR_JUST_CARGO :{CARGO_LONG} +STR_JUST_CHECKMARK :{CHECKMARK} +STR_JUST_COMMA :{COMMA} +STR_JUST_CURRENCY_SHORT :{CURRENCY_SHORT} +STR_JUST_CURRENCY_LONG :{CURRENCY_LONG} +STR_JUST_CARGO_LIST :{CARGO_LIST} +STR_JUST_INT :{NUM} +STR_JUST_DATE_TINY :{DATE_TINY} +STR_JUST_DATE_SHORT :{DATE_SHORT} +STR_JUST_DATE_LONG :{DATE_LONG} +STR_JUST_DATE_ISO :{DATE_ISO} +STR_JUST_STRING :{STRING} +STR_JUST_STRING_STRING :{STRING}{STRING} +STR_JUST_RAW_STRING :{STRING} +STR_JUST_BIG_RAW_STRING :{BIG_FONT}{STRING} + +# Slightly 'raw' stringcodes with colour or size +STR_BLACK_COMMA :{BLACK}{COMMA} +STR_TINY_BLACK_COMA :{TINY_FONT}{BLACK}{COMMA} +STR_TINY_COMMA :{TINY_FONT}{COMMA} +STR_BLUE_COMMA :{BLUE}{COMMA} +STR_RED_COMMA :{RED}{COMMA} +STR_WHITE_COMMA :{WHITE}{COMMA} +STR_TINY_BLACK_DECIMAL :{TINY_FONT}{BLACK}{DECIMAL} +STR_COMPANY_MONEY :{WHITE}{CURRENCY_LONG} +STR_BLACK_DATE_LONG :{BLACK}{DATE_LONG} +STR_WHITE_DATE_LONG :{WHITE}{DATE_LONG} +STR_SHORT_DATE :{WHITE}{DATE_TINY} +STR_DATE_LONG_SMALL :{TINY_FONT}{BLACK}{DATE_LONG} +STR_TINY_GROUP :{TINY_FONT}{GROUP} +STR_BLACK_INT :{BLACK}{NUM} +STR_ORANGE_INT :{ORANGE}{NUM} +STR_WHITE_SIGN :{WHITE}{SIGN} +STR_TINY_BLACK_STATION :{TINY_FONT}{BLACK}{STATION} +STR_BLACK_STRING :{BLACK}{STRING} +STR_BLACK_RAW_STRING :{BLACK}{STRING} +STR_ORANGE_STRING :{ORANGE}{STRING} +STR_LTBLUE_STRING :{LTBLUE}{STRING} +STR_WHITE_STRING :{WHITE}{STRING} +STR_ORANGE_STRING1_WHITE :{ORANGE}{STRING}{WHITE} +STR_ORANGE_STRING1_LTBLUE :{ORANGE}{STRING}{LTBLUE} +STR_TINY_BLACK_HEIGHT :{TINY_FONT}{BLACK}{HEIGHT} +STR_TINY_BLACK_VEHICLE :{TINY_FONT}{BLACK}{VEHICLE} +STR_TINY_RIGHT_ARROW :{TINY_FONT}{RIGHT_ARROW} + + +STR_TRAIN :{BLACK}{TRAIN} +STR_BUS :{BLACK}{BUS} +STR_LORRY :{BLACK}{LORRY} +STR_PLANE :{BLACK}{PLANE} +STR_SHIP :{BLACK}{SHIP} + diff --git a/src/lang/hungarian.txt b/src/lang/hungarian.txt index 03f76b920d..8d17f8aa53 100644 --- a/src/lang/hungarian.txt +++ b/src/lang/hungarian.txt @@ -1070,6 +1070,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardvere STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Bekapcsolásával az OpenTTD hardveres gyorsítást próbál alkalmazni. A beállítás csak a játék újraindítása után lép érvénybe. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Ez a beállítás csak a játék újraindítása után lép érvénybe +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync (Vertikális Szinkronizáció) +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Jelöld be ezt a négyzetet hogy engedélyezd a v-sync-et. A változtatás csak a játék újraindítása után fog érvényesülni. Kizárólag hardware gyorsítással működik! + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Felület mérete STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Használni kívánt felületméret kiválasztása @@ -1202,6 +1205,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Beállí STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Szűrő kifejezés: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Összes szétnyitása STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Összes összecsukása +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Visszaállítja az összes értéket STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(leírás nem elérhető) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Alapértelmezett érték: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Beállítás típusa: {ORANGE}{STRING} @@ -1210,6 +1214,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Játék beáll STR_CONFIG_SETTING_TYPE_GAME_INGAME :Játék beállítás (mentésben tárolva; csak a jelenlegi játékot befolyásolja) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Vállalat beállítás (mentésben tárolva; csak az új játékokat befolyásolja) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Vállalat beállítás (mentésben tárolva; csak a jelenlegi vállalatot befolyásolja) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Figyelem! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Ez a művelet minden játékbeállítást visszaállít.{}Biztos, hogy folytatni akarja a műveletet? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategória: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Típus: @@ -2048,6 +2054,7 @@ STR_FACE_TIE :Nyakkendő: STR_FACE_EARRING :Fülbevaló: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Nyakkendő vagy fülbevaló cseréje + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Hálózati játék STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Játékos neve: @@ -2110,10 +2117,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}A játé STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Jelszó beállítása STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Védd le a játékodat jelszóval, ha nem akarod hogy illetéktelenek csatlakozzanak -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Hírdetett -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Válassz hírdetett (internet) és nem hírdetett (helyi hálózat, LAN) játék közül. -STR_NETWORK_START_SERVER_UNADVERTISED :Nem -STR_NETWORK_START_SERVER_ADVERTISED :Igen STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} kliens STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Játékosok max. száma: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}A maximálisan felcsatlakozható kliensek számának kiválasztása. Nem szükséges pont ennyi embernek éppen kapcsolódva lennie @@ -2128,46 +2131,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}A többi STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Add meg a hálózati játékhoz a neved -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Bármilyen -STR_NETWORK_LANG_ENGLISH :Angol -STR_NETWORK_LANG_GERMAN :Német -STR_NETWORK_LANG_FRENCH :Francia -STR_NETWORK_LANG_BRAZILIAN :Brazil -STR_NETWORK_LANG_BULGARIAN :Bolgár -STR_NETWORK_LANG_CHINESE :Kínai -STR_NETWORK_LANG_CZECH :Cseh -STR_NETWORK_LANG_DANISH :Dán -STR_NETWORK_LANG_DUTCH :Holland -STR_NETWORK_LANG_ESPERANTO :Eszperantó -STR_NETWORK_LANG_FINNISH :Finn -STR_NETWORK_LANG_HUNGARIAN :Magyar -STR_NETWORK_LANG_ICELANDIC :Izlandi -STR_NETWORK_LANG_ITALIAN :Olasz -STR_NETWORK_LANG_JAPANESE :Japán -STR_NETWORK_LANG_KOREAN :Koreai -STR_NETWORK_LANG_LITHUANIAN :Litván -STR_NETWORK_LANG_NORWEGIAN :Norvég -STR_NETWORK_LANG_POLISH :Lengyel -STR_NETWORK_LANG_PORTUGUESE :Portugál -STR_NETWORK_LANG_ROMANIAN :Román -STR_NETWORK_LANG_RUSSIAN :Orosz -STR_NETWORK_LANG_SLOVAK :Szlovák -STR_NETWORK_LANG_SLOVENIAN :Szlovén -STR_NETWORK_LANG_SPANISH :Spanyol -STR_NETWORK_LANG_SWEDISH :Svéd -STR_NETWORK_LANG_TURKISH :Török -STR_NETWORK_LANG_UKRAINIAN :Ukrán -STR_NETWORK_LANG_AFRIKAANS :Afrikai -STR_NETWORK_LANG_CROATIAN :Horvát -STR_NETWORK_LANG_CATALAN :Katalán -STR_NETWORK_LANG_ESTONIAN :Észt -STR_NETWORK_LANG_GALICIAN :Gall -STR_NETWORK_LANG_GREEK :Görög -STR_NETWORK_LANG_LATVIAN :Lett -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Hálózati játék előszoba @@ -2215,19 +2178,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Megszak STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}A szerver jelszóval van védve. Írd be STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}A vállalat jelszóval van védve. Írd be -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Kliens lista # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Kliens lista -STR_NETWORK_COMPANY_LIST_SPECTATE :Megfigyelés -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Új vállalat # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kirúgás -STR_NETWORK_CLIENTLIST_BAN :Kitiltás -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Üzenet mindenkinek -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Üzenet a vállalatnak -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privát üzenet + + STR_NETWORK_SERVER :Szerver STR_NETWORK_CLIENT :Kliens diff --git a/src/lang/icelandic.txt b/src/lang/icelandic.txt index a19c5d0ca0..90d27e3a05 100644 --- a/src/lang/icelandic.txt +++ b/src/lang/icelandic.txt @@ -946,6 +946,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :annað + STR_GAME_OPTIONS_BASE_GRF :{BLACK}Grunngrafík STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Nota grunngrafíkina STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} týnd{P "" ar} eða ónýt{P "" ar} skrá{P "" r} @@ -1733,6 +1734,7 @@ STR_FACE_TIE :Bindi: STR_FACE_EARRING :Eyrnalokkur: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Breyta bindi eða eyrnalokk + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Fjölspilun STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nafn leikmanns: @@ -1805,46 +1807,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aðrir n STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Sláðu inn nafn netleiksins -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Hvað sem er -STR_NETWORK_LANG_ENGLISH :Enska -STR_NETWORK_LANG_GERMAN :Þýska -STR_NETWORK_LANG_FRENCH :Franska -STR_NETWORK_LANG_BRAZILIAN :Brasilíska -STR_NETWORK_LANG_BULGARIAN :Búlgarska -STR_NETWORK_LANG_CHINESE :Kínverska -STR_NETWORK_LANG_CZECH :Tékkneska -STR_NETWORK_LANG_DANISH :Danska -STR_NETWORK_LANG_DUTCH :Hollenska -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnska -STR_NETWORK_LANG_HUNGARIAN :Ungverska -STR_NETWORK_LANG_ICELANDIC :Íslenska -STR_NETWORK_LANG_ITALIAN :Ítalska -STR_NETWORK_LANG_JAPANESE :Japanska -STR_NETWORK_LANG_KOREAN :Kóreiska -STR_NETWORK_LANG_LITHUANIAN :Litháenska -STR_NETWORK_LANG_NORWEGIAN :Norska -STR_NETWORK_LANG_POLISH :Pólska -STR_NETWORK_LANG_PORTUGUESE :Portúgalska -STR_NETWORK_LANG_ROMANIAN :Rómanska -STR_NETWORK_LANG_RUSSIAN :Rússneska -STR_NETWORK_LANG_SLOVAK :Slóvakíska -STR_NETWORK_LANG_SLOVENIAN :Slóveska -STR_NETWORK_LANG_SPANISH :Spænska -STR_NETWORK_LANG_SWEDISH :Sænska -STR_NETWORK_LANG_TURKISH :Tyrkneska -STR_NETWORK_LANG_UKRAINIAN :Úkraínska -STR_NETWORK_LANG_AFRIKAANS :Afríkanska -STR_NETWORK_LANG_CROATIAN :Króatíska -STR_NETWORK_LANG_CATALAN :Katalónska -STR_NETWORK_LANG_ESTONIAN :Eistneska -STR_NETWORK_LANG_GALICIAN :Gelíska -STR_NETWORK_LANG_GREEK :Gríska -STR_NETWORK_LANG_LATVIAN :Lettneska -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Anddyri fjölspilunarleiks @@ -1895,15 +1857,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Fyrirtæ # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Listi yfir leikmenn -STR_NETWORK_COMPANY_LIST_SPECTATE :Fylgjast með -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nýtt fyrirtæki # Network client list -STR_NETWORK_CLIENTLIST_KICK :Sparka -STR_NETWORK_CLIENTLIST_BAN :Banna -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Tala við alla -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Tala við fyrirtæki -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Einkaskilaboð + + STR_NETWORK_SERVER :Þjónn STR_NETWORK_CLIENT :Notandi diff --git a/src/lang/unfinished/ido.txt b/src/lang/ido.txt similarity index 99% rename from src/lang/unfinished/ido.txt rename to src/lang/ido.txt index 0f7b1d1573..aad91f8978 100644 --- a/src/lang/unfinished/ido.txt +++ b/src/lang/ido.txt @@ -484,6 +484,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :altra + # Custom currency window @@ -601,6 +602,7 @@ STR_QUIT_NO :{BLACK}Ne # Face selection window + # Network server list STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} @@ -616,10 +618,6 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x -# Network game languages -############ Leave those lines in this order!! -############ End of leave-in-this-order - # Network game lobby @@ -639,6 +637,8 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x # Network client list + + # Network set password # Network company info join/password diff --git a/src/lang/indonesian.txt b/src/lang/indonesian.txt index 523ab576c2..374c29059d 100644 --- a/src/lang/indonesian.txt +++ b/src/lang/indonesian.txt @@ -946,6 +946,7 @@ STR_GAME_OPTIONS_CURRENCY_NTD :Dollar Taiwan B STR_GAME_OPTIONS_CURRENCY_CNY :Renminbi Cina (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :Dollar Hong Kong (HKD) STR_GAME_OPTIONS_CURRENCY_INR :India Rupee (INR) +STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysia (MYR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Berkendara di lajur kiri @@ -999,6 +1000,9 @@ STR_GAME_OPTIONS_RESOLUTION :{BLACK}Resolusi STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Pilih resolusi layar yang diinginkan STR_GAME_OPTIONS_RESOLUTION_OTHER :lainnya +STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Akselerasi perangkat keras +STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Pengaturan hanya akan berlaku setelah game dimulai ulang + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Ukuran antarmuka STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Pilih ukuran elemen antarmuka yang akan digunakan @@ -1016,7 +1020,10 @@ STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Kali dua STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :4 kali +STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafik +STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}Menampilkan kecepatan refresh +STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}Kecepatan refresh yang lebih tinggi dari 60Hz dapat memengaruhi kinerja. STR_GAME_OPTIONS_BASE_GRF :{BLACK}Set Grafik Dasar STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Pilih grafik dasar yang digunakan @@ -1112,6 +1119,8 @@ STR_TERRAIN_TYPE_FLAT :Datar STR_TERRAIN_TYPE_HILLY :Berbukit STR_TERRAIN_TYPE_MOUNTAINOUS :Pegunungan STR_TERRAIN_TYPE_ALPINIST :Pemanjat Gunung +STR_TERRAIN_TYPE_CUSTOM :Ketinggian Kustom +STR_TERRAIN_TYPE_CUSTOM_VALUE :Ketinggian Kustom ({NUM}) STR_CITY_APPROVAL_PERMISSIVE :Selalu boleh STR_CITY_APPROVAL_TOLERANT :Toleran @@ -1193,6 +1202,8 @@ STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Mengaktifkan be STR_CONFIG_SETTING_CITY_APPROVAL :Sikap pemerintah kota terhadap restrukturasi area: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Pilih seberapa banyak dampak kebisingan dan lingkungan oleh perusahaan terhadap peringkat kota karena pembangunan di daerah +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :Ketinggian peta maksimum: {STRING} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT :Tetapkan ketinggian maksimum medan peta. Dengan "(otomatis)" nilai yang baik akan diambil setelah pembuatan medan STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Kamu tidak bisa mengubah ketinggian peta maksimum di angka itu. Setidaknya ada satu gunung di peta yang lebih tinggi STR_CONFIG_SETTING_AUTOSLOPE :Ijinkan pembentukan slop dibawah bangunan, rel, dsb.: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Ijinkan pembentukan tanah dibawah bangunan dan trek tanpa merusaknya @@ -1338,6 +1349,9 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Jarak maksimal STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Kilang minyak hanya dibangun pada tepi peta atau pantai STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Tinggi garis salju: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Mengatur ketinggian di mana salju akan muncul. Salju juga akan mempengaruhi pengembangan industri dan persyaratan untuk pertumbuhan kota +STR_CONFIG_SETTING_DESERT_COVERAGE :Cakupan gurun: {STRING} +STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Kontrol perkiraan jumlah gurun di lanskap tropis. Gurun juga mempengaruhi generasi industri. Hanya digunakan selama pembuatan peta +STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Kekasaran daratan: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(hanya TerraGenesis) Memilih frekuensi bukit: Bentang darat rata punya bukit yang lebih sedikit dan lebih lebar. Bentang darat bergunung punya lebih banyak bukit, dan ini mungkin akan terlihat lebih membosankan STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Sangat halus @@ -1643,12 +1657,15 @@ STR_CONFIG_SETTING_ZOOM_MIN :Tingkat Perbesa STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Perbesaran viewport maksimal. Semakin besar semakin banyak memori yang dibutuhkan STR_CONFIG_SETTING_ZOOM_MAX :Tingkat zoom out Maksimal: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :Pengecilan maksimum untuk viewport. Semakin kecil semakin tidak jelas +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN :Sprite resolusi tertinggi untuk digunakan: {STRING} STR_CONFIG_SETTING_ZOOM_LVL_MIN :4x STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :2x STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :4x STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :8x +STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_IN_2X :2x +STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_NORMAL :1x STR_CONFIG_SETTING_TOWN_GROWTH :Kecepatan pertumbuhan kota: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Kecepatan pertumbuhan kota STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Tidak tumbuh @@ -1783,6 +1800,7 @@ STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Kehabisa STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Mengalokasikan {BYTES} 'spritecache' gagal. 'Spritecache' dikurangi ke {BYTES}. Ini akan kurangi kinerja OpenTTD. Untuk kurangi kebutuhan memori anda bisa coba matikan grafik 32bpp dan/atau tingkat pembesaran # Video initalization errors +STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION :{WHITE}... tidak ditemukan GPU yang kompatibel. Akselerasi perangkat keras dinonaktifkan # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} @@ -1949,6 +1967,7 @@ STR_FACE_TIE :Dasi: STR_FACE_EARRING :Anting-anting: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Ubah dasi atau anting-anting + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Bermain bersama STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nama pemain: @@ -2011,10 +2030,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Nama per STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Atur kata sandi STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Lindungi permainan ini dengan kata kunci jika anda tidak ingin membiarkannya terbuka untuk umum -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Diiklankan -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Pilih antara permainan diiklankan (internet) dan tidak diiklankan (Jaringan wilayah lokal, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Tidak -STR_NETWORK_START_SERVER_ADVERTISED :Ya STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klien STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimum jumlah klien: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Pilih jumlah klien maksimal. Tidak semua slot harus diisi @@ -2029,46 +2044,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Agar pem STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Masukkan nama dari permainan di jaringan -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Segala bahasa -STR_NETWORK_LANG_ENGLISH :Inggris -STR_NETWORK_LANG_GERMAN :Jerman -STR_NETWORK_LANG_FRENCH :Perancis -STR_NETWORK_LANG_BRAZILIAN :Brazil -STR_NETWORK_LANG_BULGARIAN :Bulgaria -STR_NETWORK_LANG_CHINESE :China -STR_NETWORK_LANG_CZECH :Ceko -STR_NETWORK_LANG_DANISH :Denmark -STR_NETWORK_LANG_DUTCH :Belanda -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finlandia -STR_NETWORK_LANG_HUNGARIAN :Hungaria -STR_NETWORK_LANG_ICELANDIC :Islandia -STR_NETWORK_LANG_ITALIAN :Italia -STR_NETWORK_LANG_JAPANESE :Jepang -STR_NETWORK_LANG_KOREAN :Korea -STR_NETWORK_LANG_LITHUANIAN :Lithuania -STR_NETWORK_LANG_NORWEGIAN :Norwegia -STR_NETWORK_LANG_POLISH :Polandia -STR_NETWORK_LANG_PORTUGUESE :Portugis -STR_NETWORK_LANG_ROMANIAN :Rumania -STR_NETWORK_LANG_RUSSIAN :Rusia -STR_NETWORK_LANG_SLOVAK :Slovakia -STR_NETWORK_LANG_SLOVENIAN :Slovenia -STR_NETWORK_LANG_SPANISH :Spanyol -STR_NETWORK_LANG_SWEDISH :Swedia -STR_NETWORK_LANG_TURKISH :Turki -STR_NETWORK_LANG_UKRAINIAN :Ukrainia -STR_NETWORK_LANG_AFRIKAANS :Afrika -STR_NETWORK_LANG_CROATIAN :Kroasia -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonia -STR_NETWORK_LANG_GALICIAN :Galisia -STR_NETWORK_LANG_GREEK :Yunani -STR_NETWORK_LANG_LATVIAN :Latvia -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Lobi Bermain bersama @@ -2116,19 +2091,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Putuskan STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server terkunci, masukkan kata kunci STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Perusahaan terkunci, masukkan kata kunci -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Daftar klien # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Daftar klien -STR_NETWORK_COMPANY_LIST_SPECTATE :Menonton -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Buat Perusahaan # Network client list -STR_NETWORK_CLIENTLIST_KICK :Usir -STR_NETWORK_CLIENTLIST_BAN :Larangan -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Bicara ke semua -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Bicara ke perusahaan -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Pesan pribadi + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klien @@ -2314,6 +2283,8 @@ STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Ya, download file gambar STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Tidak, tutup OpenTTD +STR_MISSING_GRAPHICS_ERROR_TITLE :{WHITE}Gagal Mendownload +STR_MISSING_GRAPHICS_ERROR_QUIT :{BLACK}Keluar OpenTTD # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Pengaturan Transparasi @@ -2864,6 +2835,9 @@ STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Jumlah Kota: STR_MAPGEN_DATE :{BLACK}Tgl: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Jumlah industri: +STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN :{BLACK}Kurangi satu ketinggian maksimum puncak tertinggi di peta +STR_MAPGEN_SNOW_COVERAGE_DOWN :{BLACK}Kurangi cakupan salju hingga sepuluh persen +STR_MAPGEN_DESERT_COVERAGE :{BLACK}Cakupan gurun: STR_MAPGEN_LAND_GENERATOR :{BLACK}Algoritma pulau: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Jenis dataran: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Area perairan: @@ -2889,6 +2863,7 @@ STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Nama Pet STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Luas: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} +STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}Cakupan salju (dalam %) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Ganti Tahun Permulaan # SE Map generation @@ -3179,6 +3154,7 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Kolusi STR_GOALS_CAPTION :{WHITE}{COMPANY} Target STR_GOALS_SPECTATOR_CAPTION :{WHITE}Target Global STR_GOALS_SPECTATOR :Target Global +STR_GOALS_GLOBAL_BUTTON :{BLACK}Global STR_GOALS_TEXT :{ORANGE}{STRING} STR_GOALS_NONE :{ORANGE}- Tidak ada - STR_GOALS_PROGRESS :{ORANGE}{STRING} @@ -3553,6 +3529,7 @@ STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT :{BLACK}Daya Ger STR_PURCHASE_INFO_REFITTABLE_TO :{BLACK}Kargo dapat di ganti untuk: {GOLD}{STRING} STR_PURCHASE_INFO_ALL_TYPES :Semua jenis kargo STR_PURCHASE_INFO_NONE :Tidak Ada +STR_PURCHASE_INFO_ENGINES_ONLY :Hanya Lokomotif STR_PURCHASE_INFO_ALL_BUT :Semua tapi tidak untuk {CARGO_LIST} STR_PURCHASE_INFO_MAX_TE :{BLACK}Traksi Maks.: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Jangkauan: {GOLD}{COMMA} kotak diff --git a/src/lang/irish.txt b/src/lang/irish.txt index 7112452882..6a2b65438c 100644 --- a/src/lang/irish.txt +++ b/src/lang/irish.txt @@ -969,6 +969,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Roghnaig STR_GAME_OPTIONS_RESOLUTION_OTHER :eile + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Méid an chomhéadain STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Roghnaigh méid na heiliminte comhéadain a úsáidfear @@ -1868,6 +1869,7 @@ STR_FACE_TIE :Carbhat: STR_FACE_EARRING :Fáinne cluaise: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Athraigh carbhat nó fáinne cluaise + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Ilimreoirí STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ainm imreora: @@ -1926,10 +1928,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Taispeá STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Socraigh pasfhocal STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Cosain do chluiche le pasfhocal más mian leat nach mbeidh rochtain phoiblí air -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Fógartha -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Roghnaigh idir cluiche fógartha (idirlín) agus cluiche neamhfhógartha (Líonra Achair Logánta, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Níl -STR_NETWORK_START_SERVER_ADVERTISED :Tá STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} {P ch ch ch gc c}lia{P "" "" "" "" i}nt STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Cliaint uasta: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Roghnaigh uaslíon na gcliant. Ní gá gach áit a líonadh @@ -1944,46 +1942,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Beidh a STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Iontráil ainm don chluiche líonra -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Teanga ar bith -STR_NETWORK_LANG_ENGLISH :Béarla -STR_NETWORK_LANG_GERMAN :Gearmáinis -STR_NETWORK_LANG_FRENCH :Fraincis -STR_NETWORK_LANG_BRAZILIAN :Brasaílis -STR_NETWORK_LANG_BULGARIAN :Bulgáiris -STR_NETWORK_LANG_CHINESE :Sínis -STR_NETWORK_LANG_CZECH :Seicis -STR_NETWORK_LANG_DANISH :Danmhairgis -STR_NETWORK_LANG_DUTCH :Ollainnis -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fionlainnis -STR_NETWORK_LANG_HUNGARIAN :Ungáiris -STR_NETWORK_LANG_ICELANDIC :Íoslainnis -STR_NETWORK_LANG_ITALIAN :Iodáilis -STR_NETWORK_LANG_JAPANESE :Seapáinis -STR_NETWORK_LANG_KOREAN :Cóiréis -STR_NETWORK_LANG_LITHUANIAN :Liotuáinis -STR_NETWORK_LANG_NORWEGIAN :Ioruais -STR_NETWORK_LANG_POLISH :Polainnis -STR_NETWORK_LANG_PORTUGUESE :Portaingéilis -STR_NETWORK_LANG_ROMANIAN :Rómáinis -STR_NETWORK_LANG_RUSSIAN :Rúisis -STR_NETWORK_LANG_SLOVAK :Slóvaicis -STR_NETWORK_LANG_SLOVENIAN :Slóivéinis -STR_NETWORK_LANG_SPANISH :Spáinnis -STR_NETWORK_LANG_SWEDISH :Sualainnis -STR_NETWORK_LANG_TURKISH :Tuircis -STR_NETWORK_LANG_UKRAINIAN :Úcráinis -STR_NETWORK_LANG_AFRIKAANS :Afracáinis -STR_NETWORK_LANG_CROATIAN :Cróitis -STR_NETWORK_LANG_CATALAN :Catalóinis -STR_NETWORK_LANG_ESTONIAN :Eastóinis -STR_NETWORK_LANG_GALICIAN :Gailísis -STR_NETWORK_LANG_GREEK :Gréigis -STR_NETWORK_LANG_LATVIAN :Laitvis -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Forsheomra cluichí ilimreoirí @@ -2034,15 +1992,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Tá an c # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liosta na gcliant -STR_NETWORK_COMPANY_LIST_SPECTATE :Féach air -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Cuideachta nua # Network client list -STR_NETWORK_CLIENTLIST_KICK :Ciceáil -STR_NETWORK_CLIENTLIST_BAN :Toirmisc -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Labhair le cách -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Labhair le cuideachta -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Teacht. phríobháideach + + STR_NETWORK_SERVER :Freastalaí STR_NETWORK_CLIENT :Cliant diff --git a/src/lang/italian.txt b/src/lang/italian.txt index d7f5faec48..1415418865 100644 --- a/src/lang/italian.txt +++ b/src/lang/italian.txt @@ -1008,6 +1008,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Accelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Seleziona questa opzione per consentire a OpenTTD di utilizzare l'accelerazione hardware. Eventuali cambiamenti avranno effetto solo dopo un riavvio del gioco STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Le nuove impostazioni avranno effetto solo dopo un riavvio del gioco + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Dimensione interfaccia STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Seleziona la dimensione deglie elementi dell'interfaccia grafica @@ -2004,6 +2005,7 @@ STR_FACE_TIE :Cravatta: STR_FACE_EARRING :Orecchino: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambia la cravatta o l'orecchino + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multigiocatore STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nome giocatore: @@ -2066,10 +2068,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Il nome STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Imposta password STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protegge la partita con una password in modo che non sia accessibile pubblicamente -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Pubblico -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Sceglie fra partita pubblica (su Internet) o privata (su rete locale, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Sì STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} client STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Limite client: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Imposta il numero massimo di client. Non tutti i posti dovranno essere occupati @@ -2084,46 +2082,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Fa saper STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Inserire il nome della partita -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Qualsiasi -STR_NETWORK_LANG_ENGLISH :Inglese -STR_NETWORK_LANG_GERMAN :Tedesco -STR_NETWORK_LANG_FRENCH :Francese -STR_NETWORK_LANG_BRAZILIAN :Brasiliano -STR_NETWORK_LANG_BULGARIAN :Bùlgaro -STR_NETWORK_LANG_CHINESE :Cinese -STR_NETWORK_LANG_CZECH :Ceco -STR_NETWORK_LANG_DANISH :Danese -STR_NETWORK_LANG_DUTCH :Olandese -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finlandese -STR_NETWORK_LANG_HUNGARIAN :Ungherese -STR_NETWORK_LANG_ICELANDIC :Islandese -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Giapponese -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Norvegese -STR_NETWORK_LANG_POLISH :Polacco -STR_NETWORK_LANG_PORTUGUESE :Portoghese -STR_NETWORK_LANG_ROMANIAN :Rumeno -STR_NETWORK_LANG_RUSSIAN :Russo -STR_NETWORK_LANG_SLOVAK :Slovacco -STR_NETWORK_LANG_SLOVENIAN :Sloveno -STR_NETWORK_LANG_SPANISH :Spagnolo -STR_NETWORK_LANG_SWEDISH :Svedese -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraino -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croato -STR_NETWORK_LANG_CATALAN :Catalano -STR_NETWORK_LANG_ESTONIAN :Estone -STR_NETWORK_LANG_GALICIAN :Galiziano -STR_NETWORK_LANG_GREEK :Greco -STR_NETWORK_LANG_LATVIAN :Lèttone -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Stanza principale partita multigiocatore @@ -2171,19 +2129,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disconne STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server protetto. Inserire la password STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Compagnia protetta. Inserire la password -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Elenco dei client # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Elenco dei client -STR_NETWORK_COMPANY_LIST_SPECTATE :Diventa spettatore -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nuova compagnia # Network client list -STR_NETWORK_CLIENTLIST_KICK :Espelli -STR_NETWORK_CLIENTLIST_BAN :Bandisci -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Parla a tutti -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Parla alla compagnia -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Messaggio privato + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client diff --git a/src/lang/japanese.txt b/src/lang/japanese.txt index 5787200ce4..18fc5162f0 100644 --- a/src/lang/japanese.txt +++ b/src/lang/japanese.txt @@ -32,7 +32,7 @@ STR_CARGO_PLURAL_OIL :石油 STR_CARGO_PLURAL_LIVESTOCK :家畜 STR_CARGO_PLURAL_GOODS :商品 STR_CARGO_PLURAL_GRAIN :穀物 -STR_CARGO_PLURAL_WOOD :木材 +STR_CARGO_PLURAL_WOOD :原木 STR_CARGO_PLURAL_IRON_ORE :鉄鉱石 STR_CARGO_PLURAL_STEEL :鋼鉄 STR_CARGO_PLURAL_VALUABLES :貴重品 @@ -66,7 +66,7 @@ STR_CARGO_SINGULAR_OIL :石油 STR_CARGO_SINGULAR_LIVESTOCK :家畜 STR_CARGO_SINGULAR_GOODS :商品 STR_CARGO_SINGULAR_GRAIN :穀物 -STR_CARGO_SINGULAR_WOOD :木材 +STR_CARGO_SINGULAR_WOOD :原木 STR_CARGO_SINGULAR_IRON_ORE :鉄鉱石 STR_CARGO_SINGULAR_STEEL :鋼鉄 STR_CARGO_SINGULAR_VALUABLES :貴重品 @@ -100,7 +100,7 @@ STR_QUANTITY_OIL :石油{VOLUME_L STR_QUANTITY_LIVESTOCK :家畜{COMMA}頭 STR_QUANTITY_GOODS :商品{COMMA}箱 STR_QUANTITY_GRAIN :穀物{WEIGHT_LONG} -STR_QUANTITY_WOOD :木材{WEIGHT_LONG} +STR_QUANTITY_WOOD :原木{WEIGHT_LONG} STR_QUANTITY_IRON_ORE :鉄鉱石{WEIGHT_LONG} STR_QUANTITY_STEEL :鋼鉄{WEIGHT_LONG} STR_QUANTITY_VALUABLES :貴重品{COMMA}袋 @@ -187,6 +187,7 @@ STR_COLOUR_ORANGE :橙 STR_COLOUR_BROWN :茶 STR_COLOUR_GREY :灰 STR_COLOUR_WHITE :白 +STR_COLOUR_RANDOM :ランダム # Units used in OpenTTD STR_UNITS_VELOCITY_IMPERIAL :{COMMA}mph @@ -312,6 +313,7 @@ STR_SORT_BY_RATING :レーティン STR_SORT_BY_NUM_VEHICLES :車両数 STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :昨年の総利益 STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :今年の総利益 +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :前年度の平均利益 # Group by options for vehicle list STR_GROUP_BY_SHARED_ORDERS :共有注文 @@ -360,6 +362,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}地形 STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}町を生成します STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}産業を生成します STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}道路を建設します +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}路面電車建設 STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}木を植えます。Shiftキーを押しながら決定すると費用を見積もります STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}標識を設置します STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}オブジェクトを設置します。Shiftを押しながら決定すると費用を見積もります @@ -648,6 +651,7 @@ STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLA STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ +STR_MUSIC_TITLE_NOMUSIC :{TINY_FONT}{DKGREEN}音楽がありません STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}トラック STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}タイトル @@ -673,7 +677,9 @@ STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTB STR_PLAYLIST_TRACK_INDEX :{TINY_FONT}{BLACK}楽曲索引 STR_PLAYLIST_PROGRAM :{TINY_FONT}{BLACK}プレイリスト - '{STRING}' STR_PLAYLIST_CLEAR :{TINY_FONT}{BLACK}消去 +STR_PLAYLIST_CHANGE_SET :{BLACK}セットの変更 STR_PLAYLIST_TOOLTIP_CLEAR_CURRENT_PROGRAM_CUSTOM1 :{BLACK}選択したプレイリストの内容を消去します。(カスタム1/2 のみ) +STR_PLAYLIST_TOOLTIP_CHANGE_SET :{BLACK}音楽の選択を別のインストール済みセットに変更する STR_PLAYLIST_TOOLTIP_CLICK_TO_ADD_TRACK :{BLACK}クリックすると、その曲を選択したプレイリストに追加します。(カスタム1/2 のみ) STR_PLAYLIST_TOOLTIP_CLICK_TO_REMOVE_TRACK :{BLACK}クリックすると、その曲を選択したプレイリストから削除します。(カスタム1/2 のみ) @@ -733,6 +739,7 @@ STR_SMALLMAP_LEGENDA_DOCK :{TINY_FONT}{BLA STR_SMALLMAP_LEGENDA_ROUGH_LAND :{TINY_FONT}{BLACK}荒地 STR_SMALLMAP_LEGENDA_GRASS_LAND :{TINY_FONT}{BLACK}草地 STR_SMALLMAP_LEGENDA_BARE_LAND :{TINY_FONT}{BLACK}露地 +STR_SMALLMAP_LEGENDA_RAINFOREST :{TINY_FONT} {BLACK}熱帯雨林 STR_SMALLMAP_LEGENDA_FIELDS :{TINY_FONT}{BLACK}耕作地 STR_SMALLMAP_LEGENDA_TREES :{TINY_FONT}{BLACK}樹林 STR_SMALLMAP_LEGENDA_ROCKS :{TINY_FONT}{BLACK}岩石 @@ -764,6 +771,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}全貨 STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}最新のメッセージ/ニュースを表示します STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * ポーズ中 * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * 一時停止中 (リンクグラフの更新を待っています) * * STR_STATUSBAR_AUTOSAVE :{RED}オートセーブ STR_STATUSBAR_SAVING_GAME :{RED}* * ゲームセーブ中 * * @@ -923,8 +931,12 @@ STR_GAME_OPTIONS_CURRENCY_ZAR :南アフリカ STR_GAME_OPTIONS_CURRENCY_CUSTOM :カスタム… STR_GAME_OPTIONS_CURRENCY_GEL :グルジア ラリー(GEL) STR_GAME_OPTIONS_CURRENCY_IRR :イラン リアル(IRR) +STR_GAME_OPTIONS_CURRENCY_RUB :新ロシアルーブル(RUB) STR_GAME_OPTIONS_CURRENCY_MXN :メキシコペソ(MXN) STR_GAME_OPTIONS_CURRENCY_NTD :新台湾ドル(ntd) +STR_GAME_OPTIONS_CURRENCY_CNY :人民元(CNY) +STR_GAME_OPTIONS_CURRENCY_HKD :香港ドル(HKD) +STR_GAME_OPTIONS_CURRENCY_INR :インドルピー(INR) STR_GAME_OPTIONS_CURRENCY_IDR :インドネシアルピア(IDR) ############ end of currency region @@ -982,6 +994,8 @@ STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}ハードウェアアクセラレーション +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK} 垂直同期 + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}インターフェイスのサイズ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}インターフェイス上の単位サイズを指定します @@ -991,15 +1005,19 @@ STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :2倍 STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :4倍 STR_GAME_OPTIONS_FONT_ZOOM :{BLACK}フォントサイズ +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}使用するインターフェースのフォントサイズを選択します STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_AUTO :(自動検出) STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :ノーマル +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :ダブルサイズ +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :4倍 STR_GAME_OPTIONS_GRAPHICS :{BLACK}グラフィクス STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}画面リフレッシュレート STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :{BLACK}使用する画面のリフレッシュレートを選択します STR_GAME_OPTIONS_REFRESH_RATE_OTHER :その他 +STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}60Hzを超えるリフレッシュレートはパフォーマンスに影響を与える可能性があります。 STR_GAME_OPTIONS_BASE_GRF :{BLACK}基本グラフィックセット STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}使用するグラフィックセットを選択します @@ -1095,6 +1113,8 @@ STR_TERRAIN_TYPE_FLAT :平地 STR_TERRAIN_TYPE_HILLY :丘陵地 STR_TERRAIN_TYPE_MOUNTAINOUS :山岳地 STR_TERRAIN_TYPE_ALPINIST :山脈地帯 +STR_TERRAIN_TYPE_CUSTOM :カスタム高度 +STR_TERRAIN_TYPE_CUSTOM_VALUE :カスタム高度 ({NUM}) STR_CITY_APPROVAL_PERMISSIVE :寛大 STR_CITY_APPROVAL_TOLERANT :寛容 @@ -1115,6 +1135,7 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :ゲーム設定 STR_CONFIG_SETTING_TYPE_GAME_INGAME :ゲーム設定(現在のゲームにのみ影響) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :会社設定(新規ゲームにのみ影響) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :会社設定(現在の会社のみに影響) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}注意! STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}カテゴリ: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}種類: @@ -1176,11 +1197,14 @@ STR_CONFIG_SETTING_DISASTERS_HELPTEXT :設定を有効 STR_CONFIG_SETTING_CITY_APPROVAL :地域の再編に対する町の姿勢: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :会社が街域で引き起こした騒音(主に空港)や環境破壊がどの程度、街での評価や同じ地域での更なる建設行為に影響するかを設定します +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :マップ高さ限界: {STRING} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_AUTO :(自動) STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}マップの最高高さをこの値には設定出来ません。少なくとも1箇所以上この値より高い山があります。 STR_CONFIG_SETTING_AUTOSLOPE :建物/路線の自動地形追従: {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :撤去を行わないで建物や路線がある土地の地形を変更することを可能にします。建物/路線は変更された地形に自動で追従します。 STR_CONFIG_SETTING_CATCHMENT :現実的な受入範囲: {STRING} STR_CONFIG_SETTING_CATCHMENT_HELPTEXT :駅や空港の種類の違いによって受入範囲が変動するようになります +STR_CONFIG_SETTING_SERVE_NEUTRAL_INDUSTRIES_HELPTEXT :有効にすると、駅が接続されている産業(石油掘削装置など)にも、近くに建設された会社が所有している駅がサービスを提供する場合があります。無効になっている場合、これらの産業は、接続されているステーションによってのみサービスを受けることができます。近くの会社のステーションはそれらにサービスを提供できず、接続されたステーションは業界以外のものにサービスを提供しません STR_CONFIG_SETTING_EXTRADYNAMITE :街有道路・橋・トンネルの撤去容認: {STRING} STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :街有の交通インフラや建物の撤去をより容易にします STR_CONFIG_SETTING_TRAIN_LENGTH :列車の最大長: {STRING} @@ -1318,6 +1342,8 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :石油精製所 STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :石油精製所はマップの外周付近にのみ建設されます。つまり、外周が海のマップでは海岸沿いに建設されるということです STR_CONFIG_SETTING_SNOWLINE_HEIGHT :雪線の位置: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :亜寒帯気候での雪線の高さを設定します。雪は産業と街の成長に影響があります +STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :亜寒帯の風景のおおよその雪の量を制御します。雪はまた、産業の生成と町の成長要件にも影響を及ぼします。マップの生成中にのみ使用されます。海抜のすぐ上の土地は常に雪がありません +STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :地形の起伏: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesisのみ) 地形の起伏度を設定します。なだらかな地形では丘陵の数は減り、裾野が長くなります。起伏が多い地形では丘陵が多くなりますが、似たり寄ったりな地形の繰り返しに見えることがあります STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :特になだらか @@ -1356,6 +1382,7 @@ STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :青紫 STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :スクロール時の動き STR_CONFIG_SETTING_SCROLLMODE_DEFAULT :右クリックでビューポートを移動し、マウスの位置をロックします STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :右クリックで地図を移動し、マウスの位置をロックします +STR_CONFIG_SETTING_SCROLLMODE_RMB :マップを右マウスボタンで動かす STR_CONFIG_SETTING_SMOOTH_SCROLLING :画面のスムーズスクロール: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :ミニマップでの移動や「現在位置に移動」などのコマンドを使用した際にメイン画面がどのように移動するかを設定します。有効にした場合はスムーズにスクロールして移動します。無効の場合は目的地に直接ジャンプします STR_CONFIG_SETTING_MEASURE_TOOLTIP :測定ツールチップ表示: {STRING} @@ -1426,7 +1453,9 @@ STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS :建設ツール STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :橋やトンネルなどを建設した後もツールバーを開いたままにします STR_CONFIG_SETTING_EXPENSES_LAYOUT :財政ウィンドウのグループ分け: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :財政ウィンドウのレイアウトを収入部門・支出部門でグループ分けするかどうかを設定します +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_HELPTEXT :早送りが有効になっている場合のゲームの進行速度を制限します。0 =制限なし(コンピューターが許す限り高速)。100%未満の値は、ゲームの速度を低下させます。上限はコンピュータの仕様によって異なり、ゲームによって異なる場合があります。 STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_VAL :{NUM}%通常のゲーム速度 +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :制限なし(コンピューターが許す限り高速) STR_CONFIG_SETTING_SOUND_TICKER :ニュース表示: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :ステータスバーにニュースが流れたとき効果音を鳴らすかどうかを設定します @@ -1475,6 +1504,8 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :マルチプレ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :マルチプレイヤーゲームでもAIのライバル企業が登場するかを設定します STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :命令コード処理上限: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :AIやゲームスクリプトが一つの「詰め込み指令」を処理する際に、一度に演算できる命令コード数を設定します。一般に値を小さくした場合、ゲームへの負荷が軽減されます +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :スクリプトあたりの最大メモリ使用量:{STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :最大信頼度を点検要件化: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :次の点検が必要と判断される条件を設定します。無効の場合は、前の点検から指定の期間が経過した際に点検が必要と判断されます。有効にすると、輸送機器の最大信頼度が指定の値より落ち込んだ場合に次の点検が必要と判断されます @@ -1534,7 +1565,9 @@ STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :カラー新聞 STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :新聞がカラー版になる境目の年を設定します STR_CONFIG_SETTING_STARTING_YEAR :開始年: {STRING} STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT :スコアリングの目的でゲームが終了する年。 今年の終わりには、会社のスコアが記録され、ハイスコア画面が表示されますが、プレーヤーはその後もプレイを続けることができます。{}これが開始年より前の場合、ハイスコア画面は表示されません。 +STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM} STR_CONFIG_SETTING_ECONOMY_TYPE :エコノミータイプ:{STRING} +STR_CONFIG_SETTING_ECONOMY_TYPE_ORIGINAL :オリジナル STR_CONFIG_SETTING_ECONOMY_TYPE_SMOOTH :なだらか STR_CONFIG_SETTING_ALLOW_SHARES :他社株の取引許容: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :有効にすると、ライバル会社の株式を取引できるようになります。この設定を有効にしても、目的の社が設立から丸5年経過していない場合は取引できません @@ -1585,6 +1618,7 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :町の総人口 STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :樹木の自然成長: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :ゲーム中、ランダムに生えてくる樹種を設定します。設定によっては樹木の生育に依存する産業に悪影響が生じる可能性があります(「不可」にした場合、亜熱帯地域の伐採所を機能させ続けるためには手動で植林し続ける必要があります) STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :成長するが、熱帯雨林にのみ広がる +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :成長し、どこにでも広がる STR_CONFIG_SETTING_TOOLBAR_POS :メインツールバーの位置: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :画面上のメインツールバーの位置を決めます @@ -1602,6 +1636,7 @@ STR_CONFIG_SETTING_ZOOM_MIN :最大ズーム STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :ズームインの最大倍率を設定します。倍率を高くすればするほどメモリー使用量が増えます STR_CONFIG_SETTING_ZOOM_MAX :最大ズームアウトレベル:{STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :ズームアウトの最大倍率を設定します。ズームアウトの倍率が大きいと、処理遅延が発生する可能性があります +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN :使用する最高解像度のスプライト:{STRING} STR_CONFIG_SETTING_SPRITE_ZOOM_MIN_HELPTEXT :スプライトに使用する最大解像度を制限します。 スプライトの解像度を制限すると、使用可能な場合でも高解像度のグラフィックを使用できなくなります。 これにより、高解像度のグラフィックを使用する場合と使用しない場合のGRFファイルを組み合わせて使用する場合に、ゲームの外観を統一することができます。 STR_CONFIG_SETTING_ZOOM_LVL_MIN :4倍 STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2倍 @@ -1745,6 +1780,7 @@ STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}メモ STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}スプライトキャッシュ中、{BYTES}の割り当てに失敗しました。スプライトキャッシュは{BYTES}に減ったため、OpenTTDの処理速度が低下する恐れがあります。必要メモリ量を減らすには32bitグラフィックを無効にするか、最大ズームイン・ズームアウトのレベルを下げてください # Video initalization errors +STR_VIDEO_DRIVER_ERROR :{WHITE}ビデオ設定にエラーがあります... # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} @@ -1909,6 +1945,7 @@ STR_FACE_TIE :ネクタイ: STR_FACE_EARRING :イヤリング: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}ネクタイ/イヤリングを変更します + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}マルチプレイヤーゲーム STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}プレイヤー名: @@ -1952,6 +1989,7 @@ 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}サーバーを追加 @@ -1970,10 +2008,7 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}ゲー STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}パスワードを設定 STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}ゲームをパスワードで保護することができます。一般から公然とアクセスされたくない場合等に設定します -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}ゲーム公示 -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}ゲームを公示(インターネット)するか、非公示(LAN)にするかを選びます -STR_NETWORK_START_SERVER_UNADVERTISED :非公示 -STR_NETWORK_START_SERVER_ADVERTISED :公示 +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}可視性 STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}接続者数: {NUM} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}最大接続数: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}接続できるクライアントの最大数を指定します。必ずしも全スロットを埋める必要はありません @@ -1988,46 +2023,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}この STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}ネットワークゲーム名を入力 -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :言語未指定 -STR_NETWORK_LANG_ENGLISH :英語 -STR_NETWORK_LANG_GERMAN :ドイツ語 -STR_NETWORK_LANG_FRENCH :フランス語 -STR_NETWORK_LANG_BRAZILIAN :ポルトガル語(ブラジル) -STR_NETWORK_LANG_BULGARIAN :ブルガリア語 -STR_NETWORK_LANG_CHINESE :中国語 -STR_NETWORK_LANG_CZECH :チェコ語 -STR_NETWORK_LANG_DANISH :デンマーク語 -STR_NETWORK_LANG_DUTCH :オランダ語 -STR_NETWORK_LANG_ESPERANTO :エスペラント語 -STR_NETWORK_LANG_FINNISH :フィンランド語 -STR_NETWORK_LANG_HUNGARIAN :ハンガリー語 -STR_NETWORK_LANG_ICELANDIC :アイスランド語 -STR_NETWORK_LANG_ITALIAN :イタリア語 -STR_NETWORK_LANG_JAPANESE :日本語 -STR_NETWORK_LANG_KOREAN :韓国語 -STR_NETWORK_LANG_LITHUANIAN :リトアニア語 -STR_NETWORK_LANG_NORWEGIAN :ノルウェイ語 -STR_NETWORK_LANG_POLISH :ポーランド語 -STR_NETWORK_LANG_PORTUGUESE :ポルトガル語 -STR_NETWORK_LANG_ROMANIAN :ルーマニア語 -STR_NETWORK_LANG_RUSSIAN :ロシア語 -STR_NETWORK_LANG_SLOVAK :スロバキア語 -STR_NETWORK_LANG_SLOVENIAN :スロベニア語 -STR_NETWORK_LANG_SPANISH :スペイン語 -STR_NETWORK_LANG_SWEDISH :スウェーデン語 -STR_NETWORK_LANG_TURKISH :トルコ語 -STR_NETWORK_LANG_UKRAINIAN :ウクライナ語 -STR_NETWORK_LANG_AFRIKAANS :アフリカーンス語 -STR_NETWORK_LANG_CROATIAN :クロアチア語 -STR_NETWORK_LANG_CATALAN :カタロニア語 -STR_NETWORK_LANG_ESTONIAN :エストニア語 -STR_NETWORK_LANG_GALICIAN :ガリシア語 -STR_NETWORK_LANG_GREEK :ギリシア語 -STR_NETWORK_LANG_LATVIAN :ラトビア語 -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}マルチプレイヤーゲーム ロビー @@ -2078,15 +2073,15 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}この # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :クライアントリスト -STR_NETWORK_COMPANY_LIST_SPECTATE :観覧モード -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :新会社 # Network client list -STR_NETWORK_CLIENTLIST_KICK :追放 -STR_NETWORK_CLIENTLIST_BAN :参入禁止 -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :全員へ発言 -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :チームへ発言 -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :個人的なメッセージ +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}他の人があなたのサーバーを公開リストで見ることができるかどうか +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}すべての観客にメッセージを送る +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}ゲームのホストです + + +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}プレーヤー「{STRING}」を追放してもよろしいですか? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}会社 '{COMPANY}'のパスワードをリセットしてもよろしいですか? STR_NETWORK_SERVER :サーバー STR_NETWORK_CLIENT :クライアント @@ -2136,12 +2131,14 @@ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}不正 STR_NETWORK_ERROR_SERVER_FULL :{WHITE}サーバが満員です STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}サーバー側であなたの参加が禁止されています STR_NETWORK_ERROR_KICKED :{WHITE}ゲームから追放されました +STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}理由:{STRING} STR_NETWORK_ERROR_CHEATER :{WHITE}このサーバーではチート行為は許可されていません STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}サーバーに送ったコマンド数が過剰です STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}パスワード入力時間切れです STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}サーバーとの接続を維持できる十分な処理能力がありません STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}マップのダウンロード時間が規定を超過しました STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}タイムアウトによりサーバーへの接続を確立できません +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}プレイヤー名が無効です ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :一般エラー @@ -2177,6 +2174,7 @@ STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :ゲームはま STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :ゲームはまだポーズされています。({STRING}、{STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :ゲームはまだポーズされています。 ({STRING}、{STRING}、{STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :ゲームはまだポーズされています。 ({STRING}、{STRING}、{STRING}、{STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :ゲームはまだポーズされています。 ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :ゲームのポーズが解除されました。({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :プレーヤー数不足 STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :クライアントに接続中 @@ -2194,6 +2192,7 @@ STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} は名前を {STRING} に変更しました STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}サーバがセッションを終了しました STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}このサーバーは再起動中です…{}しばらくお待ちください… +STR_NETWORK_MESSAGE_KICKED :*** {STRING}がキックされました。理由: ({STRING}) # Content downloading window STR_CONTENT_TITLE :{WHITE}コンテンツをダウンロード中 @@ -2269,6 +2268,8 @@ STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}はい STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}いいえ、OpenTTDを終了します STR_MISSING_GRAPHICS_ERROR_TITLE :{WHITE}ダウンロードに失敗しました +STR_MISSING_GRAPHICS_ERROR :{BLACK}グラフィックのダウンロードに失敗しました。{}手動でダウンロードしてください。 +STR_MISSING_GRAPHICS_ERROR_QUIT :{BLACK}OpenTTDをやめる # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}透過表示設定 @@ -2288,6 +2289,7 @@ STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}貨物 STR_LINKGRAPH_LEGEND_ALL :{BLACK}全て STR_LINKGRAPH_LEGEND_NONE :{BLACK}なし STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}表示する会社を選択 +STR_LINKGRAPH_LEGEND_COMPANY_TOOLTIP :{BLACK}{STRING}{}{COMPANY} # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}未使用(運送過多) @@ -2414,7 +2416,9 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}道路 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}軌道用トンネルを建設します。Shiftを押しながら決定すると費用の見積が出ます STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}道路の建設/撤去を切り替えます STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}軌道の建設/撤去を切り替えます +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}道路の種類を変更/アップグレードします.Shiftは、コスト見積もりの作成/表示を切り替えます +STR_ROAD_NAME_ROAD :道路 STR_ROAD_NAME_TRAM :トラムウェイ # Road depot construction window @@ -2503,7 +2507,9 @@ STR_TREES_RANDOM_TYPE :{BLACK}ラン STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}ランダムな樹類で植林します。Shift+クリックで費用を見積もります STR_TREES_RANDOM_TREES_BUTTON :{BLACK}ランダムに広域植林 STR_TREES_RANDOM_TREES_TOOLTIP :{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_TOOLTIP :{BLACK}風景の上をドラッグして、大きな森を植えます。 # Land generation window (SE) @@ -2563,6 +2569,7 @@ STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}費用: STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}調査/探鉱 STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}建設 STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}出資 +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES_QUERY :{YELLOW}すべての産業を削除してもよろしいですか? # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}産業:{STRING}に関わる産業チェーン @@ -2709,22 +2716,39 @@ STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD # Framerate display window STR_FRAMERATE_CAPTION :{WHITE}フレームレート STR_FRAMERATE_RATE_BLITTER :{BLACK}グラフィックフレームレート:{STRING} +STR_FRAMERATE_SPEED_FACTOR :{BLACK}現在のゲーム速度:{DECIMAL} x +STR_FRAMERATE_CURRENT :{WHITE}現在 +STR_FRAMERATE_AVERAGE :{WHITE}平均 +STR_FRAMERATE_MEMORYUSE :{WHITE}メモリ STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms STR_FRAMERATE_MS_WARN :{YELLOW} {DECIMAL} ms STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} フレーム/秒 STR_FRAMERATE_FPS_WARN :{YELLOW} {DECIMAL}フレーム/秒 +STR_FRAMERATE_FPS_BAD :{RED} {DECIMAL}FPS STR_FRAMERATE_BYTES_GOOD :{LTBLUE}{BYTES} +STR_FRAMERATE_BYTES_WARN :{YELLOW} {BYTES} ############ Leave those lines in this order!! STR_FRAMERATE_GAMELOOP :{BLACK}ゲームループの合計: STR_FRAMERATE_GL_ECONOMY :{BLACK}貨物の取り扱い: +STR_FRAMERATE_GL_TRAINS :{BLACK} 鉄道車両のティック: +STR_FRAMERATE_GL_ROADVEHS :{BLACK} 自動車ティック: +STR_FRAMERATE_GL_AIRCRAFT :{BLACK}航空機ティック: +STR_FRAMERATE_DRAWING :{BLACK}グラフィックレンダリング: STR_FRAMERATE_VIDEO :{BLACK}ビデオ出力: +STR_FRAMERATE_SOUND :{BLACK}サウンドミキサー: ############ End of leave-in-this-order ############ Leave those lines in this order!! STR_FRAMETIME_CAPTION_GAMELOOP :ゲームループ STR_FRAMETIME_CAPTION_GL_ECONOMY :貨物の取り扱い STR_FRAMETIME_CAPTION_GL_TRAINS :切符 +STR_FRAMETIME_CAPTION_GL_SHIPS :船のティック +STR_FRAMETIME_CAPTION_GL_AIRCRAFT :航空機ティック +STR_FRAMETIME_CAPTION_GL_LANDSCAPE :ワールドティック STR_FRAMETIME_CAPTION_GL_LINKGRAPH :リンクグラフの遅延 +STR_FRAMETIME_CAPTION_DRAWING :グラフィックレンダリング STR_FRAMETIME_CAPTION_DRAWING_VIEWPORTS :ワールドビューポートレンダリング +STR_FRAMETIME_CAPTION_VIDEO :ビデオ出力 +STR_FRAMETIME_CAPTION_AI :AI {NUM} {STRING} ############ End of leave-in-this-order @@ -2750,8 +2774,10 @@ STR_SAVELOAD_DETAIL_CAPTION :{BLACK}ゲー STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}― 情報なし ― STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} +STR_SAVELOAD_FILTER_TITLE :{BLACK}フィルター: STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}ファイルを上書きする STR_SAVELOAD_OVERWRITE_WARNING :{YELLOW}既存のファイルを上書きしてもよろしいですか? +STR_SAVELOAD_PARENT_DIRECTORY :{STRING} (Parent directory) STR_SAVELOAD_OSKTITLE :{BLACK}保存名を入力 @@ -2763,6 +2789,14 @@ STR_MAPGEN_BY :{BLACK}× STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}街数: STR_MAPGEN_DATE :{BLACK}日付: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}産業数: +STR_MAPGEN_HEIGHTMAP_HEIGHT :{BLACK}最高峰: +STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN :{BLACK}マップの最高峰の最大の高さを1減らします。 +STR_MAPGEN_SNOW_COVERAGE :{BLACK}降雪量: +STR_MAPGEN_SNOW_COVERAGE_DOWN :{BLACK}積雪量を10%減らします +STR_MAPGEN_SNOW_COVERAGE_TEXT :{BLACK} {NUM}% +STR_MAPGEN_DESERT_COVERAGE :{BLACK}砂漠の範囲: +STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}砂漠の割合を10%増やします +STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}砂漠の範囲を10%減らします STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_LAND_GENERATOR :{BLACK}地形作成: STR_MAPGEN_TERRAIN_TYPE :{BLACK}地形種類: @@ -2789,6 +2823,9 @@ STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}ハイ STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}サイズ: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} × {NUM} +STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT :{WHITE}ターゲットの最高の高さ +STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}積雪量(%) +STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}砂漠領域(%) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}開始年の変更 # SE Map generation @@ -2863,6 +2900,7 @@ STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: STR_NEWGRF_SETTINGS_PALETTE :{BLACK}パレット: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :デフォルト(D) STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :デフォルト(D)/ 32 bpp +STR_NEWGRF_SETTINGS_PALETTE_LEGACY :レガシー(W) STR_NEWGRF_SETTINGS_PALETTE_LEGACY_32BPP :レガシー(W)/ 32 bpp STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}設定: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PARAMETER_NONE :なし @@ -3043,6 +3081,7 @@ STR_TOWN_VIEW_RENAME_TOWN_BUTTON :街名を変更 # Town local authority window STR_LOCAL_AUTHORITY_CAPTION :{WHITE}{TOWN} 地方自治体 STR_LOCAL_AUTHORITY_ZONE :ゾーン +STR_LOCAL_AUTHORITY_ZONE_TOOLTIP :{BLACK}地方自治体の境界を見る STR_LOCAL_AUTHORITY_COMPANY_RATINGS :{BLACK}社の評判: STR_LOCAL_AUTHORITY_COMPANY_RATING :{YELLOW}{COMPANY} {COMPANY_NUM}: {ORANGE}{STRING} STR_LOCAL_AUTHORITY_ACTIONS_TITLE :{BLACK}可能な活動: @@ -3071,6 +3110,7 @@ STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}買収 # Goal window STR_GOALS_CAPTION :{WHITE}{COMPANY} 目標 STR_GOALS_SPECTATOR_CAPTION :{WHITE}大目標 +STR_GOALS_GLOBAL_BUTTON_HELPTEXT :{BLACK}グローバルな目標を表示する STR_GOALS_COMPANY_BUTTON :{BLACK}会社 STR_GOALS_COMPANY_BUTTON_HELPTEXT :{BLACK}会社の目標を見る STR_GOALS_TEXT :{ORANGE}{STRING} @@ -3273,6 +3313,7 @@ STR_COMPANY_VIEW_RELOCATE_HQ :{BLACK}本社 STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS :{BLACK}本社ビルを移転します(費用は社の総資産の1%になります)。Shift+クリックで費用を見積もります STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON :{BLACK}詳細 STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP :{BLACK}インフラ設備の詳細な個数・タイル数を表示します +STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP :{BLACK}この会社にお金を渡す STR_COMPANY_VIEW_NEW_FACE_BUTTON :{BLACK}顔の変更 STR_COMPANY_VIEW_NEW_FACE_TOOLTIP :{BLACK}社長の顔を変更します @@ -3290,6 +3331,7 @@ STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}この STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :会社名 STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :社長名 +STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION :寄付したい金額を入力してください STR_BUY_COMPANY_MESSAGE :{WHITE}現在、当{COMPANY}は業績悪化に伴い、債務の肩代わりを条件に社の全資産をお譲り致そうと考えております。{}{}債務{CURRENCY_LONG}を一括代済し、この会社を吸収合併しますか? @@ -3298,6 +3340,7 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION :{WHITE}{COMPANY STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT :{GOLD}線路長: STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS :{WHITE}信号 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT :{GOLD}道路長(含軌道): +STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT :{GOLD}路面電車軌道: STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT :{GOLD}水運長: STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS :{WHITE}運河 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT :{GOLD}停留施設数: @@ -3308,8 +3351,11 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENC # Industry directory STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}産業 STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- なし - +STR_INDUSTRY_DIRECTORY_ITEM_INFO :{BLACK}{CARGO_LONG}{STRING}{YELLOW} ({COMMA}% 輸送済み){BLACK} STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}産業の名前です - 名前をクリックするとこの産業拠点の場所にメイン画面を移動します。Ctrl+クリックでこの産業拠点の場所を新たなビューポートに表示します +STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER :{BLACK}受け取った貨物: {SILVER}{STRING} +STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER :{BLACK}生産された貨物:{SILVER} {STRING} STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES :すべての貨物タイプ STR_INDUSTRY_DIRECTORY_FILTER_NONE :なし @@ -3322,6 +3368,7 @@ STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}生産 STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}この産業拠点は間もなく閉鎖されます! STR_INDUSTRY_VIEW_REQUIRES_N_CARGO :{BLACK}必要条件:{YELLOW} {STRING} {STRING} +STR_INDUSTRY_VIEW_CARGO_LIST_EXTENSION :、{STRING} {STRING} STR_INDUSTRY_VIEW_REQUIRES : {BLACK}必要物資: STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT :{YELLOW} {STRING} {BLACK}:{CARGO_SHORT}待機中{STRING} @@ -3392,6 +3439,7 @@ STR_GROUP_RENAME_CAPTION :{BLACK}グル STR_GROUP_PROFIT_THIS_YEAR :今年の利益: STR_GROUP_PROFIT_LAST_YEAR :昨年の利益: +STR_GROUP_OCCUPANCY :選択中: # Build vehicle window STR_BUY_VEHICLE_TRAIN_RAIL_CAPTION :新規機関車(非電化) @@ -3400,6 +3448,7 @@ STR_BUY_VEHICLE_TRAIN_MONORAIL_CAPTION :新規モノレ STR_BUY_VEHICLE_TRAIN_MAGLEV_CAPTION :新規リニア車両 STR_BUY_VEHICLE_ROAD_VEHICLE_CAPTION :新規車両 +STR_BUY_VEHICLE_TRAM_VEHICLE_CAPTION :新しい路面電車車両 ############ range for vehicle availability starts STR_BUY_VEHICLE_TRAIN_ALL_CAPTION :新規列車 @@ -3408,6 +3457,7 @@ STR_BUY_VEHICLE_AIRCRAFT_CAPTION :新規航空機 ############ range for vehicle availability ends STR_PURCHASE_INFO_COST_WEIGHT :{BLACK}価格: {GOLD}{CURRENCY_LONG}{BLACK} 重量: {GOLD}{WEIGHT_SHORT} +STR_PURCHASE_INFO_COST_REFIT_WEIGHT :{BLACK}コスト:{GOLD} {CURRENCY_LONG} {BLACK}(修理コスト:{GOLD} {CURRENCY_LONG} {BLACK})重量:{GOLD} {WEIGHT_SHORT} STR_PURCHASE_INFO_SPEED_POWER :{BLACK}最高速度: {GOLD}{VELOCITY}{BLACK} 出力: {GOLD}{POWER} STR_PURCHASE_INFO_SPEED :{BLACK}最高速度: {GOLD}{VELOCITY} STR_PURCHASE_INFO_SPEED_OCEAN :{BLACK}外洋/湖での航行速度: {GOLD}{VELOCITY} @@ -3431,6 +3481,7 @@ STR_PURCHASE_INFO_ENGINES_ONLY :エンジンの STR_PURCHASE_INFO_ALL_BUT :{CARGO_LIST}を除いてすべて STR_PURCHASE_INFO_MAX_TE :{BLACK}最大牽引力: {GOLD}{FORCE} STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}航続距離: {GOLD}{COMMA} タイル +STR_PURCHASE_INFO_AIRCRAFT_TYPE :{BLACK}航空機の機種: {GOLD}{STRING} STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP :{BLACK}列車リスト - 個々の情報を見るには列車をクリックします。Ctrl+クリックでその列車種の表示/非表示を切り替えます STR_BUY_VEHICLE_ROAD_VEHICLE_LIST_TOOLTIP :{BLACK}車両リスト - 個々の情報を見るには車両をクリックします。Ctrl+クリックでその車両種の表示/非表示を切り替えます @@ -3442,12 +3493,15 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_BUTTON :{BLACK}車両 STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_BUTTON :{BLACK}船舶を購入 STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_BUTTON :{BLACK}航空機を購入 +STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON :{BLACK}購入し改造する +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_BUTTON :{BLACK}船の購入と修理 STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP :{BLACK}選択した列車を購入します。Shift+クリックで購入費を見積もります STR_BUY_VEHICLE_ROAD_VEHICLE_BUY_VEHICLE_TOOLTIP :{BLACK}選択した車両を購入します。Shift+クリックで購入費を見積もります STR_BUY_VEHICLE_SHIP_BUY_VEHICLE_TOOLTIP :{BLACK}選択した船舶を購入します。Shift+クリックで購入費を見積もります STR_BUY_VEHICLE_AIRCRAFT_BUY_VEHICLE_TOOLTIP :{BLACK}選択した航空機を購入します。Shift+クリックで購入費を見積もります +STR_BUY_VEHICLE_SHIP_BUY_REFIT_VEHICLE_TOOLTIP :{BLACK}ハイライトされた船を購入して修理します。Shift +クリックすると、購入なしの推定コストが表示されます STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON :{BLACK}名称を変更 STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_BUTTON :{BLACK}名称を変更 @@ -3563,6 +3617,7 @@ STR_ENGINE_PREVIEW_MONORAIL_LOCOMOTIVE :モノレール STR_ENGINE_PREVIEW_MAGLEV_LOCOMOTIVE :リニア列車 STR_ENGINE_PREVIEW_ROAD_VEHICLE :車両 +STR_ENGINE_PREVIEW_TRAM_VEHICLE :路面電車車両 STR_ENGINE_PREVIEW_AIRCRAFT :航空機 STR_ENGINE_PREVIEW_SHIP :船舶 @@ -3610,6 +3665,7 @@ STR_REPLACE_ELRAIL_VEHICLES :機関車(電 STR_REPLACE_MONORAIL_VEHICLES :モノレール車両 STR_REPLACE_MAGLEV_VEHICLES :リニア車両 +STR_REPLACE_ROAD_VEHICLES :道路車両 STR_REPLACE_TRAM_VEHICLES :路面電車の車両 STR_REPLACE_REMOVE_WAGON :{BLACK}列車の短縮: {ORANGE}{STRING} @@ -3619,6 +3675,7 @@ STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}機関 STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_CENTER_TOOLTIP :{BLACK}メイン画面を列車に中心します。ダブルクリックで列車をメイン画面で追従します。Ctrl+クリックで列車の場所で新しいビューポートでを開きます。 +STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}航空機の位置に関する中央のメインビュー。ダブルクリックすると、メインビューで航空機が表示されます。Ctrl +クリックすると、航空機の位置に新しいビューポートが開きます STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}列車を列車庫へ回送します。Ctrl+クリックすると点検後、再出庫します STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}車両を車庫へ回送します。Ctrl+クリックすると点検後、再出庫します @@ -3650,6 +3707,8 @@ STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}車両 STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}船舶の情報を表示 STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}航空機の情報を表示します +STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}現在の列車の動作-クリックして列車を停止/開始します +STR_VEHICLE_VIEW_ROAD_VEHICLE_STATUS_START_STOP_TOOLTIP :{BLACK}現在の車両の動作-クリックして車両を停止/開始します STR_VEHICLE_VIEW_SHIP_STATE_STATUS_STOP_TOOLTIP :{BLACK}現在の船のアクション-クリックして船を停止/開始します STR_VEHICLE_VIEW_AIRCRAFT_STATUS_START_STOP_TOOLTIP :{BLACK}現在の航空機のアクション-クリックして航空機を停止/開始します @@ -3692,6 +3751,8 @@ STR_VEHICLE_INFO_AGE :{COMMA}年({COM STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA}年({COMMA}年) STR_VEHICLE_INFO_MAX_SPEED :{BLACK}最高速度: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_MAX_SPEED_TYPE :{BLACK}最高速度: {LTBLUE}{VELOCITY} {BLACK}航空機のタイプ: {LTBLUE}{STRING} +STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE :{BLACK}最高速度: {LTBLUE}{VELOCITY} {BLACK}航空機のタイプ: {LTBLUE}{STRING} {BLACK}範囲: {LTBLUE}{COMMA}タイル STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}重量: {LTBLUE}{WEIGHT_SHORT} {BLACK}出力: {LTBLUE}{POWER}{BLACK} 最高速度: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}重量: {LTBLUE}{WEIGHT_SHORT} {BLACK}出力: {LTBLUE}{POWER}{BLACK} 最高速度: {LTBLUE}{VELOCITY} {BLACK}最大牽引力: {LTBLUE}{FORCE} @@ -3877,6 +3938,7 @@ STR_ORDER_REFIT_STOP_ORDER :({STRING}に改 STR_ORDER_STOP_ORDER :(運用停止) STR_ORDER_GO_TO_STATION :{1:STATION}へ{0:STRING} {2:STRING} +STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(駅を使用できません){POP_COLOUR} {STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(自動) @@ -4055,7 +4117,11 @@ STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}選択 STR_AI_LIST_CANCEL :{BLACK}キャンセル STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}スクリプトを変更しません +STR_SCREENSHOT_CAPTION :{WHITE}スクリーンショットを撮る +STR_SCREENSHOT_ZOOMIN_SCREENSHOT :{BLACK}スクリーンショットを完全に拡大 STR_SCREENSHOT_WORLD_SCREENSHOT :{BLACK}地図全体のスクリーンショット +STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}ハイトマップスクリーンショット +STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}ミニマップのスクリーンショット # AI Parameters STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} パラメータ @@ -4115,6 +4181,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :このファイ STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :ファイルを読み込むことができません STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :ファイルに書き込むことができません STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :データ保全性チェック失敗 +STR_GAME_SAVELOAD_ERROR_PATCHPACK :安定版のセーブデータです。 STR_GAME_SAVELOAD_NOT_AVAILABLE :<使用不能> STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}このゲームは路面電車に対応していないバージョンで保存されましたので、すべての路面電車が削除されました。 @@ -4195,6 +4262,7 @@ STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}全額 STR_ERROR_CURRENCY_REQUIRED :{WHITE}{CURRENCY_LONG}が必要です STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}借入金を返済できません STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}借入金を送金することはできません +STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}この会社にお金を渡すことはできません... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}会社を買収できません STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}会社の本社ビルを建設できません STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}この会社の株を25%購入できません @@ -4322,6 +4390,7 @@ STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}この輸送機器の自動置換/更新は行われませんでした STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(最低資金が確保できていません) STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO :{WHITE}新しい車両は{STRING}を運ぶことができません +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT :{WHITE}新しい車両は順番に修理できません{NUM} # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}不可能な線路の組み合わせです @@ -4330,6 +4399,7 @@ STR_ERROR_NO_SUITABLE_RAILROAD_TRACK :{WHITE}適当 STR_ERROR_MUST_REMOVE_RAILROAD_TRACK :{WHITE}先に線路を撤去しなければなりません STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}道路は一方通行または進入禁止です STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}このレール種別との平面交差はできません +STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}この道路では踏切は作れません STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}ここには信号を設置できません STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}ここには線路を建設できません STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}ここから線路を撤去できません @@ -4350,6 +4420,9 @@ STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}ここ STR_ERROR_THERE_IS_NO_ROAD :{WHITE}道路がありません STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}軌道がありません STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}この道路のタイプは変更できません +STR_ERROR_CAN_T_CONVERT_TRAMWAY :{WHITE}ここで路面電車の種類を変更できません... +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}有効な路面電車がありません +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}軌道に互換性がありません # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}ここには運河を建設できません @@ -4901,6 +4974,7 @@ STR_FORMAT_BUOY_NAME :{TOWN} ブイ STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} 第{COMMA}ブイ STR_FORMAT_COMPANY_NUM :(会社{COMMA}) STR_FORMAT_GROUP_NAME :グループ {COMMA} +STR_FORMAT_GROUP_VEHICLE_NAME :{GROUP} #{COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN}{STRING} STR_FORMAT_WAYPOINT_NAME :{TOWN}中継駅 STR_FORMAT_WAYPOINT_NAME_SERIAL :第{1:COMMA} {0:TOWN}中継駅 diff --git a/src/lang/korean.txt b/src/lang/korean.txt index ed0d2603f9..ec38b57036 100644 --- a/src/lang/korean.txt +++ b/src/lang/korean.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :말레이시아 STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :좌측통행 STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :우측통행 -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}도시 이름 +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}도시 이름: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}도시 이름 스타일을 선택하세요 ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :12개월마다 STR_GAME_OPTIONS_LANGUAGE :{BLACK}언어 STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}사용할 언어를 선택하세요 +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% 번역됨) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}전체화면 STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD를 전체화면으로 플레이하려면 클릭하세요. @@ -1004,9 +1005,12 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :기타 STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}하드웨어 가속 -STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}OpenTTD가 하드웨어 가속을 사용하게 하려면 체크하세요. 변경된 설정은 게임을 재시작한 뒤에 적용됩니다. +STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}OpenTTD가 하드웨어 가속을 사용하게 하려면 체크하세요. 변경한 설정은 게임을 재시작한 뒤에 적용될 것입니다. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}이 설정은 게임을 재시작한 뒤에 적용될 것입니다 +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}수직 동기화 +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}화면과 수직 동기화하려면 체크하세요. 변경한 설정은 게임을 재시작한 뒤에 적용될 것입니다. 하드웨어 가속을 켠 경우에만 작동합니다. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}인터페이스 크기 STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}인터페이스의 크기를 선택합니다. @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}설정 STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}검색할 문자열: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}모두 펼치기 STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}모두 접기 +STR_CONFIG_SETTING_RESET_ALL :{BLACK}모든 설정 초기화 STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(설명이 존재하지 않습니다) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}기본값: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}설정 종류: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :게임 설정 ( STR_CONFIG_SETTING_TYPE_GAME_INGAME :게임 설정 (게임 저장 파일에 저장됨; 현재 게임에만 적용됨) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :회사 설정 (게임 저장 파일에 저장됨; 새 게임에만 적용됨) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :회사 설정 (게임 저장 파일에 저장됨; 현재 회사에만 적용됨) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}경고! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}게임의 모든 설정을 기본값으로 되돌립니다.{}정말 모든 설정을 초기화하시겠습니까? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}분류: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}종류: @@ -1259,7 +1266,7 @@ STR_CONFIG_SETTING_MULTIPINDTOWN_HELPTEXT :일반적으로 STR_CONFIG_SETTING_SIGNALSIDE :신호기 보이기: {STRING} STR_CONFIG_SETTING_SIGNALSIDE_HELPTEXT :선로의 어느 쪽에 신호기를 설치할 지 선택합니다. STR_CONFIG_SETTING_SIGNALSIDE_LEFT :왼쪽에 -STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :진행 방향에 +STR_CONFIG_SETTING_SIGNALSIDE_DRIVING_SIDE :자동차 통행 방향에 STR_CONFIG_SETTING_SIGNALSIDE_RIGHT :오른쪽에 STR_CONFIG_SETTING_SHOWFINANCES :연말에 자동으로 재정 창을 띄우기: {STRING} STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :이 설정을 켜면. 회사의 재정 상태를 확인하기 쉽도록 매년 말에 재정 창이 자동으로 뜹니다. @@ -1526,7 +1533,7 @@ STR_CONFIG_SETTING_AI_PROFILE_EASY :쉬움 STR_CONFIG_SETTING_AI_PROFILE_MEDIUM :중간 STR_CONFIG_SETTING_AI_PROFILE_HARD :어려움 -STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :멀티플레이에서 컴퓨터 플레이어의 참여 허용: {STRING} +STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :멀티 플레이에서 컴퓨터 플레이어의 참여 허용: {STRING} STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :멀티 플레이 게임에서 인공지능 컴퓨터 플레이어가 참여하는 것을 허용합니다. STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :게임 스크립트가 중지되기 직전에 계산할 수 있는 최대 횟수: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :게임 스크립트가 한 단계에서 계산할 수 있는 최대 계산 횟수를 설정합니다. @@ -1534,20 +1541,20 @@ STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :스크립트당 STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :스크립트 하나가 강제 종료되기 전까지 사용할 수 있는 메모리의 양입니다. 크기가 큰 맵에서는 값을 크게 설정해야할 수도 있습니다. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB -STR_CONFIG_SETTING_SERVINT_ISPERCENT :신뢰도에 따른 정비 설정: {STRING} +STR_CONFIG_SETTING_SERVINT_ISPERCENT :신뢰도에 따른 점검 설정: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :차량 점검 방식을 "마지막 점검 이후 지난 시간 (또는) 최대 신뢰도에 대한 차량 신뢰도의 일정 퍼센트 하락 여부" 중에 하나로 선택합니다. STR_CONFIG_SETTING_SERVINT_TRAINS :열차에 대한 기본 점검 기준: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :열차에 따로 점검 기간이 설정되어있지 않은 경우에 사용할 기본 점검 기간을 설정합니다. STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA}{NBSP}일/% STR_CONFIG_SETTING_SERVINT_DISABLED :사용 안 함 STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :차량에 대한 기본 점검 기준: {STRING} -STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :차량 정비 설정을 하지 않은 경우, 기본값으로 사용할 정비 주기를 설정합니다. +STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :차량 점검 설정을 하지 않은 경우, 기본값으로 사용할 점검 주기를 설정합니다 STR_CONFIG_SETTING_SERVINT_AIRCRAFT :항공기에 대한 기본 점검 기준: {STRING} STR_CONFIG_SETTING_SERVINT_AIRCRAFT_HELPTEXT :항공기에 따로 점검 기간이 설정되어있지 않은 경우에 사용할 기본 점검 기간을 설정합니다. STR_CONFIG_SETTING_SERVINT_SHIPS :선박에 대한 기본 점검 기준: {STRING} STR_CONFIG_SETTING_SERVINT_SHIPS_HELPTEXT :선박에 따로 점검 기간이 설정되어있지 않은 경우에 사용할 기본 점검 기간을 설정합니다. -STR_CONFIG_SETTING_NOSERVICE :차량 고장 설정이 비활성화된 경우 정비하지 않음: {STRING} -STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :이 설정을 켜면, 차량이 고장나지 않도록 설정되어 있는 경우 차량이 정비를 하러 가지 않습니다. +STR_CONFIG_SETTING_NOSERVICE :차량 고장 설정을 껐으면 점검을 하지 않음: {STRING} +STR_CONFIG_SETTING_NOSERVICE_HELPTEXT :이 설정을 켜면, 차량이 고장나지 않도록 설정되어 있는 경우 차량이 자동으로 점검을 하러 가지 않습니다 STR_CONFIG_SETTING_WAGONSPEEDLIMITS :화물차 속력 제한 적용: {STRING} STR_CONFIG_SETTING_WAGONSPEEDLIMITS_HELPTEXT :이 설정을 켜면, 화물차의 속력 제한값에 따라 열차의 최대 속력을 제한합니다. STR_CONFIG_SETTING_DISABLE_ELRAILS :전기 철도를 사용하지 않음: {STRING} @@ -1723,38 +1730,38 @@ STR_CONFIG_SETTING_SHORT_PATH_SATURATION_HELPTEXT :종종 두 역 STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY :속력 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :속력를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :임페리얼법 (mph) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :야드파운드법 (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :미터법 (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :국제표준규격 (m/s) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :게임 단위 (칸/일) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :차량의 힘 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :출력할 차량의 힘 단위를 선택합니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :임페리얼법 (마력) +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :야드파운드법 (마력) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :미터법 (마력) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :국제표준규격 (kW) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT :무게 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_HELPTEXT :무게를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :임페리얼법 (미국 톤) +STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_IMPERIAL :야드파운드법 (미국 톤) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_METRIC :미터법 (톤) STR_CONFIG_SETTING_LOCALISATION_UNITS_WEIGHT_SI :국제표준규격 (kg) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME :부피 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_HELPTEXT :부피를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :임페리얼법 (갤런) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_IMPERIAL :야드파운드법 (갤런) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_METRIC :미터법 (리터) STR_CONFIG_SETTING_LOCALISATION_UNITS_VOLUME_SI :국제표준규격 (m³) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE :견인 효과 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_HELPTEXT :견인 효과(견인력)를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :임페리얼법 (파운드중) +STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_IMPERIAL :야드파운드법 (파운드중) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_METRIC :미터법 (kgf) STR_CONFIG_SETTING_LOCALISATION_UNITS_FORCE_SI :국제표준규격 (kN) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT :높이 단위: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_HELPTEXT :높이를 표시할 때 선택한 단위를 사용하여 나타냅니다. -STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :임페리얼법 (ft) +STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_IMPERIAL :야드파운드법 (ft) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_METRIC :미터법 (m) STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :국제표준규격 (m) @@ -1801,8 +1808,8 @@ STR_CONFIG_ERROR :{WHITE}설정 STR_CONFIG_ERROR_ARRAY :{WHITE}... 배열 '{STRING}'에서 오류 발생 STR_CONFIG_ERROR_INVALID_VALUE :{WHITE}... '{1:STRING}'에 잘못된 값('{0:STRING}')이 지정되었습니다. STR_CONFIG_ERROR_TRAILING_CHARACTERS :{WHITE}... '{STRING}' 설정의 끝에 후행 문자가 있습니다. -STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... NewGRF '{STRING}' 무시중: '{STRING}'{G 1 "과" "와"} GRF ID가 겹침 -STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... 유효하지 않은 NewGRF '{STRING}' 무시중: {STRING} +STR_CONFIG_ERROR_DUPLICATE_GRFID :{WHITE}... '{STRING}' NewGRF를 무시합니다: '{STRING}'{G 1 "과" "와"} GRF ID가 겹침 +STR_CONFIG_ERROR_INVALID_GRF :{WHITE}... 유효하지 않은 '{STRING}' NewGRF를 무시합니다: {STRING} STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND :찾을 수 없음 STR_CONFIG_ERROR_INVALID_GRF_UNSAFE :사용하기에 불안함 STR_CONFIG_ERROR_INVALID_GRF_SYSTEM :NewGRF 시스템 @@ -1985,6 +1992,9 @@ STR_FACE_TIE :넥타이: STR_FACE_EARRING :귀걸이: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}넥타이/귀걸이 변경 +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :비공개 +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :공개 + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}멀티 플레이 STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}플레이어 이름: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}멀티 STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}비밀번호 설정 STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}서버에 공개적으로 접근하는 것을 막고 싶을 때 비밀번호를 걸어 보호합니다. -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}공개 여부 -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}공개된 게임(인터넷)과 비공개된 게임(LAN) 중에서 선택하세요 -STR_NETWORK_START_SERVER_UNADVERTISED :아니요 -STR_NETWORK_START_SERVER_ADVERTISED :예 +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}공개 여부 +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}서버 목록에 이 서버를 공개할 지 여부를 설정합니다 STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM}명 STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}최대 접속자 수: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}최대 접속자 수를 선택합니다. 모든 자리가 다 차 있을 필요는 없습니다 @@ -2065,51 +2073,11 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}서버 STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}네트워크 게임에서 사용할 이름을 입력하세요 -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :모든 언어 -STR_NETWORK_LANG_ENGLISH :영어 -STR_NETWORK_LANG_GERMAN :독일어 -STR_NETWORK_LANG_FRENCH :프랑스어 -STR_NETWORK_LANG_BRAZILIAN :브라질어 -STR_NETWORK_LANG_BULGARIAN :불가리아어 -STR_NETWORK_LANG_CHINESE :중국어 -STR_NETWORK_LANG_CZECH :체코어 -STR_NETWORK_LANG_DANISH :덴마크어 -STR_NETWORK_LANG_DUTCH :네덜란드어 -STR_NETWORK_LANG_ESPERANTO :에스페란토 -STR_NETWORK_LANG_FINNISH :핀란드어 -STR_NETWORK_LANG_HUNGARIAN :헝가리어 -STR_NETWORK_LANG_ICELANDIC :아이슬란드어 -STR_NETWORK_LANG_ITALIAN :이탈리아어 -STR_NETWORK_LANG_JAPANESE :일본어 -STR_NETWORK_LANG_KOREAN :한국어 -STR_NETWORK_LANG_LITHUANIAN :리투아니아어 -STR_NETWORK_LANG_NORWEGIAN :노르웨이어 -STR_NETWORK_LANG_POLISH :폴란드어 -STR_NETWORK_LANG_PORTUGUESE :포르투갈어 -STR_NETWORK_LANG_ROMANIAN :루마니아어 -STR_NETWORK_LANG_RUSSIAN :러시아어 -STR_NETWORK_LANG_SLOVAK :슬로바키아어 -STR_NETWORK_LANG_SLOVENIAN :슬로베니아어 -STR_NETWORK_LANG_SPANISH :스페인어 -STR_NETWORK_LANG_SWEDISH :스웨덴어 -STR_NETWORK_LANG_TURKISH :터키어 -STR_NETWORK_LANG_UKRAINIAN :우크라이나어 -STR_NETWORK_LANG_AFRIKAANS :아프리카어 -STR_NETWORK_LANG_CROATIAN :크로아티아어 -STR_NETWORK_LANG_CATALAN :카탈로니아어 -STR_NETWORK_LANG_ESTONIAN :에스토니아어 -STR_NETWORK_LANG_GALICIAN :갈리시아어 -STR_NETWORK_LANG_GREEK :그리스어 -STR_NETWORK_LANG_LATVIAN :라트비아어 -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}멀티플레이 게임 대기실 STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}참가 준비중: {ORANGE}{STRING} -STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}이 게임에 있는 회사의 목록입니다. 다른 회사에 같이 참가하거나, 빈 자리가 있을 경우 새로운 회사로 시작할 수 있습니다 +STR_NETWORK_GAME_LOBBY_COMPANY_LIST_TOOLTIP :{BLACK}이 게임에 있는 회사의 목록입니다. 다른 회사에 같이 참여하거나, 빈 자리가 있을 경우 새로운 회사를 세워서 시작할 수 있습니다 STR_NETWORK_GAME_LOBBY_COMPANY_INFO :{SILVER}회사 정보 STR_NETWORK_GAME_LOBBY_COMPANY_NAME :{SILVER}회사 이름: {WHITE}{STRING} @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}접속 STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}서버 암호가 걸려있습니다. 암호를 입력하세요 STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}회사 암호가 걸려있습니다. 암호를 입력하세요 -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}접속자 목록 # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :접속자 목록 -STR_NETWORK_COMPANY_LIST_SPECTATE :관전 -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :새 회사 # Network client list -STR_NETWORK_CLIENTLIST_KICK :추방 -STR_NETWORK_CLIENTLIST_BAN :차단 -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :모두에게 말하기 -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :이 회사에게 말하기 -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :귓속말하기 +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}멀티 플레이 +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}서버 +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}이름 +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}현재 플레이하고 있는 서버의 이름입니다 +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}서버의 이름을 수정합니다 +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :서버 이름 +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}공개 여부 +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}서버 목록에 이 서버를 공개할 지 여부를 설정합니다 +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}플레이어 +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}이름 +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}당신의 접속자 이름입니다 +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}접속자 이름을 수정합니다 +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :접속자 이름 +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}관리자가 이 접속자에게 할 수 있는 기능입니다 +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}관리자가 이 접속자에게 할 수 있는 기능입니다 +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}여기에 참여합니다 +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}이 플레이어에게 메시지를 보냅니다 +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}이 회사에 참여 중인 모든 플레이어에게 메시지를 보냅니다 +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}모든 관전자에게 메시지를 보냅니다 +STR_NETWORK_CLIENT_LIST_SPECTATORS :관전 +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(새 회사) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}새 회사를 만듭니다 +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}당신입니다 +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}이 게임을 연 사람입니다 + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :추방 +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :차단 +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :삭제 +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :비밀번호 초기화 + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}관리자 기능 +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}'{STRING}' 플레이어를 정말로 추방하시겠습니까? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}'{STRING}' 플레이어를 정말로 차단하시겠습니까? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}'{COMPANY}' 회사를 정말로 삭제하시겠습니까? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}'{COMPANY}' 회사의 비밀번호를 정말로 초기화하시겠습니까? STR_NETWORK_SERVER :서버 STR_NETWORK_CLIENT :접속자 @@ -2175,11 +2170,11 @@ STR_COMPANY_PASSWORD_CANCEL :{BLACK}입력 STR_COMPANY_PASSWORD_OK :{BLACK}이 회사에 새 비밀번호 부여 STR_COMPANY_PASSWORD_CAPTION :{WHITE}회사 비밀번호 STR_COMPANY_PASSWORD_MAKE_DEFAULT :{BLACK}회사 비밀번호 기본값으로 설정 -STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}이 회사 비밀번호를 새 회사의 비밀번호 기본값으로 사용 +STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}이 비밀번호를 새 회사의 비밀번호 기본값으로 사용합니다 # Network company info join/password STR_COMPANY_VIEW_JOIN :{BLACK}참여 -STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}이 회사로 참가해서 플레이합니다 +STR_COMPANY_VIEW_JOIN_TOOLTIP :{BLACK}이 회사에 참여해서 플레이합니다 STR_COMPANY_VIEW_PASSWORD :{BLACK}비밀번호 STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}다른 참가자가 이 회사에 참여하여 플레이하지 못 하도록 암호로 보호합니다 STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}회사 비밀번호 설정 @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}서버 STR_NETWORK_ERROR_CLIENT_START :{WHITE}접속할 수 없습니다 STR_NETWORK_ERROR_TIMEOUT :{WHITE}접속자 #{NUM}의 입력 시간이 초과되었습니다 STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}프로토콜 오류가 발생되어 연결이 끊어졌습니다 +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}접속자 이름을 설정하지 않았습니다. 이름은 멀티플레이 창의 상단에서 설정할 수 있습니다. STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}이 접속자의 게임 버전이 서버의 버전과 일치하지 않습니다 STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}잘못된 비밀번호입니다 STR_NETWORK_ERROR_SERVER_FULL :{WHITE}서버에 인원이 가득 찼습니다 @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}비밀 STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}사용자의 컴퓨터가 서버와 연결을 유지할 수 있을 만큼 빠르지 않습니다 STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}지도 다운로드 시간을 초과하였습니다 STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}서버 접속 시간을 초과하였습니다 +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}사용할 수 없는 이름입니다 ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :일반 오류 @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :제 시간에 STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :반응 시간 초과 STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :지도 다운로드 시간 초과 STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :지도 생성 / 입장 시간 초과 +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :유효하지 않은 클라이언트 이름 ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}가능한 연결 손실 @@ -2271,7 +2269,7 @@ STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {STRING} 님이 관전을 시작하셨습니다 STR_NETWORK_MESSAGE_CLIENT_COMPANY_NEW :*** {STRING} 님이 새로운 회사({2:NUM}번)를 창설하셨습니다 STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} 님이 퇴장하셨습니다 (사유: {2:STRING}) -STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} 님의 이름이 {STRING}(으)로 바뀌었습니다 +STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} 님이 이름을 {STRING}(으)로 바꾸었습니다 STR_NETWORK_MESSAGE_GIVE_MONEY :*** {0:STRING} 님이 {1:STRING}에게 {2:CURRENCY_LONG}만큼의 돈을 보내셨습니다 STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}서버가 게임을 종료하였습니다 STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}서버가 재시작되고 있습니다...{}기다려주세요... @@ -2406,7 +2404,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :자기부상열 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}선로를 건설합니다. CTRL 키를 누르면 건설모드/철거모드로 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL :{BLACK}자동건설 모드로 선로를 건설합니다. CTRL 키를 누르면 건설/철거모드를 바꿀 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 -STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}차량기지를 건설합니다. 차량을 구입하거나 정비를 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 +STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}차량기지를 건설합니다. 차량을 구입하거나 점검을 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}선로에 경유지를 설치합니다. CTRL 키를 사용하면 같은 이름의 경유지를 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}철도역을 짓습니다. CTRL 키를 사용하면 같은 이름의 역을 서로 떨어진 곳에 지을 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}신호기를 설치합니다. CTRL 키를 누르면 구식/전자식으로 전환합니다.{}선로를 따라 드래그해서 설치할 수 있습니다. CTRL 키를 누른 채로 드래그하면 다음 분기점이나 다음 신호기까지 신호기를 설치합니다.{}CTRL 키를 누른 채 클릭하면 신호기 선택 창을 전환합니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 @@ -2487,8 +2485,8 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION :{BLACK}도로 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION :{BLACK}전차 선로를 짓습니다. CTRL 키를 누르고 있으면 건설/제거 모드를 바꿀 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}자동건설 모드로 도로를 짓습니다. CTRL 키를 누르고 있으면 건설/제거 모드를 바꿀 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}자동건설 모드로 전차 선로를 짓습니다. CTRL 키를 누르고 있으면 건설/제거 모드를 바꿀 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}차고지를 건설합니다. 차량을 구입하거나 정비를 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 -STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}전차 차고지를 건설합니다. 차량을 구입하거나 정비를 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}차고지를 건설합니다. 차량을 구입하거나 점검을 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 +STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}전차 차고지를 건설합니다. 차량을 구입하거나 점검을 할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}버스 정류장을 짓습니다. CTRL 키를 사용하면 근처 정류장과 연결할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}여객 전차역을 짓습니다. CTRL 키를 사용하면 근처 역과 연결할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}트럭 적하장을 짓습니다. CTRL 키를 사용하면 근처 적하장과 연결할 수 있습니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}항구 STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}경유지로 사용할 수 있는 부표를 만듭니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}수도교를 만듭니다. SHIFT 키를 누른 채로 사용하면 예상 비용을 볼 수 있습니다 STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}벽으로 물을 막고 있는 운하를 만듭니다.{}해수면 높이에서 CTRL 키를 누른 채로 사용하면 벽 없이 물을 만들어 바다나 호수를 만들 수 있습니다 -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}강을 만듭니다 +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}강을 만듭니다. CTRL 키를 누르면 대각선 방향의 영역을 선택할 수 있습니다. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}정박소 방향 선택 @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}경고: {S STR_NEWGRF_ERROR_MSG_ERROR :{RED}오류: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}치명적 오류: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}치명적인 NewGRF 오류가 발생했습니다:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}NewGRF 관련 오류가 발생했습니다:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING}{G 1 "은" "는"} OpenTTD에서 보고된 TTDPatch 버전에서 작동하지 않을 것입니다 STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING}{G 1 "은" "는"} {STRING} 버전의 TTD를 위한 것입니다 STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING}{G 1 "은" "는"} {STRING}{G 1 "와" "과"} 같이 사용해야 합니다 @@ -3090,7 +3089,7 @@ STR_NEWGRF_ERROR_LOAD_BEFORE :{1:STRING}{G 1 STR_NEWGRF_ERROR_LOAD_AFTER :{1:STRING}{G 1 "은" "는"} 반드시 {STRING} 뒤에 불러와야 합니다 STR_NEWGRF_ERROR_OTTD_VERSION_NUMBER :{1:STRING}{G 1 "은" "는"} OpenTTD {STRING} 버전이나 그 이상이 필요합니다 STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE :GRF 파일이 번역을 위해 만들어졌습니다 -STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :NewGRF이 너무 많습니다 +STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED :NewGRF가 너무 많습니다 STR_NEWGRF_ERROR_STATIC_GRF_CAUSES_DESYNC :{2:STRING}{G 2 "을" "를"} 포함한 정적 NewGRF {1:STRING}{G 1 "을" "를"} 불러오는 것은 비동기화를 일으킬 수 있습니다 STR_NEWGRF_ERROR_UNEXPECTED_SPRITE :예기치 않은 스프라이트 (스프라이트 {3:NUM}) STR_NEWGRF_ERROR_UNKNOWN_PROPERTY :알려지지 않은 액션 0 속성 {4:HEX} (스프라이트 {3:NUM}) @@ -3124,8 +3123,8 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}호환 STR_NEWGRF_LIST_MISSING :{RED}파일 없음 # NewGRF 'it's broken' warnings -STR_NEWGRF_BROKEN :{WHITE}'{0:STRING}' NewGRF이 적용되는 과정에서 비동기화나 충돌이 일어날 수 있습니다 -STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}차고지 안에 있지 않은 '{1:ENGINE}'에 대한 동력 차량 상태가 바뀌었습니다 +STR_NEWGRF_BROKEN :{WHITE}'{0:STRING}' NewGRF가 적용되는 과정에서 비동기화나 충돌이 일어날 수 있습니다 +STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}차고지 안에 있지 않은 '{1:ENGINE}' 동력 차량의 상태가 바뀌었습니다 STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}'{1:ENGINE}'{G 1 "이" "가"} 차고지 안에 있지 않으면 차량 길이가 바뀝니다 STR_NEWGRF_BROKEN_CAPACITY :{WHITE}차량이 기지 안에 있지 않거나 개조가 불가능한 상태에서 '{1:ENGINE}'의 수송량이 변경되었습니다 STR_BROKEN_VEHICLE_LENGTH :{WHITE}'{1:COMPANY}'에 속한 열차 '{0:VEHICLE}'의 길이가 잘못된 값을 가지고 있습니다. NewGRF에 의한 문제로 보입니다. 게임이 비동기화 또는 충돌을 일으킬 수 있습니다. @@ -3529,7 +3528,7 @@ STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP :{BLACK}이 차 STR_VEHICLE_LIST_MANAGE_LIST :{BLACK}관리 STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP :{BLACK}이 목록에 있는 모든 열차에 지시를 내려 관리합니다 STR_VEHICLE_LIST_REPLACE_VEHICLES :차량 교체 -STR_VEHICLE_LIST_SEND_FOR_SERVICING :정비하러 보내기 +STR_VEHICLE_LIST_SEND_FOR_SERVICING :점검하러 보내기 STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT :차량기지로 보내기 STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT :차고지로 보내기 @@ -3748,7 +3747,7 @@ STR_DEPOT_MASS_START_HANGAR_TOOLTIP :{BLACK}이 격 STR_DEPOT_SELL_CONFIRMATION_TEXT :{YELLOW}이 안에 있는 모든 차량을 판매하려고 합니다. 계속하시겠습니까? # Engine preview window -STR_ENGINE_PREVIEW_CAPTION :{WHITE}차량 개발자로부터의 메시지 +STR_ENGINE_PREVIEW_CAPTION :{WHITE}차량 개발자가 보낸 메시지 STR_ENGINE_PREVIEW_MESSAGE :{GOLD}저희는 이제 막 새로운 {STRING}{G 0 "을" "를"} 개발했습니다. 1년 먼저 이 차량을 사용하셔서 모두에게 공개되기 전에 잘 작동하는지 확인해주시겠습니까? STR_ENGINE_PREVIEW_RAILROAD_LOCOMOTIVE :{G=f}철도 기관차 @@ -3823,10 +3822,10 @@ STR_VEHICLE_VIEW_ROAD_VEHICLE_CENTER_TOOLTIP :{BLACK}이 차 STR_VEHICLE_VIEW_SHIP_CENTER_TOOLTIP :{BLACK}이 선박의 위치로 화면을 이동합니다. 더블 클릭하면 이 선박을 따라 화면이 움직입니다. CTRL+클릭하면 이 선박 위치를 기준으로 외부 화면을 엽니다 STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}이 항공기의 위치로 화면을 이동합니다. 더블 클릭하면 이 항공기를 따라 화면이 움직입니다. CTRL+클릭하면 이 항공기 위치를 기준으로 외부 화면을 엽니다 -STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}열차를 차량기지로 보냅니다. CTRL+클릭하면 정비를 하러 차량기지에 들르기만 합니다 -STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}차량을 차고지로 보냅니다. CTRL+클릭하면 정비를 하러 차고지에 들르기만 합니다 -STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}선박을 정박소로 보냅니다. CTRL+클릭하면 정비를 하러 정박소에 들르기만 합니다 -STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}항공기를 격납고로 보냅니다. CTRL+클릭하면 정비를 하러 격납고에 들르기만 합니다 +STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}열차를 차량기지로 보냅니다. CTRL+클릭하면 점검을 하러 차량기지에 들르기만 합니다 +STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}차량을 차고지로 보냅니다. CTRL+클릭하면 점검을 하러 차고지에 들르기만 합니다 +STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}선박을 정박소로 보냅니다. CTRL+클릭하면 점검을 하러 정박소에 들르기만 합니다 +STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}항공기를 격납고로 보냅니다. CTRL+클릭하면 점검을 하러 격납고에 들르기만 합니다 STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}객차/화차를 포함한 열차 전체를 복제합니다. CTRL+클릭하면 경로도 함께 공유됩니다. SHIFT+클릭하면 예상 비용을 볼 수 있습니다 STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}차량을 복제합니다. CTRL+클릭하면 경로도 함께 공유됩니다. SHIFT+클릭하면 예상 비용을 볼 수 있습니다 @@ -3914,12 +3913,12 @@ STR_VEHICLE_INFO_CAPACITY_CAPACITY :{BLACK}수송 STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}환승 수익: {LTBLUE}{CURRENCY_LONG} -STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}정비 간격: {LTBLUE}{COMMA}일{BLACK}마다 마지막 정비 날짜: {LTBLUE}{DATE_LONG} -STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}정비 기준: {LTBLUE}{COMMA}%{BLACK} 떨어지면 마지막 정비 날짜: {LTBLUE}{DATE_LONG} +STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}점검 간격: {LTBLUE}{COMMA}일{BLACK}마다{NBSP} 마지막 점검 날짜: {LTBLUE}{DATE_LONG} +STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}점검 기준: {LTBLUE}{COMMA}%{BLACK} 떨어지면 마지막 점검 날짜: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}점검 기준값을 10만큼 올립니다. CTRL+클릭하면 점검 기준값을 5만큼 올립니다 STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}점검 기준값을 10만큼 내립니다. CTRL+클릭하면 점검 기준값을 5만큼 내립니다 -STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}정비 기준 설정을 변경합니다 +STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}점검 기준 설정을 변경합니다 STR_VEHICLE_DETAILS_DEFAULT :기본 STR_VEHICLE_DETAILS_DAYS :날짜 STR_VEHICLE_DETAILS_PERCENT :신뢰도 @@ -4017,11 +4016,11 @@ STR_ORDER_REFIT_AUTO_TOOLTIP :{BLACK}이 경 STR_ORDER_DROP_REFIT_AUTO :특정 화물로 STR_ORDER_DROP_REFIT_AUTO_ANY :이용 가능한 화물로 -STR_ORDER_SERVICE :{BLACK}정비 +STR_ORDER_SERVICE :{BLACK}점검 STR_ORDER_DROP_GO_ALWAYS_DEPOT :항상 감 -STR_ORDER_DROP_SERVICE_DEPOT :필요하면 정비 +STR_ORDER_DROP_SERVICE_DEPOT :필요하면 점검 STR_ORDER_DROP_HALT_DEPOT :멈춤 -STR_ORDER_SERVICE_TOOLTIP :{BLACK}정비가 필요하지 않으면 이 경로를 건너뜁니다 +STR_ORDER_SERVICE_TOOLTIP :{BLACK}점검이 필요하지 않으면 이 경로를 건너뜁니다 STR_ORDER_CONDITIONAL_VARIABLE_TOOLTIP :{BLACK}경로를 건너뛰기 위한 비교 조건을 선택합니다 @@ -4030,7 +4029,7 @@ STR_ORDER_CONDITIONAL_LOAD_PERCENTAGE :적재율 STR_ORDER_CONDITIONAL_RELIABILITY :신뢰도 STR_ORDER_CONDITIONAL_MAX_SPEED :최고 속력 STR_ORDER_CONDITIONAL_AGE :연령 (년) -STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :정비 필요성 +STR_ORDER_CONDITIONAL_REQUIRES_SERVICE :점검 필요성 STR_ORDER_CONDITIONAL_UNCONDITIONALLY :항상 STR_ORDER_CONDITIONAL_REMAINING_LIFETIME :남은 수명 (년) STR_ORDER_CONDITIONAL_MAX_RELIABILITY :최대 신뢰도 @@ -4062,7 +4061,7 @@ STR_ORDER_GO_TO_NEAREST_DEPOT :가까운 차 STR_ORDER_GO_TO_NEAREST_HANGAR :가까운 격납고로 STR_ORDER_CONDITIONAL :조건부 경로 건너뛰기 STR_ORDER_SHARE :경로 공유하기 -STR_ORDERS_GO_TO_TOOLTIP :{BLACK}선택된 경로 바로 전이나 목록 맨 끝에 새 경로를 삽입합니다. CTRL 키와 함께 누르면, 역에서는 '아무 화물이나 가득 싣기'로, 경유지에서는 '직행'으로, 차량기지에서는 '점검'으로 지정됩니다. '공유된 경로'를 클릭하거나 CTRL 키를 누르면 선택했던 차량과 이 차량의 경로를 공유하게 됩니다. 단순히 클릭하면 그 차량의 경로를 복사하기만 합니다. 차량기지를 경로에 포함시키면 이 차량은 자동 정비를 할 수 없게 됩니다 +STR_ORDERS_GO_TO_TOOLTIP :{BLACK}선택된 경로 바로 전이나 목록 맨 끝에 새 경로를 삽입합니다. CTRL 키와 함께 누르면, 역에서는 '아무 화물이나 가득 싣기'로, 경유지에서는 '직행'으로, 차량기지에서는 '점검'으로 지정됩니다. '공유된 경로'를 클릭하거나 CTRL 키를 누르면 선택했던 차량과 이 차량의 경로를 공유하게 됩니다. 단순히 클릭하면 그 차량의 경로를 복사하기만 합니다. 차량기지를 경로에 포함시키면 이 차량은 자동 점검를 할 수 없게 됩니다 STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}이 경로를 공유하고 있는 모든 차량을 표시합니다. @@ -4070,8 +4069,8 @@ STR_ORDERS_VEH_WITH_SHARED_ORDERS_LIST_TOOLTIP :{BLACK}이 경 STR_ORDER_GO_TO_WAYPOINT :완행 경유 {WAYPOINT} STR_ORDER_GO_NON_STOP_TO_WAYPOINT :직행 경유 {WAYPOINT} -STR_ORDER_SERVICE_AT :완행 정비 -STR_ORDER_SERVICE_NON_STOP_AT :직행 정비 +STR_ORDER_SERVICE_AT :완행 점검 +STR_ORDER_SERVICE_NON_STOP_AT :직행 점검 STR_ORDER_NEAREST_DEPOT :가까운 STR_ORDER_NEAREST_HANGAR :가까운 격납고 @@ -4679,7 +4678,7 @@ STR_ERROR_SHIP_NOT_AVAILABLE :{WHITE}이 선 STR_ERROR_AIRCRAFT_NOT_AVAILABLE :{WHITE}이 항공기는 사용할 수 없는 상태입니다 STR_ERROR_TOO_MANY_VEHICLES_IN_GAME :{WHITE}게임에 차량이 너무 많습니다! -STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}정비 간격 설정을 바꿀 수 없습니다... +STR_ERROR_CAN_T_CHANGE_SERVICING :{WHITE}점검 간격 설정을 바꿀 수 없습니다... STR_ERROR_VEHICLE_IS_DESTROYED :{WHITE}... 차량이 파괴되었습니다 diff --git a/src/lang/latin.txt b/src/lang/latin.txt index 42cc1b824f..ce65bfd5c9 100644 --- a/src/lang/latin.txt +++ b/src/lang/latin.txt @@ -1166,6 +1166,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Eligere STR_GAME_OPTIONS_RESOLUTION_OTHER :alia + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Magnitudo interfaciei STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Eligere magnitudinem interfaciei adhibendam @@ -2087,6 +2088,7 @@ STR_FACE_TIE :Focale: STR_FACE_EARRING :Inauris: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Mutare focale vel inaurem + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Modus Plurium Lusorum STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nomen lusoris: @@ -2145,10 +2147,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Hoc ludi STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Elige tesseram STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Custodire tessera ludum tuum, si non vis publicos iungere -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Ostensum -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Eligere servatrum ostensum (interretis) aut non ostensum (LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Non -STR_NETWORK_START_SERVER_ADVERTISED :Ita STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} clien{P s tes} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Clientes maximi: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Eligere numerum maximum clientorum. Necesse non est omnes loci pleni esse @@ -2163,46 +2161,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Lingua i STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Inscribe nomen ludi retis -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Quaevis -STR_NETWORK_LANG_ENGLISH :Anglica -STR_NETWORK_LANG_GERMAN :Theodisca -STR_NETWORK_LANG_FRENCH :Francogallica -STR_NETWORK_LANG_BRAZILIAN :Brasilica -STR_NETWORK_LANG_BULGARIAN :Bulgarica -STR_NETWORK_LANG_CHINESE :Sinica -STR_NETWORK_LANG_CZECH :Cecha -STR_NETWORK_LANG_DANISH :Danica -STR_NETWORK_LANG_DUTCH :Batavica -STR_NETWORK_LANG_ESPERANTO :Esperantica -STR_NETWORK_LANG_FINNISH :Finnica -STR_NETWORK_LANG_HUNGARIAN :Hungarica -STR_NETWORK_LANG_ICELANDIC :Islandica -STR_NETWORK_LANG_ITALIAN :Italiana -STR_NETWORK_LANG_JAPANESE :Iaponica -STR_NETWORK_LANG_KOREAN :Coreana -STR_NETWORK_LANG_LITHUANIAN :Lithuanica -STR_NETWORK_LANG_NORWEGIAN :Norvegica -STR_NETWORK_LANG_POLISH :Polonica -STR_NETWORK_LANG_PORTUGUESE :Lusitana -STR_NETWORK_LANG_ROMANIAN :Romanica -STR_NETWORK_LANG_RUSSIAN :Russica -STR_NETWORK_LANG_SLOVAK :Slovaca -STR_NETWORK_LANG_SLOVENIAN :Slovena -STR_NETWORK_LANG_SPANISH :Hispanica -STR_NETWORK_LANG_SWEDISH :Suecica -STR_NETWORK_LANG_TURKISH :Turcica -STR_NETWORK_LANG_UKRAINIAN :Ucrainica -STR_NETWORK_LANG_AFRIKAANS :Africana -STR_NETWORK_LANG_CROATIAN :Croatica -STR_NETWORK_LANG_CATALAN :Catalana -STR_NETWORK_LANG_ESTONIAN :Estonica -STR_NETWORK_LANG_GALICIAN :Gallaica -STR_NETWORK_LANG_GREEK :Graeca -STR_NETWORK_LANG_LATVIAN :Lettonica -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Atrium Plurium Lusorum @@ -2250,19 +2208,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Disiunge STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servatrum tutum est. Tesseram inscribe STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Societas tuta est. Tesseram inscribe -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Index clientum # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Index clientum -STR_NETWORK_COMPANY_LIST_SPECTATE :Spectare -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Societas Nova # Network client list -STR_NETWORK_CLIENTLIST_KICK :Dimittere -STR_NETWORK_CLIENTLIST_BAN :Expellere -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Ad omnes loqui -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Ad societatem loqui -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Ad clientem loqui + + STR_NETWORK_SERVER :Servatrum STR_NETWORK_CLIENT :Cliens diff --git a/src/lang/latvian.txt b/src/lang/latvian.txt index 73bf27de60..259b10b31d 100644 --- a/src/lang/latvian.txt +++ b/src/lang/latvian.txt @@ -1004,6 +1004,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Ekrāna STR_GAME_OPTIONS_RESOLUTION_OTHER :Cita + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Lietotāja saskarnes lielums STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Lietotāja saskarnes elementu lieluma izvēle @@ -1959,6 +1960,7 @@ STR_FACE_TIE :Kaklasaite: STR_FACE_EARRING :Auskars: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Mainīt kaklasaiti vai auskarus + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Vairākspēlētāju spēle STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spēlētāja vārds: @@ -2021,10 +2023,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Spēles STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Uzstādīt paroli STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Aizsargā jūsu spēli ar paroli, ja nevēlaties lai tā būtu publiski pieejama -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Izsludināt -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Izvēlieties starp reklamēto (interneta) un nereklamēto (lokālā tīkla, LAN) spēli -STR_NETWORK_START_SERVER_UNADVERTISED :Nē -STR_NETWORK_START_SERVER_ADVERTISED :Jā STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} spēlētāj{P s i u} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maksimālais spēlētāju skaits: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Izvēlēties maksimālo spēlētāju skaitu. Ne visiem slotiem ir jābūt aizpildītiem @@ -2039,46 +2037,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Citi lie STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Ievadīt tīkla spēles nosaukumu -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Jebkura -STR_NETWORK_LANG_ENGLISH :Angļu -STR_NETWORK_LANG_GERMAN :Vācu -STR_NETWORK_LANG_FRENCH :Franču -STR_NETWORK_LANG_BRAZILIAN :Brazīļu -STR_NETWORK_LANG_BULGARIAN :Bulgāru -STR_NETWORK_LANG_CHINESE :Ķīniešu -STR_NETWORK_LANG_CZECH :Čehu -STR_NETWORK_LANG_DANISH :Dāņu -STR_NETWORK_LANG_DUTCH :Holandiešu -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Somu -STR_NETWORK_LANG_HUNGARIAN :Ungāru -STR_NETWORK_LANG_ICELANDIC :Īslandiešu -STR_NETWORK_LANG_ITALIAN :Itāliešu -STR_NETWORK_LANG_JAPANESE :Japāņu -STR_NETWORK_LANG_KOREAN :Korejiešu -STR_NETWORK_LANG_LITHUANIAN :Lietuviešu -STR_NETWORK_LANG_NORWEGIAN :Norvēģu -STR_NETWORK_LANG_POLISH :Poļu -STR_NETWORK_LANG_PORTUGUESE :Portugāļu -STR_NETWORK_LANG_ROMANIAN :Rumāņu -STR_NETWORK_LANG_RUSSIAN :Krievu -STR_NETWORK_LANG_SLOVAK :Slovāku -STR_NETWORK_LANG_SLOVENIAN :Slovēņu -STR_NETWORK_LANG_SPANISH :Spāņu -STR_NETWORK_LANG_SWEDISH :Zviedru -STR_NETWORK_LANG_TURKISH :Turku -STR_NETWORK_LANG_UKRAINIAN :Ukraiņu -STR_NETWORK_LANG_AFRIKAANS :Āfrikāņu -STR_NETWORK_LANG_CROATIAN :Horvātu -STR_NETWORK_LANG_CATALAN :Kataloņu -STR_NETWORK_LANG_ESTONIAN :Igauņu -STR_NETWORK_LANG_GALICIAN :Galisiešu -STR_NETWORK_LANG_GREEK :Grieķu -STR_NETWORK_LANG_LATVIAN :Latviešu -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Vairākspēlētāju spēles vestibils @@ -2126,19 +2084,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Atvienot STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Serveris ir aizsargāts. Ievadiet paroli STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Uzņēmums ir aizsargāts. Ievadiet paroli -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Klientu saraksts # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spēlētāju saraksts -STR_NETWORK_COMPANY_LIST_SPECTATE :Skatīt -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Jauns uzņēmums # Network client list -STR_NETWORK_CLIENTLIST_KICK :Izmest -STR_NETWORK_CLIENTLIST_BAN :Aizliegt -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Runāt ar visiem -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Runāt ar uzņēmumu -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privāts ziņojums + + STR_NETWORK_SERVER :Serveris STR_NETWORK_CLIENT :Spēlētājs diff --git a/src/lang/lithuanian.txt b/src/lang/lithuanian.txt index b142248989..bfb74b6965 100644 --- a/src/lang/lithuanian.txt +++ b/src/lang/lithuanian.txt @@ -1211,6 +1211,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Aparatin STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Pažymėkite šį langelį, jei norite, kad OpenTTD taikytų aparatinį spartinimą. Kad nuostata įsigaliotų, reiks perkrauti OpenTTD STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Kad pakeitimai įsigaliotų, reikia paleisti OpenTTD iš naujo + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Sąsajos elementų dydis STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Pasirinkite vartotojo sąsajos elementų santykinį dydį @@ -2203,6 +2204,7 @@ STR_FACE_TIE :Kaklaraištis: STR_FACE_EARRING :Auskaras: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Pakeisti kaklaraištį arba auskarą + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Žaidimas tinkle STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Žaidėjo vardas: @@ -2265,10 +2267,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Žaidimo STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Nustatyti slaptažodi STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Apsaugokite savo žaidimą slaptažodžiu, jei nenorite, kad jis būtų viešai prieinamas -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Reklamuoti -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Pasirinkite tarp reklamuojamo (internetas) ir nereklamuojamo (Vietinis Tinklas, LAN) žaidimo -STR_NETWORK_START_SERVER_UNADVERTISED :Ne -STR_NETWORK_START_SERVER_ADVERTISED :Taip STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P as ai ų} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Didžiausias klientų skaičius: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Pasirinkite didžiausią klientų skaičių. Nebūtinai visos jungtys turi būti užpildytos @@ -2283,46 +2281,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Kiti ža STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Įveskite tinklo žaidimo pavadinimą -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Bet kokia -STR_NETWORK_LANG_ENGLISH :Anglų -STR_NETWORK_LANG_GERMAN :Vokiečių -STR_NETWORK_LANG_FRENCH :Prancūzų -STR_NETWORK_LANG_BRAZILIAN :Brazilų -STR_NETWORK_LANG_BULGARIAN :Bulgarų -STR_NETWORK_LANG_CHINESE :Kinų -STR_NETWORK_LANG_CZECH :Čekų -STR_NETWORK_LANG_DANISH :Danų -STR_NETWORK_LANG_DUTCH :Olandų -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Suomių -STR_NETWORK_LANG_HUNGARIAN :Vengrų -STR_NETWORK_LANG_ICELANDIC :Islandų -STR_NETWORK_LANG_ITALIAN :Italų -STR_NETWORK_LANG_JAPANESE :Japonų -STR_NETWORK_LANG_KOREAN :Korėjiečių -STR_NETWORK_LANG_LITHUANIAN :Lietuvių -STR_NETWORK_LANG_NORWEGIAN :Norvegų -STR_NETWORK_LANG_POLISH :Lenkų -STR_NETWORK_LANG_PORTUGUESE :Portugalų -STR_NETWORK_LANG_ROMANIAN :Rumunų -STR_NETWORK_LANG_RUSSIAN :Rusų -STR_NETWORK_LANG_SLOVAK :Slovakų -STR_NETWORK_LANG_SLOVENIAN :Slovėnų -STR_NETWORK_LANG_SPANISH :Ispanų -STR_NETWORK_LANG_SWEDISH :Švedų -STR_NETWORK_LANG_TURKISH :Turkų -STR_NETWORK_LANG_UKRAINIAN :Ukrainiečių -STR_NETWORK_LANG_AFRIKAANS :Afrikiečių -STR_NETWORK_LANG_CROATIAN :Kroatų -STR_NETWORK_LANG_CATALAN :Katalonų -STR_NETWORK_LANG_ESTONIAN :Estų -STR_NETWORK_LANG_GALICIAN :Galicijos -STR_NETWORK_LANG_GREEK :Graikų -STR_NETWORK_LANG_LATVIAN :Latvių -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Kelių žaidėjų meniu @@ -2370,19 +2328,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Atsijung STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Serveris apsaugotas. Įvesk slaptažodį STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Kompanija apsaugota. Įvesk slaptažodį -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Žaidėjų sąrašas # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Žaidėjų sąrašas -STR_NETWORK_COMPANY_LIST_SPECTATE :Stebėti -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nauja įmonė # Network client list -STR_NETWORK_CLIENTLIST_KICK :Išmesti (Kick) -STR_NETWORK_CLIENTLIST_BAN :Užblokuoti -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Sakyti visiems -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Sakyti kompanijai -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privati žinutė + + STR_NETWORK_SERVER :Serveris STR_NETWORK_CLIENT :Žaidėjas diff --git a/src/lang/luxembourgish.txt b/src/lang/luxembourgish.txt index e81bd41e94..2d712f7852 100644 --- a/src/lang/luxembourgish.txt +++ b/src/lang/luxembourgish.txt @@ -1006,6 +1006,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardware STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Dës Optioun wielen, dass OpenTTD Hardwarebeschleunigung dierf notzen. Wäert just geännert ginn wann d'Spill nei gestart gëtt STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}D'Astellung huet réicht en Afloss no engem Neistart vum Spill + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Interfacegréisst STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Wiel d'Gréisst déi fir den Interface soll benotzt ginn @@ -1984,6 +1985,7 @@ STR_FACE_TIE :Krawatt: STR_FACE_EARRING :Ouerréng: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Krawatt oder Ouerréng änneren + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spillernumm: @@ -2046,10 +2048,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Den Numm STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Passwuert setzen STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}En Passwuert fir d'Spill setzen, dass et net Public accessibel ass -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Ugekënnegt -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Wiel tëschent engem ugekënnegten (Internet) an net ugekënnegten (LAN) Spill -STR_NETWORK_START_SERVER_UNADVERTISED :Nee -STR_NETWORK_START_SERVER_ADVERTISED :Jo STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} Spiller STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximal Spiller: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Maximal Unzuel vun de Clients. Et muss net all Slot gefëllt sinn. @@ -2064,46 +2062,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aner Lei STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Gëff en Numm fir d'Spill un -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Egal -STR_NETWORK_LANG_ENGLISH :Englesch -STR_NETWORK_LANG_GERMAN :Däitsch -STR_NETWORK_LANG_FRENCH :Franséisch -STR_NETWORK_LANG_BRAZILIAN :Brasilianesch -STR_NETWORK_LANG_BULGARIAN :Bulgaresch -STR_NETWORK_LANG_CHINESE :Chinesesch -STR_NETWORK_LANG_CZECH :Tschechesch -STR_NETWORK_LANG_DANISH :Dänesch -STR_NETWORK_LANG_DUTCH :Holländesch -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finnesch -STR_NETWORK_LANG_HUNGARIAN :Ungaresch -STR_NETWORK_LANG_ICELANDIC :Isländesch -STR_NETWORK_LANG_ITALIAN :Italienesch -STR_NETWORK_LANG_JAPANESE :Japanesch -STR_NETWORK_LANG_KOREAN :Koreanesch -STR_NETWORK_LANG_LITHUANIAN :Litauesch -STR_NETWORK_LANG_NORWEGIAN :Norwegesch -STR_NETWORK_LANG_POLISH :Polnesch -STR_NETWORK_LANG_PORTUGUESE :Portugiesesch -STR_NETWORK_LANG_ROMANIAN :Rumänesch -STR_NETWORK_LANG_RUSSIAN :Russesch -STR_NETWORK_LANG_SLOVAK :Slovakesch -STR_NETWORK_LANG_SLOVENIAN :Slovenesch -STR_NETWORK_LANG_SPANISH :Spuenesch -STR_NETWORK_LANG_SWEDISH :Schwedesch -STR_NETWORK_LANG_TURKISH :Türkesch -STR_NETWORK_LANG_UKRAINIAN :Ukrainesch -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatesch -STR_NETWORK_LANG_CATALAN :Katalanesch -STR_NETWORK_LANG_ESTONIAN :Estnesch -STR_NETWORK_LANG_GALICIAN :Gälesch -STR_NETWORK_LANG_GREEK :Griechesch -STR_NETWORK_LANG_LATVIAN :Lettesch -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Multiplayer-Spill Lobby @@ -2151,19 +2109,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Verbindu STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server ass geschützt. Passwuert aginn STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firma ass geschützt. Passwuert aginn -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Spillerlëscht # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spillerlëscht -STR_NETWORK_COMPANY_LIST_SPECTATE :Nokucken -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nei Firma # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kicken -STR_NETWORK_CLIENTLIST_BAN :Bannen -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Mat alle schwetzen -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Mat der Firma schwetzen -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatmessage + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Spiller diff --git a/src/lang/unfinished/macedonian.txt b/src/lang/macedonian.txt similarity index 99% rename from src/lang/unfinished/macedonian.txt rename to src/lang/macedonian.txt index a4614cb1f9..844bfd0a36 100644 --- a/src/lang/unfinished/macedonian.txt +++ b/src/lang/macedonian.txt @@ -804,6 +804,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_1_MONTH :Секој ме + # Custom currency window @@ -959,6 +960,7 @@ STR_ABANDON_GAME_QUERY :{YELLOW}Дал # Face selection window + # Network server list STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} @@ -974,10 +976,6 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x -# Network game languages -############ Leave those lines in this order!! -############ End of leave-in-this-order - # Network game lobby @@ -997,6 +995,8 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x # Network client list + + # Network set password # Network company info join/password diff --git a/src/lang/malay.txt b/src/lang/malay.txt index 5fff6dd202..f678671e99 100644 --- a/src/lang/malay.txt +++ b/src/lang/malay.txt @@ -944,6 +944,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Pilih re STR_GAME_OPTIONS_RESOLUTION_OTHER :lain + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Saiz Antaramuka STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Sila pilih saiz elemen antara muka untuk digunakan @@ -1630,6 +1631,7 @@ STR_FACE_TIE :Tali leher: STR_FACE_EARRING :Anting-anting: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Tukar tali leher atau anting-anting + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Pemain berbilang STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nama pemain: @@ -1688,7 +1690,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Nama per STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Tetapkan kata laluan STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Lindungi permainan anda dengan kata laluan jika anda tidak mahu ianya diakses awam -STR_NETWORK_START_SERVER_UNADVERTISED :Tidak STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} pelanggan STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Amaun maksimum pemain: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Tentukan bilangan klien maks. Tidak perlu semua slot diisi @@ -1703,46 +1704,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Pemain l STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Masukkan nama untuk permainan rangkaian -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Mana-mana -STR_NETWORK_LANG_ENGLISH :Inggeris -STR_NETWORK_LANG_GERMAN :Jerman -STR_NETWORK_LANG_FRENCH :Perancis -STR_NETWORK_LANG_BRAZILIAN :Brazil -STR_NETWORK_LANG_BULGARIAN :Bulgaria -STR_NETWORK_LANG_CHINESE :Cina -STR_NETWORK_LANG_CZECH :Czech -STR_NETWORK_LANG_DANISH :Denmark -STR_NETWORK_LANG_DUTCH :Belanda -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finland -STR_NETWORK_LANG_HUNGARIAN :Hungary -STR_NETWORK_LANG_ICELANDIC :Iceland -STR_NETWORK_LANG_ITALIAN :Itali -STR_NETWORK_LANG_JAPANESE :Jepun -STR_NETWORK_LANG_KOREAN :Korea -STR_NETWORK_LANG_LITHUANIAN :Lituania -STR_NETWORK_LANG_NORWEGIAN :Norway -STR_NETWORK_LANG_POLISH :Poland -STR_NETWORK_LANG_PORTUGUESE :Portugis -STR_NETWORK_LANG_ROMANIAN :Romania -STR_NETWORK_LANG_RUSSIAN :Rusia -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenia -STR_NETWORK_LANG_SPANISH :Sepanyol -STR_NETWORK_LANG_SWEDISH :Sweden -STR_NETWORK_LANG_TURKISH :Turki -STR_NETWORK_LANG_UKRAINIAN :Ukraine -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croatia -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonia -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :Yunani -STR_NETWORK_LANG_LATVIAN :Latvia -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Ruang tunggu berbilang pemain @@ -1793,15 +1754,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Syarikat # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Senarai klien -STR_NETWORK_COMPANY_LIST_SPECTATE :Saksi -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Syarikat baru # Network client list -STR_NETWORK_CLIENTLIST_KICK :Tendang -STR_NETWORK_CLIENTLIST_BAN :Larang -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Cakap kepada semua -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Cakap kepada syarikat -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Pesanan peribadi + + STR_NETWORK_SERVER :Pelayan STR_NETWORK_CLIENT :Klien diff --git a/src/lang/unfinished/maltese.txt b/src/lang/maltese.txt similarity index 99% rename from src/lang/unfinished/maltese.txt rename to src/lang/maltese.txt index 7261c292f2..58f13463c4 100644 --- a/src/lang/unfinished/maltese.txt +++ b/src/lang/maltese.txt @@ -417,6 +417,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :oħrajn + # Custom currency window @@ -527,6 +528,7 @@ STR_CHEAT_CHANGE_DATE_QUERY_CAPT :{WHITE}Ibdel is # Face selection window + # Network server list STR_NETWORK_SERVER_LIST_GENERAL_ONLINE :{BLACK}{COMMA}/{COMMA} - {COMMA}/{COMMA} @@ -542,10 +544,6 @@ STR_NETWORK_SERVER_LIST_MAP_SIZE_SHORT :{BLACK}{COMMA}x -# Network game languages -############ Leave those lines in this order!! -############ End of leave-in-this-order - # Network game lobby @@ -567,6 +565,8 @@ STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} # Network client list + + # Network set password # Network company info join/password diff --git a/src/lang/unfinished/marathi.txt b/src/lang/marathi.txt similarity index 97% rename from src/lang/unfinished/marathi.txt rename to src/lang/marathi.txt index f7717c2c0e..8f4c7fbac3 100644 --- a/src/lang/unfinished/marathi.txt +++ b/src/lang/marathi.txt @@ -757,6 +757,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :अन्य + # Custom currency window @@ -891,6 +892,7 @@ STR_FACE_LIPS_MOUSTACHE_TOOLTIP :{BLACK}ओठ STR_FACE_CHIN :हनुवटी: STR_FACE_CHIN_TOOLTIP :{BLACK}हनुवटी बदला + # Network server list STR_NETWORK_SERVER_LIST_GAME_NAME :{BLACK}नाव @@ -910,37 +912,6 @@ STR_NETWORK_SERVER_LIST_LANGUAGE :{SILVER}भा -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ENGLISH :इंग्रजी -STR_NETWORK_LANG_GERMAN :जर्मन -STR_NETWORK_LANG_FRENCH :फ्रेंच -STR_NETWORK_LANG_BRAZILIAN :ब्रज़िलिअन -STR_NETWORK_LANG_BULGARIAN :बल्जेरिअन -STR_NETWORK_LANG_CHINESE :चिनी -STR_NETWORK_LANG_CZECH :झेख -STR_NETWORK_LANG_DANISH :डेनिश -STR_NETWORK_LANG_DUTCH :डच -STR_NETWORK_LANG_ESPERANTO :एस्परांतो -STR_NETWORK_LANG_FINNISH :फिन्निश -STR_NETWORK_LANG_HUNGARIAN :हंगेरियन -STR_NETWORK_LANG_ICELANDIC :आईसलेंडीक -STR_NETWORK_LANG_JAPANESE :जपानी -STR_NETWORK_LANG_POLISH :पोलिश -STR_NETWORK_LANG_PORTUGUESE :पोर्चुगीस -STR_NETWORK_LANG_ROMANIAN :रोमेनिअन -STR_NETWORK_LANG_RUSSIAN :रशिअन -STR_NETWORK_LANG_SLOVAK :स्लोवेक -STR_NETWORK_LANG_SLOVENIAN :स्लोवेनिअन -STR_NETWORK_LANG_SPANISH :स्पेनिश -STR_NETWORK_LANG_SWEDISH :स्वीडिश -STR_NETWORK_LANG_TURKISH :तुर्की -STR_NETWORK_LANG_UKRAINIAN :युक्रेनिअन -STR_NETWORK_LANG_AFRIKAANS :आफ्रिकान्स -STR_NETWORK_LANG_CROATIAN :क्रोएशिअन -STR_NETWORK_LANG_GREEK :ग्रीक -############ End of leave-in-this-order - # Network game lobby @@ -964,6 +935,8 @@ STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} # Network client list + + # Network set password # Network company info join/password diff --git a/src/lang/norwegian_bokmal.txt b/src/lang/norwegian_bokmal.txt index 8b9cd410a9..886efdcf77 100644 --- a/src/lang/norwegian_bokmal.txt +++ b/src/lang/norwegian_bokmal.txt @@ -955,7 +955,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Malaysisk Ringg STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Venstrekjøring STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Høyrekjøring -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Bynavn +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Bynavn: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Velg nasjonalitet på bynavn ############ start of townname region @@ -995,6 +995,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Hver 12. måned STR_GAME_OPTIONS_LANGUAGE :{BLACK}Språk STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Velg språk som skal brukes +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% fullført) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Fullskjerm STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Kryss av denne knappen for å spille OpenTTD i fullskjermmodus @@ -1008,6 +1009,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Maskinva STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Merk av i denne boksen for å la OpenTTD prøve å bruke maskinvareakselerasjon. En endret innstilling blir bare brukt ved omstart av spillet STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Innstillingen vil ikke tre i kraft før spillet er restartet +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Merk av i denne boksen for å v-synkronisere skjermen. Endring av innstillinger krever omstart av spillet. Fungerer bare med maskinvareakselerasjon aktivert + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Grensesnitt-størrelse STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Velg grensesnitt-størrelsen som skal benyttes @@ -1140,6 +1144,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Innstill STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrer streng: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Vis alle STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Skjul alle +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Tilbakestill alle verdier STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(ingen forklaring tilgjengelig) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standard verdi: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Instillings type: {ORANGE}{STRING} @@ -1148,6 +1153,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Selskapet innst STR_CONFIG_SETTING_TYPE_GAME_INGAME :Selskapet innstilling (lagret i lagringsfilen, påvirker bare gjeldende spill) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Selskapet innstilling (lagret i lagringsfilen, påvirker bare nye spill) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Selskapet innstilling (lagret i lagringsfilen, påvirker bare gjeldende selskap) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Advarsel! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Denne handlingen vil tilbakestille alle spillinnstillingene til standard verdier.{}Er du sikker på at du vil fortsette? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategori: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Type: @@ -1987,6 +1994,9 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Ørering: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Endre slips eller ørering +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privat +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Offentlig + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Flerspiller STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spillernavn: @@ -2049,10 +2059,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Spillnav STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Sett passord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskytt ditt spill med et passord hvis du ikke vil at hvem som helst skal bli med på det -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Annonsert -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Velg mellom et utlyst (internett) og et ikke utlyst (Lokalnettverk, LAN) spill -STR_NETWORK_START_SERVER_UNADVERTISED :Nei -STR_NETWORK_START_SERVER_ADVERTISED :Ja +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Synlighet +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Om andre mennesker kan se serveren din i den offentlige oppføringen STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maks antall klienter: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS.small :dra og slipp @@ -2068,46 +2076,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Andre sp STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Skriv inn et navn for nettverksspillet -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Hvilket som helst -STR_NETWORK_LANG_ENGLISH :Engelsk -STR_NETWORK_LANG_GERMAN :Tysk -STR_NETWORK_LANG_FRENCH :Fransk -STR_NETWORK_LANG_BRAZILIAN :Brasiliansk -STR_NETWORK_LANG_BULGARIAN :Bulgarsk -STR_NETWORK_LANG_CHINESE :Kinesisk -STR_NETWORK_LANG_CZECH :Tsjekkisk -STR_NETWORK_LANG_DANISH :Dansk -STR_NETWORK_LANG_DUTCH :Nederlandsk -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finsk -STR_NETWORK_LANG_HUNGARIAN :Ungarsk -STR_NETWORK_LANG_ICELANDIC :Islandsk -STR_NETWORK_LANG_ITALIAN :Italiensk -STR_NETWORK_LANG_JAPANESE :Japansk -STR_NETWORK_LANG_KOREAN :Koreansk -STR_NETWORK_LANG_LITHUANIAN :Litauisk -STR_NETWORK_LANG_NORWEGIAN :Norsk -STR_NETWORK_LANG_POLISH :Polsk -STR_NETWORK_LANG_PORTUGUESE :Portugisisk -STR_NETWORK_LANG_ROMANIAN :Rumensk -STR_NETWORK_LANG_RUSSIAN :Russisk -STR_NETWORK_LANG_SLOVAK :Slovakisk -STR_NETWORK_LANG_SLOVENIAN :Slovensk -STR_NETWORK_LANG_SPANISH :Spansk -STR_NETWORK_LANG_SWEDISH :Svensk -STR_NETWORK_LANG_TURKISH :Tyrkisk -STR_NETWORK_LANG_UKRAINIAN :Ukrainsk -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatisk -STR_NETWORK_LANG_CATALAN :Katalansk -STR_NETWORK_LANG_ESTONIAN :Estisk -STR_NETWORK_LANG_GALICIAN :Galicisk -STR_NETWORK_LANG_GREEK :Gresk -STR_NETWORK_LANG_LATVIAN :Latvisk -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Flerspillerlobby @@ -2155,19 +2123,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Koble fr STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Tjeneren er beskyttet. Skriv inn passord STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firmaet er beskyttet. Skriv inn passord -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Klientliste # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste over klienter -STR_NETWORK_COMPANY_LIST_SPECTATE :Vær tilskuer -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nytt firma +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Påloggede spillere # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kast ut -STR_NETWORK_CLIENTLIST_BAN :Bannlys -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Snakk til alle -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Snakk til firma -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privat melding +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Flerspiller +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Server +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Navn +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Navnet på serveren du spiller på +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Rediger navnet på serveren +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Servernavn +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Synlighet +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Om andre mennesker kan se serveren din i den offentlige oppføringen +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Spiller +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Navn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Ditt spillernavn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Rediger ditt spillernavn +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Ditt spillernavn +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Administrative handlinger å utføre for denne klienten +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Administrative tiltak å utføre for dette firmaet +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Bli med i dette firmaet +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Send en melding til denne spilleren +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Send en melding til alle spillerne i dette firmaet +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Send en melding til alle tilskuerne +STR_NETWORK_CLIENT_LIST_SPECTATORS :Tilskuere +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nytt firma) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Opprett et nytt firma og bli med i det +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Dette er deg +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Dette er verten for spillet + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Spark +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Utesteng +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Slett +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Låse opp passord + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Administratorhandling +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Er du sikker på at du vil utestenge spiller '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Er du sikker på at du vil utestenge spiller '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Er du sikker på at du vil slette firmaet '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Er du sikker på at du vil tilbakestille passordet til firma '{COMPANY}'? STR_NETWORK_SERVER :Tjener STR_NETWORK_CLIENT :Klient @@ -2212,6 +2207,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Kunne ik STR_NETWORK_ERROR_CLIENT_START :{WHITE}Kunne ikke opprette forbindelse STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tilkobling #{NUM} ble tidsavbrutt STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Forbindelsen ble brutt pga. en protokollfeil +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Spillernavnet ditt er ikke angitt. Navnet kan angis øverst i flerspillervinduet STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Klientversjonen er ikke den samme som tjenerversjonen STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Feil passord STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Tjeneren er full @@ -2224,6 +2220,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Du brukt STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Din datamaskin er ikke rask nok til å holde følge med tjeneren STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Din datamaskin brukte for lang tid på å laste ned kartet STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Din datamaskin brukte for lang tid på å koble til tjeneren +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Spillernavnet ditt er ugyldig ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :generell feil @@ -2246,6 +2243,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :mottok ikke pas STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :generelt tidsavbrudd STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :nedlasting av kart tok for lang tid STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :behandling av kartet tok for lang tid +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :ugyldig klientnavn ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Mulig tap av tilkobling @@ -2535,7 +2533,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Bygg hav STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Plasser en bøye, som kan brukes til å danne kontrollpunkter. Shift slår av/på kostnadsestimat STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Bygg akvedukt. Shift slår av/på kostnadsestimat STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Definer vannområde.{}Lag en kanal, unntatt hvis Ctrl holdes nede på havnivå, hvorpå området rundt vil fylles istedenfor -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Plasser elver +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Plasser elver. Ctrl velger området diagonalt # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Skipsdokkens retning @@ -3085,6 +3083,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Advarsel: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Feil: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}En fatal NewGRF-feil har oppstått:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}En NewGRF feil har oppstått:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} virker ikke med TTDPatch-versjonen som er rapportert av OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} er for versjon {STRING} av TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} er laget for bruk med {STRING} diff --git a/src/lang/norwegian_nynorsk.txt b/src/lang/norwegian_nynorsk.txt index 30d015bdf6..2fb33fd4c6 100644 --- a/src/lang/norwegian_nynorsk.txt +++ b/src/lang/norwegian_nynorsk.txt @@ -971,6 +971,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Vel skje STR_GAME_OPTIONS_RESOLUTION_OTHER :anna + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Grensesnittstorleik STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Vel storleik å bruke på grensesnittet @@ -1792,6 +1793,7 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Øyrering: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Byt slips eller øyrering + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Fleirspelar STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spelarnamn: @@ -1850,10 +1852,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Spelnamn STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Set passord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Beskytt spelet ditt med passord så ikkje kven som helst kan verte med på det -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Kunngjort -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Vel mellom spel på internett (kunngjort) og spel på lokalt nett (ikkje kunngjort) -STR_NETWORK_START_SERVER_UNADVERTISED :Nei -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maks. antal tilletne klientar: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Vel maks. antal klientar. Alle plassane treng ikkje å verte tekne @@ -1868,46 +1866,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Andre sp STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Gje eit namn til nettverksspelet -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Kva som helst -STR_NETWORK_LANG_ENGLISH :Engelsk -STR_NETWORK_LANG_GERMAN :Tysk -STR_NETWORK_LANG_FRENCH :Fransk -STR_NETWORK_LANG_BRAZILIAN :Brasiliansk -STR_NETWORK_LANG_BULGARIAN :Bulgarsk -STR_NETWORK_LANG_CHINESE :Kinesisk -STR_NETWORK_LANG_CZECH :Tsjekkisk -STR_NETWORK_LANG_DANISH :Dansk -STR_NETWORK_LANG_DUTCH :Nederlandsk -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finsk -STR_NETWORK_LANG_HUNGARIAN :Ungarsk -STR_NETWORK_LANG_ICELANDIC :Islandsk -STR_NETWORK_LANG_ITALIAN :Italiensk -STR_NETWORK_LANG_JAPANESE :Japansk -STR_NETWORK_LANG_KOREAN :Koreansk -STR_NETWORK_LANG_LITHUANIAN :Litauisk -STR_NETWORK_LANG_NORWEGIAN :Norsk -STR_NETWORK_LANG_POLISH :Polsk -STR_NETWORK_LANG_PORTUGUESE :Portugisisk -STR_NETWORK_LANG_ROMANIAN :Rumensk -STR_NETWORK_LANG_RUSSIAN :Russisk -STR_NETWORK_LANG_SLOVAK :Slovakisk -STR_NETWORK_LANG_SLOVENIAN :Slovensk -STR_NETWORK_LANG_SPANISH :Spansk -STR_NETWORK_LANG_SWEDISH :Svensk -STR_NETWORK_LANG_TURKISH :Tyrkisk -STR_NETWORK_LANG_UKRAINIAN :Ukrainsk -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatisk -STR_NETWORK_LANG_CATALAN :Katalansk -STR_NETWORK_LANG_ESTONIAN :Estisk -STR_NETWORK_LANG_GALICIAN :Gælisk -STR_NETWORK_LANG_GREEK :Gresk -STR_NETWORK_LANG_LATVIAN :Latvisk -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Fleirspelarspel-lobby @@ -1958,15 +1916,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firmaet # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Liste over klientar -STR_NETWORK_COMPANY_LIST_SPECTATE :Vær tilskodar -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nytt firma # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kast ut -STR_NETWORK_CLIENTLIST_BAN :Svartelist -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Snakk til alle -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Snakk til firma -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privat melding + + STR_NETWORK_SERVER :Tenar STR_NETWORK_CLIENT :Klient diff --git a/src/lang/unfinished/persian.txt b/src/lang/persian.txt similarity index 98% rename from src/lang/unfinished/persian.txt rename to src/lang/persian.txt index 049ba91447..a6c6a03bcd 100644 --- a/src/lang/unfinished/persian.txt +++ b/src/lang/persian.txt @@ -962,6 +962,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :دیگر + STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :دو برابر @@ -1590,6 +1591,7 @@ STR_FACE_TIE :کراوات: STR_FACE_EARRING :گوشواره: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}تغییر کراوات یا گوشواره + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}چندنفره STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}نام بازیگر: @@ -1648,9 +1650,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}بازی STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}ثبت رمز STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}اگر بازی برای استفاده همگان نیست، بازی خود را با رمز محافظت کنید -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}تبلیغ دار -STR_NETWORK_START_SERVER_UNADVERTISED :خیر -STR_NETWORK_START_SERVER_ADVERTISED :بله STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} سرویس گیرنده STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}بیشترین تعداد سرویس گیرنده: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}بیشترین تعداد سرویس گیرنده را مشخص کنید.لازم نیست دقیقا به تعداد نفرات باشد @@ -1665,46 +1664,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}دیگر STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}برای بازی شبکه‌ای یک نام وارد نمایید -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :هر زبانی -STR_NETWORK_LANG_ENGLISH :انگلیسی -STR_NETWORK_LANG_GERMAN :آلمانی -STR_NETWORK_LANG_FRENCH :فرانسوی -STR_NETWORK_LANG_BRAZILIAN :برزیلی -STR_NETWORK_LANG_BULGARIAN :بلغاری -STR_NETWORK_LANG_CHINESE :چینی -STR_NETWORK_LANG_CZECH :چکی -STR_NETWORK_LANG_DANISH :دانمارکی -STR_NETWORK_LANG_DUTCH :هلندی -STR_NETWORK_LANG_ESPERANTO :اسپرانتو -STR_NETWORK_LANG_FINNISH :فنلاندی -STR_NETWORK_LANG_HUNGARIAN :مجارستانی -STR_NETWORK_LANG_ICELANDIC :ایسلندی -STR_NETWORK_LANG_ITALIAN :ایتالیایی -STR_NETWORK_LANG_JAPANESE :زاپنی -STR_NETWORK_LANG_KOREAN :کُره‌ای -STR_NETWORK_LANG_LITHUANIAN :لیتوانیایی -STR_NETWORK_LANG_NORWEGIAN :نروژی -STR_NETWORK_LANG_POLISH :لهستانی -STR_NETWORK_LANG_PORTUGUESE :پرتغالی -STR_NETWORK_LANG_ROMANIAN :رومانیایی -STR_NETWORK_LANG_RUSSIAN :روسی -STR_NETWORK_LANG_SLOVAK :اسلوواکیایی -STR_NETWORK_LANG_SLOVENIAN :اسلوونیایی -STR_NETWORK_LANG_SPANISH :اسپانیایی -STR_NETWORK_LANG_SWEDISH :سوئدی -STR_NETWORK_LANG_TURKISH :ترکی -STR_NETWORK_LANG_UKRAINIAN :اوکراینی -STR_NETWORK_LANG_AFRIKAANS :آفریقایی -STR_NETWORK_LANG_CROATIAN :کرواسی -STR_NETWORK_LANG_CATALAN :کاتالانی -STR_NETWORK_LANG_ESTONIAN :استوونی -STR_NETWORK_LANG_GALICIAN :گالیسیایی -STR_NETWORK_LANG_GREEK :یونانی -STR_NETWORK_LANG_LATVIAN :لاتویانی -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}سالن انتظار بازی چندنفره @@ -1755,15 +1714,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}شرکت # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}لیست سرویس گیرنده ها -STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}تماشا -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}شرکت جدید # Network client list -STR_NETWORK_CLIENTLIST_KICK :اخراج -STR_NETWORK_CLIENTLIST_BAN :قدغن کردن -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :گفتگو با همه -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :گفتگو با شرکت -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :پیام خصوصی + + STR_NETWORK_SERVER :سرویس دهنده STR_NETWORK_CLIENT :سرویس گیرنده diff --git a/src/lang/polish.txt b/src/lang/polish.txt index 2012eff99d..0161b59550 100644 --- a/src/lang/polish.txt +++ b/src/lang/polish.txt @@ -1373,6 +1373,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Co 12 miesięcy STR_GAME_OPTIONS_LANGUAGE :{BLACK}Język STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Wybierz język interfejsu +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} (ukończono {NUM}%) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pełny ekran STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Zaznacz, jeśli chcesz grać w OpenTTD w trybie pełnoekranowym @@ -1386,6 +1387,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Przyspie STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Zaznacz to pole, aby zezwolić OpenTTD na użycie przyspieszenia sprzętowego. Ustawienia zostaną zastosowane dopiero po ponownym uruchomieniu gry. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Ustawienie to zacznie obowiązywać dopiero po ponownym uruchomieniu gry. +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Synchronizacja pionowa +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Zaznacz to pole aby włączyć synchronizację pionową. Zmiany zostaną zastosowane po restarcie gry. Działa tylko z włączoną akceleracją sprzętową. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Rozmiar interfejsu STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Wybierz rozmiar elementów interfejsu @@ -1518,6 +1522,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Ustawien STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrowanie po frazie: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Otwórz wszystko STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Zamknij wszystko +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Zresetuj wszystkie ustawienia STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(wyjaśnienie niedostępne) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Domyślna wartość: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Typ ustawienia: {ORANGE}{STRING} @@ -1526,6 +1531,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Ustawienie gry STR_CONFIG_SETTING_TYPE_GAME_INGAME :Ustawienie gry (przechowywane w pliku zapisu; ma wpływ tylko na aktualną grę) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Ustawienie firmy (przechowywane w plikach zapisu; ma wpływ tylko na nowe gry) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Ustawienie firmy (przechowywane w pliku zapisu; ma wpływ tylko na aktualną firmę) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Uwaga! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Wszystkie ustawienia zostaną przywrócone do wartości domyślnych.{}Jesteś pewien czy chcesz kontynuować? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Typ: @@ -2364,6 +2371,7 @@ STR_FACE_TIE :Krawat: STR_FACE_EARRING :Kolczyk: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Zmień krawat lub kolczyk + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Gra wieloosobowa STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nazwa gracza: @@ -2406,10 +2414,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Przyłą STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Odśwież serwer STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Odśwież informacje o serwerze -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :Przeszukaj internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Przeszukaj internet STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Znajdź w internecie serwery publiczne -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :Przeszukaj LAN -STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :Znajdź serwery w sieci lokalnej +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Przeszukaj LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Znajdź serwery w sieci lokalnej STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Zapisz serwer STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Zapisz serwer na liście serwerów, które będą zawsze sprawdzane w poszukiwaniu uruchomionych gier STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Uruchom serwer @@ -2426,10 +2434,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Nazwa gr STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Ustaw hasło STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Zabezpiecz grę hasłem jeśli nie chcesz, by była publicznie dostępna -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Publiczny -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Wybierz między rozgrywkami reklamowanymi (internetowymi) a niereklamowanymi (w sieci lokalnej LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Nie -STR_NETWORK_START_SERVER_ADVERTISED :Tak STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" ów ów} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Dopuszczalna liczba klientów: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Ustaw maksymalną liczbę klientów. Nie wszystkie pola muszą być wypełnione. @@ -2444,46 +2448,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Inni gra STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Wpisz nazwę dla gry sieciowej -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Dowolny -STR_NETWORK_LANG_ENGLISH :Angielski -STR_NETWORK_LANG_GERMAN :Niemiecki -STR_NETWORK_LANG_FRENCH :Francuski -STR_NETWORK_LANG_BRAZILIAN :Brazylijski -STR_NETWORK_LANG_BULGARIAN :Bułgarski -STR_NETWORK_LANG_CHINESE :Chiński -STR_NETWORK_LANG_CZECH :Czeski -STR_NETWORK_LANG_DANISH :Duński -STR_NETWORK_LANG_DUTCH :Holenderski -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fiński -STR_NETWORK_LANG_HUNGARIAN :Węgierski -STR_NETWORK_LANG_ICELANDIC :Islandzki -STR_NETWORK_LANG_ITALIAN :Włoski -STR_NETWORK_LANG_JAPANESE :Japoński -STR_NETWORK_LANG_KOREAN :Koreański -STR_NETWORK_LANG_LITHUANIAN :Litewski -STR_NETWORK_LANG_NORWEGIAN :Norweski -STR_NETWORK_LANG_POLISH :Polski -STR_NETWORK_LANG_PORTUGUESE :Portugalski -STR_NETWORK_LANG_ROMANIAN :Rumuński -STR_NETWORK_LANG_RUSSIAN :Rosyjski -STR_NETWORK_LANG_SLOVAK :Słowacki -STR_NETWORK_LANG_SLOVENIAN :Słoweński -STR_NETWORK_LANG_SPANISH :Hiszpański -STR_NETWORK_LANG_SWEDISH :Szwedzki -STR_NETWORK_LANG_TURKISH :Turecki -STR_NETWORK_LANG_UKRAINIAN :Ukraiński -STR_NETWORK_LANG_AFRIKAANS :Afrykanerski -STR_NETWORK_LANG_CROATIAN :Chorwacki -STR_NETWORK_LANG_CATALAN :Kataloński -STR_NETWORK_LANG_ESTONIAN :Estoński -STR_NETWORK_LANG_GALICIAN :Galicyjski -STR_NETWORK_LANG_GREEK :Grecki -STR_NETWORK_LANG_LATVIAN :Łotewski -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Rozpoczęcie gry wieloosobowej @@ -2531,19 +2495,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Rozłąc STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Serwer jest chroniony. Wprowadź hasło STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Firma jest chroniona. Wprowadź hasło -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista klientów # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista klientów -STR_NETWORK_COMPANY_LIST_SPECTATE :Obserwuj -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nowa firma # Network client list -STR_NETWORK_CLIENTLIST_KICK :Wyrzuć -STR_NETWORK_CLIENTLIST_BAN :Banuj -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Mów do wszystkich -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Mów do firmy -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Prywatna wiadomość + + STR_NETWORK_SERVER :Serwer STR_NETWORK_CLIENT :Klient @@ -2911,7 +2869,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Zbuduj p STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Ustaw boję, która może być użyta jako pkt. orientacyjny. Shift przełącza pomiędzy trybem budowania a szacowaniem jego kosztów STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Zbuduj akwedukt. Shift przełącza pomiędzy trybem budowania a szacowaniem jego kosztów STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Stwórz akwen wodny.{}Tworzy kanał, chyba że przyrzymany jest CTRL na poziomie morza, wtedy pobliski teren zostanie zatopiony -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Umieszczanie rzek +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Umieszczanie rzek. Ctrl zaznacza obszar po przekątnej. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Ukierunkowanie stoczni diff --git a/src/lang/portuguese.txt b/src/lang/portuguese.txt index f8a0d09078..99a92f78e2 100644 --- a/src/lang/portuguese.txt +++ b/src/lang/portuguese.txt @@ -242,7 +242,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Fechar j STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Título da janela - arraste isto para mover a janela STR_TOOLTIP_SHADE :{BLACK}Encolher janela - apenas mostra a barra de título STR_TOOLTIP_DEBUG :{BLACK}Mostrar informação de depuração de NewGRF -STR_TOOLTIP_DEFSIZE :{BLACK}Reajusta janela para tamanho por defeito. Ctrl+Clique para manter o tamanho actual como o por defeito +STR_TOOLTIP_DEFSIZE :{BLACK}Redimensionar a janela para o tamanho padrão. Ctrl+Clique para guardar o tamanho atual como padrão STR_TOOLTIP_STICKY :{BLACK}Marcar esta janela como não-encerrável pela tecla 'Fechar Todas as Janelas'. Ctrl+Clique para tambem salvar o estado como por omissão STR_TOOLTIP_RESIZE :{BLACK}Clique e arraste para reajustar janela STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Alternar entre janela grande/pequena @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit da Mal STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Circular pela esquerda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Circular pela direita -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das localidades +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nomes das localidades: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Seleccionar o estilo dos nomes das localidades ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Seleccionar o idioma da interface do jogo +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completado) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Ecrã Inteiro STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Seleccione esta opção para jogar o OpenTTD em modo de ecrã inteiro @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelera STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Marque esta caixa para permitir que o OpenTTD tente usar a aceleração por hardware. Uma configuração alterada só será aplicada após reiniciar o jogo STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}A definição só terá efeito após reiniciar o jogo +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Marque esta caixa para ativar "V-Sync" no ecrã. Uma configuração alterada só terá efeito quando reiniciar o jogo. Só funciona com a aceleração por hardware ativada + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamanho interface STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Seleccionar tamanho do elemento de interface a usar @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Definiç STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrar frase: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expandir todas STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Colapsar todas +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Repor todos os valores STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(sem explicação disponível) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valor por omissão: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Tipo de configuração: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Configuração STR_CONFIG_SETTING_TYPE_GAME_INGAME :Configuração de jogo (guardado; afeta apenas o jogo atual) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Configurações de empresa (guardado; afeta apenas novos jogos) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Configurações de empresa (guardado; afeta apenas a empresa atual) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Cuidado! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Esta ação vai repor todas as configurações do jogo para os seus valores padrão.{}Tem a certeza que deseja continuar? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categoria: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipo: @@ -1266,7 +1273,7 @@ STR_CONFIG_SETTING_SHOWFINANCES_HELPTEXT :Se ativado, os STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT :Novas ordens são 'sem parar' por predefinição: {STRING} STR_CONFIG_SETTING_NONSTOP_BY_DEFAULT_HELPTEXT :Normalmente, um veículo para em cada estação por onde passa. Ao ativar esta configuração, um veículo irá passar por todas as estações no seu percurso, parando apenas no destino final. Esta opção só tem efeito para novas rotas, mas as rotas existentes podem ser alteradas para funcionarem de forma igual. STR_CONFIG_SETTING_STOP_LOCATION :Ordens novas do comboio param {STRING} da plataforma -STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Local onde um combóio parará na plataforma por omissão. A opção 'extremo mais próximo' significa perto do ponto de entrada, 'meio' significa no meio da plataforma e 'extremo mais distante' significa o mais distante possível do ponto de entrada. Esta opção apenas afecta o valor por omissão para novas encomendas. Encomendas individuais podem utilizar qualquer uma das opções independentemente desta +STR_CONFIG_SETTING_STOP_LOCATION_HELPTEXT :Local de paragem do comboio nas plataformas por omissão. A opção 'extremo mais próximo' significa perto do ponto de entrada, 'meio' significa no meio da plataforma e 'extremo mais distante' significa o mais distante possível do ponto de entrada. Esta opção apenas afeta o valor por omissão para novas ordens. Ordens individuais podem utilizar qualquer uma das opções independentemente desta STR_CONFIG_SETTING_STOP_LOCATION_NEAR_END :no extremo perto STR_CONFIG_SETTING_STOP_LOCATION_MIDDLE :no meio STR_CONFIG_SETTING_STOP_LOCATION_FAR_END :no extremo longe @@ -1313,7 +1320,7 @@ STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Activar esta pr STR_CONFIG_SETTING_WARN_LOST_VEHICLE :Avisar se o veículo está perdido: {STRING} STR_CONFIG_SETTING_WARN_LOST_VEHICLE_HELPTEXT :Mostrar mensagens sobre veículos que não conseguem encontrar o caminho para o seu próximo destino. STR_CONFIG_SETTING_ORDER_REVIEW :Analisar ordens dos veículos: {STRING} -STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Quando activo, as encomendas dos veículos são periodicamente revistas e algumas falhas óbvias são anunciadas através de notícias, quando detectadas +STR_CONFIG_SETTING_ORDER_REVIEW_HELPTEXT :Quando ativo, as ordens dos veículos são periodicamente revistas e algumas falhas óbvias são anunciadas através de notícias, quando detetadas STR_CONFIG_SETTING_ORDER_REVIEW_OFF :Não STR_CONFIG_SETTING_ORDER_REVIEW_EXDEPOT :Sim, mas excluir veículos parados STR_CONFIG_SETTING_ORDER_REVIEW_ON :De todos os veículos @@ -1904,11 +1911,11 @@ STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Seleccio STR_LIVERY_PANEL_TOOLTIP :{BLACK}Seleccione o esquema de cores a alterar, ou esquemas múltiplos utilizando a tecla Ctrl com o botão esquerdo do rato. Marque a caixa para comutar a utilização do esquema de cores STR_LIVERY_DEFAULT :Estampagem Padrão -STR_LIVERY_STEAM :Motor a Vapor -STR_LIVERY_DIESEL :Motor Diesel -STR_LIVERY_ELECTRIC :Motor Eléctrico -STR_LIVERY_MONORAIL :Motor Monocarril -STR_LIVERY_MAGLEV :Motor Maglev (Levitação Magnética) +STR_LIVERY_STEAM :Locomotivas a Vapor +STR_LIVERY_DIESEL :Locomotivas Diesel +STR_LIVERY_ELECTRIC :Locomotivas Eléctricas +STR_LIVERY_MONORAIL :Motoras Monocarril +STR_LIVERY_MAGLEV :Motoras Maglev (Levitação Magnética) STR_LIVERY_DMU :DMU STR_LIVERY_EMU :EMU STR_LIVERY_PASSENGER_WAGON_STEAM :Carruagem de Passageiros (Vapor) @@ -1917,8 +1924,8 @@ STR_LIVERY_PASSENGER_WAGON_ELECTRIC :Carruagem de Pa STR_LIVERY_PASSENGER_WAGON_MONORAIL :Carruagem de Passageiros (Monocarril) STR_LIVERY_PASSENGER_WAGON_MAGLEV :Carruagem de Passageiros (Maglev) STR_LIVERY_FREIGHT_WAGON :Vagão de Carga -STR_LIVERY_BUS :Autocarro -STR_LIVERY_TRUCK :Veículo de Mercadorias +STR_LIVERY_BUS :Autocarros +STR_LIVERY_TRUCK :Camiões STR_LIVERY_PASSENGER_SHIP :Navio de passageiros STR_LIVERY_FREIGHT_SHIP :Navio cargueiro STR_LIVERY_HELICOPTER :Helicóptero @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Gravata: STR_FACE_EARRING :Brinco: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Mudar gravata ou brinco +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multi-jogador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nome do jogador: @@ -2036,7 +2046,7 @@ STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adiciona STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Iniciar servidor STR_NETWORK_SERVER_LIST_START_SERVER_TOOLTIP :{BLACK}Iniciar um servidor próprio -STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Digite teu nome +STR_NETWORK_SERVER_LIST_PLAYER_NAME_OSKTITLE :{BLACK}Introduza o seu nome STR_NETWORK_SERVER_LIST_ENTER_IP :{BLACK}Introduza o endereço IP do servidor # Start new multiplayer server @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}O nome d STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Definir palavra-chave STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteja o jogo com uma senha se não desejar que pessoas indesejadas se juntem -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Anunciado -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Escolher entre jogo público (internet) e privado (Área de Rede Local, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Não -STR_NETWORK_START_SERVER_ADVERTISED :Sim +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidade +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se as outras pessoas podem ver o seu servidor na lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Escolha o número máximo de clientes. Não necessitam estar todos presentes. @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Outros j STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Digite nome para o jogo de rede -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Qualquer -STR_NETWORK_LANG_ENGLISH :Inglês -STR_NETWORK_LANG_GERMAN :Alemão -STR_NETWORK_LANG_FRENCH :Francês -STR_NETWORK_LANG_BRAZILIAN :Brasileiro -STR_NETWORK_LANG_BULGARIAN :Búlgaro -STR_NETWORK_LANG_CHINESE :Chinês -STR_NETWORK_LANG_CZECH :Checo -STR_NETWORK_LANG_DANISH :Dinamarquês -STR_NETWORK_LANG_DUTCH :Holandês -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finlandês -STR_NETWORK_LANG_HUNGARIAN :Húngaro -STR_NETWORK_LANG_ICELANDIC :Islandês -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Japonês -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Norueguês -STR_NETWORK_LANG_POLISH :Polaco -STR_NETWORK_LANG_PORTUGUESE :Português -STR_NETWORK_LANG_ROMANIAN :Romeno -STR_NETWORK_LANG_RUSSIAN :Russo -STR_NETWORK_LANG_SLOVAK :Eslovaco -STR_NETWORK_LANG_SLOVENIAN :Esloveno -STR_NETWORK_LANG_SPANISH :Espanhol -STR_NETWORK_LANG_SWEDISH :Sueco -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraniano -STR_NETWORK_LANG_AFRIKAANS :Dialecto Africano Afrikaans -STR_NETWORK_LANG_CROATIAN :Croata -STR_NETWORK_LANG_CATALAN :Catalão -STR_NETWORK_LANG_ESTONIAN :Estónio -STR_NETWORK_LANG_GALICIAN :Galego -STR_NETWORK_LANG_GREEK :Grego -STR_NETWORK_LANG_LATVIAN :Letão -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sala de espera de jogo multi-jogador @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desligar STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor protegido. Introduza palavra-chave STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introduza palavra-chave -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista de clientes # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes -STR_NETWORK_COMPANY_LIST_SPECTATE :Assistir -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nova empresa +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jogadores "online" # Network client list -STR_NETWORK_CLIENTLIST_KICK :Expulsar -STR_NETWORK_CLIENTLIST_BAN :Banir -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Falar com todos -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Falar com a empresa -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mensagem privada +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multi-jogador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nome do servidor onde está a jogar +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Editar o nome do seu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nome do servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidade +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Se as outras pessoas podem ver o seu servidor na lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nome +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}O seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Editar o seu nome de jogador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :O seu nome de jogador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Ações administrativas para executar a este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Ações administrativas para executar a esta empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Juntar-se a esta empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Enviar uma mensagem a este jogador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Enviar uma mensagem a todos os jogadores desta empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Enviar uma mensagem a todos os espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nova empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Criar uma nova empresa e juntar-se a ela +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este é você +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este é o anfitrião do jogo + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Banir +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Apagar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :desbloquear com palavra-passe + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Ação administrativa +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Tem a certeza que quer expulsar o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Tem a certeza que quer banir o jogador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}Tem a certeza que quer apagar a empresa '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}Tem a certeza que quer restabelecer a palavra-chave da empresa '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Não foi STR_NETWORK_ERROR_CLIENT_START :{WHITE}Não foi possível estabelecer ligação STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tempo de espera esgotado na conexão #{NUM}. STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Ocorreu um erro de protocolo e a ligação foi encerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}O seu nome de jogador não foi definido. O nome pode ser definido no topo da janela de Multi-jogador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}A revisão deste cliente não condiz com a revisão do servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Palavra-chave incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Servidor cheio @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Demorou STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}O seu computador é demasiado lento para acompanhar com o servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}O seu computador demorou demasiado a transferir o mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}O seu computador demorou demasiado a ligar ao servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}O seu nome de jogador não é válido ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :erro geral @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :não foi recebi STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :demasiado tempo (geral) STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :demorou demasiado a transferir o mapa STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :demorou demasiado a processar o mapa +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nome de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Possível perda de conexão @@ -2442,7 +2440,7 @@ STR_STATION_BUILD_DRAG_DROP_TOOLTIP :{BLACK}Construi STR_STATION_BUILD_STATION_CLASS_TOOLTIP :{BLACK}Escolher a classe da estação a mostrar STR_STATION_BUILD_STATION_TYPE_TOOLTIP :{BLACK}Escolher o tipo de estação a construir -STR_STATION_CLASS_DFLT :Estação por defeito +STR_STATION_CLASS_DFLT :Estação padrão STR_STATION_CLASS_WAYP :Pontos de passagem # Signal window @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construi STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Esta bóia de posição pode ser usada para marcar pontos de rota adicionais. Shift alterna construção/mostra de custos estimados STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Construir aqueduto. Shift alterna contruir/mostrar custo estimado STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Definir área de água.{}Construir um canal, a não ser que a tecla Ctrl esteja pressionada a nível do mar, nesse caso inundará as zonas circundantes -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Colocar rios +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Colocar rios. Tecla "Ctrl" seleciona a área diagonalmente # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orientação do Depósito @@ -2872,7 +2870,7 @@ STR_SAVELOAD_SAVE_SCENARIO :{WHITE}Guardar STR_SAVELOAD_LOAD_SCENARIO :{WHITE}Abrir Cenário STR_SAVELOAD_LOAD_HEIGHTMAP :{WHITE}Carregar mapa de alturas STR_SAVELOAD_SAVE_HEIGHTMAP :{WHITE}Guardar mapa de alturas -STR_SAVELOAD_HOME_BUTTON :{BLACK}Carregue aqui para saltar para a directoria de gravação/carregamento por defeito +STR_SAVELOAD_HOME_BUTTON :{BLACK}Clique aqui para saltar para o diretório atual de gravação/carregamento padrão STR_SAVELOAD_BYTES_FREE :{BLACK}{BYTES} livres STR_SAVELOAD_LIST_TOOLTIP :{BLACK}Lista de unidades, directorias e ficheiros de jogos guardados STR_SAVELOAD_EDITBOX_TOOLTIP :{BLACK}Nome escolhido para guardar o jogo @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Aviso: {SI STR_NEWGRF_ERROR_MSG_ERROR :{RED}Erro: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ocorreu um erro fatal num NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ocorreu um erro de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} não funciona com a versão do TTDPatch reportada por OpenTTD. STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} é para a versão {STRING} do TTD. STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} foi concebido para ser usado com {STRING} @@ -3897,11 +3896,11 @@ STR_VEHICLE_INFO_AGE_RUNNING_COST_YR :{BLACK}Idade: { STR_VEHICLE_INFO_AGE :{COMMA} ano{P "" s} ({COMMA}) STR_VEHICLE_INFO_AGE_RED :{RED}{COMMA} ano{P "" s} ({COMMA}) -STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Máx. velocidade: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_MAX_SPEED :{BLACK}Velocidade máx.: {LTBLUE}{VELOCITY} STR_VEHICLE_INFO_MAX_SPEED_TYPE :{BLACK}Vel. máxima: {LTBLUE}{VELOCITY} {BLACK}Tipo de Aeronave: {LTBLUE}{STRING} STR_VEHICLE_INFO_MAX_SPEED_TYPE_RANGE :{BLACK}Velocidade Máx.: {LTBLUE}{VELOCITY} {BLACK}Tipo de Aeronave: {LTBLUE}{STRING} {BLACK}Alcance: {LTBLUE}{COMMA} quadrados -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Peso: {LTBLUE}{WEIGHT_SHORT} {BLACK}Potência: {LTBLUE}{POWER}{BLACK} Max. velocidade: {LTBLUE}{VELOCITY} -STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Peso: {LTBLUE}{WEIGHT_SHORT} {BLACK}Potência: {LTBLUE}{POWER}{BLACK} Máx. velocidade: {LTBLUE}{VELOCITY} {BLACK}Máx. E.T.: {LTBLUE}{FORCE} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED :{BLACK}Peso: {LTBLUE}{WEIGHT_SHORT} {BLACK}Potência: {LTBLUE}{POWER}{BLACK} Velocidade máx.: {LTBLUE}{VELOCITY} +STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :{BLACK}Peso: {LTBLUE}{WEIGHT_SHORT} {BLACK}Potência: {LTBLUE}{POWER}{BLACK} Velocidade máx.: {LTBLUE}{VELOCITY} {BLACK}Tração Máx.: {LTBLUE}{FORCE} STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR :{BLACK}Lucro neste ano: {LTBLUE}{CURRENCY_LONG} (último ano: {CURRENCY_LONG}) STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS :{BLACK}Fiabilidade: {LTBLUE}{COMMA}% {BLACK}Avarias desde o último serviço: {LTBLUE}{COMMA} @@ -3920,7 +3919,7 @@ STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Aumentar STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Diminuir intervalo de serviço por 10. Ctrl+Clique diminui o intervalo de serviço por 5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Alterar tipo de intervalo de manutenção -STR_VEHICLE_DETAILS_DEFAULT :Por Defeito +STR_VEHICLE_DETAILS_DEFAULT :Padrão STR_VEHICLE_DETAILS_DAYS :Dias STR_VEHICLE_DETAILS_PERCENT :Percentagem diff --git a/src/lang/romanian.txt b/src/lang/romanian.txt index 692c8a1bf3..8d852f12dc 100644 --- a/src/lang/romanian.txt +++ b/src/lang/romanian.txt @@ -1,7 +1,7 @@ ##name Romanian ##ownname Românӑ ##isocode ro_RO -##plural 0 +##plural 14 ##textdir ltr ##digitsep . ##digitsepcur . @@ -93,37 +93,25 @@ STR_CARGO_SINGULAR_FIZZY_DRINK :Suc acidulat # Quantity of cargo STR_QUANTITY_NOTHING : -STR_QUANTITY_PASSENGERS :{COMMA} călător{P "" i} STR_QUANTITY_COAL :{WEIGHT_LONG} de cărbune -STR_QUANTITY_MAIL :{COMMA} sac{P "" i} cu colete poștale STR_QUANTITY_OIL :{VOLUME_LONG} de petrol -STR_QUANTITY_LIVESTOCK :{COMMA} animal{P "" e} -STR_QUANTITY_GOODS :{COMMA} pachet{P "" e} de bunuri STR_QUANTITY_GRAIN :{WEIGHT_LONG} de cereale STR_QUANTITY_WOOD :{WEIGHT_LONG} de lemne STR_QUANTITY_IRON_ORE :{WEIGHT_LONG} de minereu de fier STR_QUANTITY_STEEL :{WEIGHT_LONG} de oțel -STR_QUANTITY_VALUABLES :{COMMA} cuti{P e i} de valori STR_QUANTITY_COPPER_ORE :{WEIGHT_LONG} de minereu de cupru STR_QUANTITY_MAIZE :{WEIGHT_LONG} de porumb STR_QUANTITY_FRUIT :{WEIGHT_LONG} de fructe -STR_QUANTITY_DIAMONDS :{COMMA} sac{P "" i} cu diamante STR_QUANTITY_FOOD :{WEIGHT_LONG} de alimente STR_QUANTITY_PAPER :{WEIGHT_LONG} de hârtie -STR_QUANTITY_GOLD :{COMMA} sac{P "" i} cu aur STR_QUANTITY_WATER :{VOLUME_LONG} de apă STR_QUANTITY_WHEAT :{WEIGHT_LONG} de grâu STR_QUANTITY_RUBBER :{VOLUME_LONG} de cauciuc STR_QUANTITY_SUGAR :{WEIGHT_LONG} de zahăr -STR_QUANTITY_TOYS :{COMMA} sac{P "" i} cu jucării -STR_QUANTITY_SWEETS :{COMMA} sac{P "" i} cu bomboane STR_QUANTITY_COLA :{VOLUME_LONG} de cola STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} de vată de zahăr -STR_QUANTITY_BUBBLES :{COMMA} balonaș{P "" e} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} de caramel -STR_QUANTITY_BATTERIES :{COMMA} bateri{P e i} STR_QUANTITY_PLASTIC :{VOLUME_LONG} de plastic -STR_QUANTITY_FIZZY_DRINKS :{COMMA} bido{P n ane} cu suc STR_QUANTITY_N_A :N/A # Two letter abbreviation of cargo name @@ -163,12 +151,10 @@ STR_ABBREV_NONE :{TINY_FONT}NU STR_ABBREV_ALL :{TINY_FONT}TOT # 'Mode' of transport for cargoes -STR_PASSENGERS :{COMMA} călător{P "" i} -STR_BAGS :{COMMA} sac{P "" i} +STR_BAGS :{COMMA}{NBSP}sac{P "" "" "de "}sac{P "" i i} STR_TONS :{COMMA} tone STR_LITERS :{COMMA} litri STR_ITEMS :{COMMA} bucăți -STR_CRATES :{COMMA} pachet{P "" e} # Colours, do not shuffle STR_COLOUR_DARK_BLUE :Albastru închis @@ -194,6 +180,7 @@ STR_COLOUR_DEFAULT :Prestabilit STR_UNITS_VELOCITY_IMPERIAL :{COMMA} mph STR_UNITS_VELOCITY_METRIC :{COMMA} km/h STR_UNITS_VELOCITY_SI :{COMMA} m/s +STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL}{NBSP}dale/zi STR_UNITS_POWER_IMPERIAL :{COMMA}cp STR_UNITS_POWER_METRIC :{COMMA}cp @@ -203,16 +190,12 @@ STR_UNITS_WEIGHT_SHORT_IMPERIAL :{COMMA}t STR_UNITS_WEIGHT_SHORT_METRIC :{COMMA}t STR_UNITS_WEIGHT_SHORT_SI :{COMMA}kg -STR_UNITS_WEIGHT_LONG_IMPERIAL :{COMMA} ton{P ă e} -STR_UNITS_WEIGHT_LONG_METRIC :{COMMA} ton{P ă e} STR_UNITS_WEIGHT_LONG_SI :{COMMA} kg STR_UNITS_VOLUME_SHORT_IMPERIAL :{COMMA}gal STR_UNITS_VOLUME_SHORT_METRIC :{COMMA}l STR_UNITS_VOLUME_SHORT_SI :{COMMA}m³ -STR_UNITS_VOLUME_LONG_IMPERIAL :{COMMA} galo{P n ane} -STR_UNITS_VOLUME_LONG_METRIC :{COMMA} litr{P u i} STR_UNITS_VOLUME_LONG_SI :{COMMA} m³ STR_UNITS_FORCE_IMPERIAL :{COMMA} lbf @@ -312,8 +295,13 @@ STR_SORT_BY_CARGO_CAPACITY :Capacitate înc STR_SORT_BY_RANGE :Raza de acțiune STR_SORT_BY_POPULATION :Populaţia STR_SORT_BY_RATING :Cotaţie +STR_SORT_BY_NUM_VEHICLES :Număr de vehicule +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Profit total în anul trecut +STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Profit mediu în anul trecut +STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Profit mediu în acest an # Group by options for vehicle list +STR_GROUP_BY_SHARED_ORDERS :Comenzi comune # Tooltips for the main toolbar STR_TOOLBAR_TOOLTIP_PAUSE_GAME :{BLACK}Pauză joc @@ -331,14 +319,15 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Afişeaz STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Afişează grafice STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Afişează clasamentul companiilor STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Listează sau fondează obiectivele industriale -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Afişează lista cu trenurile companiei. Ctrl+Click alternează deschiderea listei cu grupuri/vehicule -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Afişează lista cu autovehiculele companiei. Ctrl+Click alternează deschiderea listei cu grupuri/vehicule -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Afişează lista cu navele companiei. Ctrl+Click alternează deschiderea listei cu grupuri/vehicule -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Afişează lista cu aeronavele companiei. Ctrl+Click alternează deschiderea listei cu grupuri/vehicule +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Afișează lista cu trenurile companiei. Ctrl+clic comută afișarea listei cu grupuri/vehicule +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Afișează lista cu autovehiculele companiei. Ctrl+clic comută afișarea listei cu grupuri/vehicule +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Afișează lista cu navele companiei. Ctrl+clic comută afișarea listei cu grupuri/vehicule +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Afișează lista cu aeronavele companiei. Ctrl+clic comută afișarea listei cu grupuri/vehicule STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Măreşte imaginea STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Micşorează imaginea STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Construieşte căi ferate STR_TOOLBAR_TOOLTIP_BUILD_ROADS :{BLACK}Construieşte drumuri +STR_TOOLBAR_TOOLTIP_BUILD_TRAMWAYS :{BLACK}Construiește linii de tramvai STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS :{BLACK}Construieşte porturi STR_TOOLBAR_TOOLTIP_BUILD_AIRPORTS :{BLACK}Construieşte aeroporturi STR_TOOLBAR_TOOLTIP_LANDSCAPING :{BLACK}Afişează instrumentele pentru modelarea terenului, plantarea copacilor, etc. @@ -359,6 +348,7 @@ STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION :{BLACK}Generare STR_SCENEDIT_TOOLBAR_TOWN_GENERATION :{BLACK}Generare oraş STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION :{BLACK}Generare industrii STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION :{BLACK}Construcţii rutiere +STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION :{BLACK}Construcție tramvai STR_SCENEDIT_TOOLBAR_PLANT_TREES :{BLACK}Plantează arbori. Shift comută între plantare/afişare cost estimat STR_SCENEDIT_TOOLBAR_PLACE_SIGN :{BLACK}Plasează semn STR_SCENEDIT_TOOLBAR_PLACE_OBJECT :{BLACK}Amplasează obiect. Shift comută între amplasare/afişare cost estimat @@ -368,7 +358,7 @@ STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO :Salvează scena STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO :Încarcă scenariu STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP :Salvează harta înălţimilor STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP :Încarcă harta de înălţimi -STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Ieşire din editorul de scenarii +STR_SCENEDIT_FILE_MENU_QUIT_EDITOR :Ieșire din editorul de scenarii STR_SCENEDIT_FILE_MENU_SEPARATOR : STR_SCENEDIT_FILE_MENU_QUIT :Ieşire din joc ############ range for SE file menu starts @@ -393,7 +383,7 @@ STR_SETTINGS_MENU_TRANSPARENT_SIGNS :Nume staţii/se ############ range for file menu starts STR_FILE_MENU_SAVE_GAME :Salvează jocul STR_FILE_MENU_LOAD_GAME :Încarcă joc -STR_FILE_MENU_QUIT_GAME :Ieşire în meniul principal +STR_FILE_MENU_QUIT_GAME :Ieșire în meniul principal STR_FILE_MENU_SEPARATOR : STR_FILE_MENU_EXIT :Ieşire din joc ############ range ends here @@ -443,7 +433,7 @@ STR_RAIL_MENU_MAGLEV_CONSTRUCTION :Construcţie pe ############ range for road construction menu starts STR_ROAD_MENU_ROAD_CONSTRUCTION :Construcţii rutiere -STR_ROAD_MENU_TRAM_CONSTRUCTION :Construcţie tramvai +STR_ROAD_MENU_TRAM_CONSTRUCTION :Construcție tramvai ############ range ends here ############ range for waterways construction menu starts @@ -649,13 +639,14 @@ STR_MUSIC_EFFECTS_VOLUME :{TINY_FONT}{BLA STR_MUSIC_TRACK_NONE :{TINY_FONT}{DKGREEN}-- STR_MUSIC_TRACK_DIGIT :{TINY_FONT}{DKGREEN}{ZEROFILL_NUM} STR_MUSIC_TITLE_NONE :{TINY_FONT}{DKGREEN}------ +STR_MUSIC_TITLE_NOMUSIC :{TINY_FONT}{DKGREEN}Nu există muzică disponibilă STR_MUSIC_TITLE_NAME :{TINY_FONT}{DKGREEN}"{STRING}" STR_MUSIC_TRACK :{TINY_FONT}{BLACK}Piesa STR_MUSIC_XTITLE :{TINY_FONT}{BLACK}Titlul STR_MUSIC_SHUFFLE :{TINY_FONT}{BLACK}Aleator STR_MUSIC_PROGRAM :{TINY_FONT}{BLACK}Program -STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Sari la piesa precedentă din selecţie -STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Sari la piesa următoare din selecţie +STR_MUSIC_TOOLTIP_SKIP_TO_PREVIOUS_TRACK :{BLACK}Sari la piesa precedentă din selecție +STR_MUSIC_TOOLTIP_SKIP_TO_NEXT_TRACK_IN_SELECTION :{BLACK}Sari la următoarea piesă din selecție STR_MUSIC_TOOLTIP_STOP_PLAYING_MUSIC :{BLACK}Opreşte muzica STR_MUSIC_TOOLTIP_START_PLAYING_MUSIC :{BLACK}Porneşte muzica STR_MUSIC_TOOLTIP_DRAG_SLIDERS_TO_SET_MUSIC :{BLACK}Foloseşte aceste indicatoare pentru a regla volumul muzicii şi al efectelor sonore @@ -666,7 +657,7 @@ STR_MUSIC_TOOLTIP_SELECT_EZY_STREET_STYLE :{BLACK}Selectea STR_MUSIC_TOOLTIP_SELECT_CUSTOM_1_USER_DEFINED :{BLACK}Selectează programul personal 1 STR_MUSIC_TOOLTIP_SELECT_CUSTOM_2_USER_DEFINED :{BLACK}Selectează programul personal 2 STR_MUSIC_TOOLTIP_TOGGLE_PROGRAM_SHUFFLE :{BLACK}Comutator pentru amestecarea melodiilor (pornit/oprit) -STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Afişeaza fereastra pentru selecţia melodiilor +STR_MUSIC_TOOLTIP_SHOW_MUSIC_TRACK_SELECTION :{BLACK}Afișează fereastra pentru selecția melodiilor # Playlist window STR_PLAYLIST_TRACK_NAME :{TINY_FONT}{LTBLUE}{ZEROFILL_NUM} "{STRING}" @@ -766,6 +757,7 @@ STR_SMALLMAP_TOOLTIP_ENABLE_ALL_CARGOS :{BLACK}Afișeaz STR_STATUSBAR_TOOLTIP_SHOW_LAST_NEWS :{BLACK}Re-afişează ultimul mesaj STR_STATUSBAR_COMPANY_NAME :{SILVER}- - {COMPANY} - - STR_STATUSBAR_PAUSED :{YELLOW}* * PAUZĂ * * +STR_STATUSBAR_PAUSED_LINK_GRAPH :{ORANGE}* * PAUZĂ (se actualizează graficul conexiunilor) * * STR_STATUSBAR_AUTOSAVE :{RED}SALVARE AUTOMATĂ STR_STATUSBAR_SAVING_GAME :{RED}* * SALVARE JOC * * @@ -811,6 +803,7 @@ STR_NEWS_MERGER_TAKEOVER_TITLE :{BIG_FONT}{BLAC STR_PRESIDENT_NAME_MANAGER :{BLACK}{PRESIDENT_NAME}{}(Preşedinte) STR_NEWS_NEW_TOWN :{BLACK}{BIG_FONT}{STRING} a sponsorizat construcţia unui nou oras {TOWN}! +STR_NEWS_NEW_TOWN_UNSPONSORED :{BLACK}{BIG_FONT}Un nou oraș, numit {TOWN}, a fost construit! STR_NEWS_INDUSTRY_CONSTRUCTION :{BIG_FONT}{BLACK}Un nou obiectiv industrial ({STRING}) se construieşte lângă {TOWN}! STR_NEWS_INDUSTRY_PLANTED :{BIG_FONT}{BLACK}O nouă {STRING} se plantează lângă {TOWN}! @@ -873,7 +866,7 @@ STR_NEWS_SERVICE_SUBSIDY_AWARDED_DOUBLE :{BIG_FONT}{BLAC STR_NEWS_SERVICE_SUBSIDY_AWARDED_TRIPLE :{BIG_FONT}{BLACK}Subvenţie acordată companiei {STRING}!{}{}Transportul de {STRING} de la {STRING} la {STRING} va aduce încasări triple timp de un an! STR_NEWS_SERVICE_SUBSIDY_AWARDED_QUADRUPLE :{BIG_FONT}{BLACK}Subvenţie acordată companiei {STRING}!{}{}Transportul de {STRING} de la {STRING} la {STRING} va aduce încasări de patru ori mai mari timp de un an! -STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Haos pe străzile din {TOWN}!{}{}Programul finanţat de {STRING} pentru reconstrucţia străzilor aduce 6 luni de haos participanţilor la trafic! +STR_NEWS_ROAD_REBUILDING :{BIG_FONT}{BLACK}Haos pe străzile din {TOWN}!{}{}Programul finanțat de {STRING} pentru reconstrucția străzilor aduce 6 luni de haos participanților la trafic! STR_NEWS_EXCLUSIVE_RIGHTS_TITLE :{BIG_FONT}{BLACK}Monopol de transport! STR_NEWS_EXCLUSIVE_RIGHTS_DESCRIPTION :{BIG_FONT}{BLACK}Autoritatea locală a oraşului {TOWN} semnează un contract cu {STRING} pentru un an de drepturi exclusive de transport! @@ -925,6 +918,11 @@ STR_GAME_OPTIONS_CURRENCY_CUSTOM :Personalizată. STR_GAME_OPTIONS_CURRENCY_GEL :Lari Georgian (GEL) STR_GAME_OPTIONS_CURRENCY_IRR :Rial Iranian (IRR) STR_GAME_OPTIONS_CURRENCY_RUB :Ruble rusești (RUB) +STR_GAME_OPTIONS_CURRENCY_MXN :Peso Mexican (MXN) +STR_GAME_OPTIONS_CURRENCY_NTD :Noul Dolar Taiwanez (NTD) +STR_GAME_OPTIONS_CURRENCY_CNY :Renminbi Chinezesc (CNY) +STR_GAME_OPTIONS_CURRENCY_INR :Rupia Indiană (INR) +STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysian (MYR) ############ end of currency region STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Pe partea stângă @@ -977,23 +975,35 @@ STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Bifează STR_GAME_OPTIONS_RESOLUTION :{BLACK}Rezoluţia ecranului STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Alege rezoluţia dorită pentru joc STR_GAME_OPTIONS_RESOLUTION_OTHER :(alta/nespecificată) +STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} +STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Accelerare hardware +STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Setarea va avea efect doar după repornirea jocului + +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Mărime interfată STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Alege mărimea elementelor de interfaţa +STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_AUTO :(auto-detecție) STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_NORMAL :Normală STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_2X_ZOOM :Mărime dublă STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_4X_ZOOM :Mărime împătrită +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Alege dimensiunea fontului pentru interfață +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_AUTO :(auto-detecție) +STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :Normal STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :Mărime dublă +STR_GAME_OPTIONS_GRAPHICS :{BLACK}Grafică +STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :{BLACK}Alegeți rata de reîmprospătare dorită +STR_GAME_OPTIONS_REFRESH_RATE_ITEM :{NUM}Hz +STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}Ratele de împrospătare de peste 60Hz ar putea afecta performanța. STR_GAME_OPTIONS_BASE_GRF :{BLACK}Set grafic de bază STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}Selectează setul grafic de bază utilizat în joc -STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} fişier{P "" "e"} lipsă/corupt{P "" e} STR_GAME_OPTIONS_BASE_GRF_DESCRIPTION_TOOLTIP :{BLACK}Informaţii adiţionale despre setul grafic de bază STR_GAME_OPTIONS_BASE_SFX :{BLACK}Set sunete de bază @@ -1002,7 +1012,6 @@ STR_GAME_OPTIONS_BASE_SFX_DESCRIPTION_TOOLTIP :{BLACK}Informa STR_GAME_OPTIONS_BASE_MUSIC :{BLACK}Setul de muzică de bază STR_GAME_OPTIONS_BASE_MUSIC_TOOLTIP :{BLACK}Selectaţi setul de muzică de bază -STR_GAME_OPTIONS_BASE_MUSIC_STATUS :{RED}{NUM} fişier{P "" e} corupt{P "" e} STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :{BLACK}Informaţii adiţionale despre setul de muzică de bază STR_ERROR_RESOLUTION_LIST_FAILED :{WHITE}Nu s-a putut obține lista de rezoluții suportate @@ -1085,6 +1094,7 @@ STR_TERRAIN_TYPE_FLAT :Plat STR_TERRAIN_TYPE_HILLY :Deluros STR_TERRAIN_TYPE_MOUNTAINOUS :Muntos STR_TERRAIN_TYPE_ALPINIST :Alpinist +STR_TERRAIN_TYPE_CUSTOM_VALUE :Înălțime personalizată ({NUM}) STR_CITY_APPROVAL_PERMISSIVE :Permisivă STR_CITY_APPROVAL_TOLERANT :Tolerantă @@ -1108,7 +1118,7 @@ STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Setări compani STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categorie: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tip: -STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Arată în lista de mai jos doar setările modificate +STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}Limitează lista de mai jos doar la setările modificate STR_CONFIG_SETTING_RESTRICT_BASIC :Setări de bază (afişează numai setări importante) STR_CONFIG_SETTING_RESTRICT_ADVANCED :Setări avansate (afişează majoritatea setărilor) STR_CONFIG_SETTING_RESTRICT_ALL :Setări expert (afişează toate setările) @@ -1165,7 +1175,9 @@ STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Comută dezastr STR_CONFIG_SETTING_CITY_APPROVAL :Atitudinea consiliului orașului cu privire la restructurarea zonei: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Alege în ce măsură poluarea fonică si deranjamentul local provocat de o companie va afecta impresia orașului despre aceasta, si viitoarele planuri de construcție in zonă -STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Nu poţi seta înălţimea maxima a hărţii la aceasta valoare. Cel puţin un munte pe hartă are o înălţime mai mare. +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :Înălțimea limită a hărții: {STRING} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE :{NUM} +STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Nu poți seta înălțimea maximă a hărții la această valoare. Cel puțin un munte de pe hartă este mai înalt de-atât. STR_CONFIG_SETTING_AUTOSLOPE :Permite terra-formarea sub clădiri, şine, etc. (auto-pante): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Permite terraformarea sub clădiri şi şine fără eliminarea acestora STR_CONFIG_SETTING_CATCHMENT :Permite arii de cuprindere mai realiste: {STRING} @@ -1175,12 +1187,11 @@ STR_CONFIG_SETTING_EXTRADYNAMITE :Permite demolar STR_CONFIG_SETTING_EXTRADYNAMITE_HELPTEXT :Facilitează eliminarea de clădiri şi infrastructură deţinute de oraş STR_CONFIG_SETTING_TRAIN_LENGTH :Lungimea maximă a trenurilor: {STRING} STR_CONFIG_SETTING_TRAIN_LENGTH_HELPTEXT :Configurează lungimea maximă a trenurilor -STR_CONFIG_SETTING_TILE_LENGTH :{COMMA} pătrăţel{P 0 "" e} STR_CONFIG_SETTING_SMOKE_AMOUNT :Cantitatea de fum/ scântei ale vehiculului: {STRING} STR_CONFIG_SETTING_SMOKE_AMOUNT_HELPTEXT :Configurează cât de mult fum sau cât de multe scântei sunt emise de vehicule STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL :Modelul de acceleraţie al trenurilor: {STRING} STR_CONFIG_SETTING_TRAIN_ACCELERATION_MODEL_HELPTEXT :Selectează modelul fizic pentru accelerarea trenurilor. Modelul "original" penalizează pantele în mod egal pentru toate vehiculele. Modelul "realistic" penalizează pantele şi curbele în funcţie de mai mulţi parametrii, cum ar fi lungimea şi efortul tractor -STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Modelul de acceleraţie al vehiculelor rutiere: {STRING} +STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL :Modelul de accelerație al vehiculelor rutiere: {STRING} STR_CONFIG_SETTING_ROAD_VEHICLE_ACCELERATION_MODEL_HELPTEXT :Selectează modelul fizic pentru accelerarea autovehiculelor. Modelul "original" penalizează pantele în mod egal pentru toate autovehiculele. Modelul "realistic" penalizează pantele şi curbele în funcţie de mai mulţi parametrii ai motorului, cum ar fi efortul tractor STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS :Înclinarea pantelor pentru trenuri: {STRING} STR_CONFIG_SETTING_TRAIN_SLOPE_STEEPNESS_HELPTEXT :Înclinarea unui pătrăţel de pantă pentru trenuri. O valoare mai mare face urcarea mai dificilă @@ -1195,8 +1206,8 @@ STR_CONFIG_SETTING_INFLATION :Inflaţia: {STR STR_CONFIG_SETTING_INFLATION_HELPTEXT :Activează inflaţia în economie, unde costurile cresc ceva mai rapid decât plăţile STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH :Lungimea maximă a podurilor: {STRING} STR_CONFIG_SETTING_MAX_BRIDGE_LENGTH_HELPTEXT :Lungimea maximă pentru construcţia de poduri -STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Întăltimea maximă a podurilor: {STRING} -STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Întăltimea maximă pentru construcţia de poduri +STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT :Înălțimea maximă a podurilor: {STRING} +STR_CONFIG_SETTING_MAX_BRIDGE_HEIGHT_HELPTEXT :Înălțimea maximă pentru construcția de poduri STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Lungimea maximă a tunelurilor: {STRING} STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Lungimea maximă pentru construcţia de tuneluri STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Metoda manuală de construcţie a industriilor primare: {STRING} @@ -1231,7 +1242,7 @@ STR_CONFIG_SETTING_AUTOSCROLL_EVERY_VIEWPORT :fiecare ecran STR_CONFIG_SETTING_BRIBE :Permite mituirea autorităţilor locale: {STRING} STR_CONFIG_SETTING_BRIBE_HELPTEXT :Permite companiilor să încerce să mituiască autoritatea locală. Daca încercarea este descoperită de către un inspector, compania nu va mai putea executa nici o acțiune în oraș timp de șase luni STR_CONFIG_SETTING_ALLOW_EXCLUSIVE :Permite cumpărarea de drepturi exclusive de transport: {STRING} -STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Dacă o companie cumpără drepturi exclusive de transport într-un oras, staţiilor oponenţilor (de pasageri şi mărfuri) nu vor primi niciun fel de cargo pentru un an întreg +STR_CONFIG_SETTING_ALLOW_EXCLUSIVE_HELPTEXT :Dacă o companie cumpără drepturi exclusive de transport într-un oraș, stațiile concurenței (de pasageri și mărfuri) nu vor primi niciun fel de marfă timp de un an STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS :Permite finaţarea clădirilor noi: {STRING} STR_CONFIG_SETTING_ALLOW_FUND_BUILDINGS_HELPTEXT :Permite companiilor să doneze bani orașelor pentru construcția de noi locuințe STR_CONFIG_SETTING_ALLOW_FUND_ROAD :Permite finanțarea reconstrucției străzilor locale: {STRING} @@ -1256,6 +1267,7 @@ STR_CONFIG_SETTING_DYNAMIC_ENGINES_EXISTING_VEHICLES :{WHITE}Schimbar STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE :Mentenanță infrastructură: {STRING} STR_CONFIG_SETTING_INFRASTRUCTURE_MAINTENANCE_HELPTEXT :Cand este activă, infrastructura necesita cheltuieli cu intreținerea. Costurile cresc proporțional cu rețeaua de transport, afectând companiile mari mai mult decât companiile mici +STR_CONFIG_SETTING_COMPANY_STARTING_COLOUR_HELPTEXT :Alegeți culoarea de început pentru companie STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS :Aeroporturile nu expiră niciodată: {STRING} STR_CONFIG_SETTING_NEVER_EXPIRE_AIRPORTS_HELPTEXT :Activarea acestei opțiuni determina ca fiecare tip de aeroport sa fie disponibil permanent, după ce a fost introdus. @@ -1275,21 +1287,18 @@ STR_CONFIG_SETTING_AUTORENEW_VEHICLE :Înnoire automa STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT :După activare, orice vehicul care este învechit va fi reînnoit automat când condițiile de înlocuire automată sunt îndeplinite STR_CONFIG_SETTING_AUTORENEW_MONTHS :Autoreînnoire când vehiculul {STRING} vârsta maximă STR_CONFIG_SETTING_AUTORENEW_MONTHS_HELPTEXT :Vârsta aproximativă când un vehicul ar trebui autoreînnoit -STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_BEFORE :mai are {COMMA} lun{P 0 ă i} până la -STR_CONFIG_SETTING_AUTORENEW_MONTHS_VALUE_AFTER :a depășit cu {COMMA} lun{P 0 ă i} STR_CONFIG_SETTING_AUTORENEW_MONEY :Fonduri minime pentru înnoire automată: {STRING} STR_CONFIG_SETTING_AUTORENEW_MONEY_HELPTEXT :Suma minimă care trebuie să rămână disponibilă atunci când se face autoreînnoirea STR_CONFIG_SETTING_ERRMSG_DURATION :Durata de afișare a mesajelor de eroare: {STRING} STR_CONFIG_SETTING_ERRMSG_DURATION_HELPTEXT :Durata afișării mesajelor de eroare în fereastra roșie. Unele mesaje de eroare (cele critice) nu sunt închise automat după trecerea acestei perioade, și trebuie închise manual. -STR_CONFIG_SETTING_ERRMSG_DURATION_VALUE :{COMMA} secund{P 0 ă e} STR_CONFIG_SETTING_HOVER_DELAY :Afișează texte informative: {STRING} STR_CONFIG_SETTING_HOVER_DELAY_HELPTEXT :Durata dinaintea afișării sfaturilor când se ține mausul pe un element al interfeței. Alternativ, afișarea sfaturilor poate fi setată pentru clic-dreapta -STR_CONFIG_SETTING_HOVER_DELAY_VALUE :Plutește {COMMA} milisecund{P 0 ă e} STR_CONFIG_SETTING_HOVER_DELAY_DISABLED :Click dreapta STR_CONFIG_SETTING_POPULATION_IN_LABEL :Afişează populaţia unui oras lângă nume: {STRING} STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Afișează populația orașelor în numele afișate pe hartă STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Grosimea liniilor din grafice: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Grosimea liniilor din grafice. O linie subțire este mai informativă, o linie mai groasă este mai ușor de văzut și are culorile mai usor de distins +STR_CONFIG_SETTING_SHOW_NEWGRF_NAME :Afișează numele NewGRF în fereastra de construcție a vehiculului: {STRING} STR_CONFIG_SETTING_LANDSCAPE :Peisaj: {STRING} STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Peisajele definesc scenariile de bază a jocului cu cerințe diferite pentru încărcături și dezvoltare a orașelor. NewGRF și scripturile de joc permit un control mai fin @@ -1300,10 +1309,16 @@ STR_CONFIG_SETTING_LAND_GENERATOR_TERRA_GENESIS :TerraGenesis STR_CONFIG_SETTING_TERRAIN_TYPE :Tip teren: {STRING} STR_CONFIG_SETTING_TERRAIN_TYPE_HELPTEXT :(Doar TerraGenesis) Frecvența dealurilor din peisaj STR_CONFIG_SETTING_INDUSTRY_DENSITY :Densitatea industriei: {STRING} +STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Stabilește câte industrii ar trebui generate și ce nivel ar trebui întreținut pe durata jocului STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Distanța maximă de la marginea hărții pentru rafinării: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Rafinăriile de petrol vor fi construite doar la marginea hărţii, sau pe coastă, în cazul harţilor insulare STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Grosimea stratului de zăpadă: {STRING} -STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Controlează înălțimea de la care zăpada apare în peisajul sub-arctic. De asemenea, zăpada afectează generarea industriilor și cerințele de creștere a orașelor. +STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Controlează înălțimea de la care zăpada apare în peisajul sub-arctic. Zăpada afectează și generarea industriilor și cerințele de creștere a orașelor. Se poate modifica doar prin Editorul de scenarii sau este calculat prin „acoperirea cu zăpadă” +STR_CONFIG_SETTING_SNOW_COVERAGE :Acoperire cu zăpadă: {STRING} +STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% +STR_CONFIG_SETTING_DESERT_COVERAGE :Acoperire cu deșert: {STRING} +STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Controlează întinderea aproximativă de deșert din peisajul tropical. Deșert afectează și generarea industriilor. Parametrul se folosește doar la generarea hărții +STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Duritatea terenului (doar pt TerraGenesis) : {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Doar TerraGenesis) Alegeți frecvența dealurilor: Peisajele line au dealuri mai puține și mai întinse. Peisajele dure au multe dealuri și pot arăta repetitiv STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Foarte fin @@ -1311,6 +1326,8 @@ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :Fin STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :Dur STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_ROUGH :Foarte dur STR_CONFIG_SETTING_VARIETY :Distribuția varietății: {STRING} +STR_CONFIG_SETTING_VARIETY_HELPTEXT :(TerraGenesis only) Specifică dacă harta conține și zone muntoase și teren plat. Deoarece aceasta face harta mai plată, alte setări ar trebui să adauge zone muntoase +STR_CONFIG_SETTING_RIVER_AMOUNT :Numărul de râuri: {STRING} STR_CONFIG_SETTING_RIVER_AMOUNT_HELPTEXT :Alege câte râuri să fie generate STR_CONFIG_SETTING_TREE_PLACER :Algoritm amplasare arbori: {STRING} STR_CONFIG_SETTING_TREE_PLACER_HELPTEXT :Alegeți distribuția copacilor pe hartă: 'Original' plantează copacii dispersați uniform, 'Îmbunătățit' îi plantează grupat @@ -1337,7 +1354,9 @@ STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_HELPTEXT :Culoarea terenu STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_GREEN :Verde STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_DARK_GREEN :Verde închis STR_CONFIG_SETTING_SMALLMAP_LAND_COLOUR_VIOLET :Mov +STR_CONFIG_SETTING_SCROLLMODE_HELPTEXT :Comportamentul derulării hărții STR_CONFIG_SETTING_SCROLLMODE_RMB_LOCKED :Mută harta ținând apăsat click dreapta, poziția cursorului rămânând fixă +STR_CONFIG_SETTING_SCROLLMODE_RMB :Mută harta cu clic dreapta STR_CONFIG_SETTING_SCROLLMODE_LMB :Mută harta cu clic stânga STR_CONFIG_SETTING_SMOOTH_SCROLLING :Derulare uşoară ecran: {STRING} STR_CONFIG_SETTING_SMOOTH_SCROLLING_HELPTEXT :Controlează modul de deplasare a imaginii din ecranul principal când se face click pe harta mică sau când se execută o comandă de deplasare către un obiect anume de pe hartă. Dacă este activată, imaginea se deplasează în mod fluid, altfel imaginea sare direct la zona dorită @@ -1370,6 +1389,8 @@ STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_COMMAND :Comandă+Click STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_CONTROL :Control+Click STR_CONFIG_SETTING_RIGHT_MOUSE_BTN_EMU_OFF :Oprit +STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE :Închidere fereastră la clic-dreapta: {STRING} +STR_CONFIG_SETTING_RIGHT_MOUSE_WND_CLOSE_HELPTEXT :Închide o fereastră prin clic-dreapta înăuntrul ei. Dezactivează sfatul oferit la clic-dreapta! STR_CONFIG_SETTING_AUTOSAVE :Autosalvare: {STRING} STR_CONFIG_SETTING_AUTOSAVE_HELPTEXT :Alege intervalul de timp dintre salvările automate @@ -1410,6 +1431,9 @@ STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :Menține barele STR_CONFIG_SETTING_EXPENSES_LAYOUT :Grupează cheltuielile în raportul financiar al companiei: {STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :Definește stilul ferestrei care afișează cheltuielile companiei STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS_HELPTEXT :Elimină automat semnalele când construiești căi ferate dacă ele îți vin în cale. Nu uita că asta ar putea conduce la accidente feroviare. +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT :Limita de viteză pentru trecerea timpului: {STRING} +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_VAL :{NUM}% din viteza normală a jocului +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :Fără limită (atât de rapid pe cât permite calculatorul tău) STR_CONFIG_SETTING_SOUND_TICKER :Afișaj știri: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :Redă sunet la afișarea sumarului știrilor @@ -1458,13 +1482,14 @@ STR_CONFIG_SETTING_AI_IN_MULTIPLAYER :Permite Intelig STR_CONFIG_SETTING_AI_IN_MULTIPLAYER_HELPTEXT :Permite ca jucătorii controlați de AI să participe în jocuri multiplayer STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES :Număr opcodes înainte de suspendarea scripturilor: {STRING} STR_CONFIG_SETTING_SCRIPT_MAX_OPCODES_HELPTEXT :Numărul maxim de instrucțiuni pe care un script le poate executa pe parcursul unei ture +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY :Maximul de memorie utilizată per script: {STRING} +STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_HELPTEXT :Câtă memorie poate consuma un singur script înainte să fie terminat forțat. Cantitatea necesară ar putea fi mai mare pentru hărți mari. STR_CONFIG_SETTING_SCRIPT_MAX_MEMORY_VALUE :{COMMA} MiB STR_CONFIG_SETTING_SERVINT_ISPERCENT :Intervaluri de service în procente: {STRING} STR_CONFIG_SETTING_SERVINT_ISPERCENT_HELPTEXT :Alege dacă întreținerea vehiculelor este activată de trecerea unei anumite perioade de timp, sau scăzând un anumit procent din gradul de rezistență al vehiculului STR_CONFIG_SETTING_SERVINT_TRAINS :Intervalul de întreținere implicit al trenurilor: {STRING} STR_CONFIG_SETTING_SERVINT_TRAINS_HELPTEXT :Alege perioada de întreținere implicită pentru noi vehicule feroviare, dacă nu există un interval de întreținere stabilit pentru vehicul -STR_CONFIG_SETTING_SERVINT_VALUE :{COMMA} zi{P 0 "" le}/% STR_CONFIG_SETTING_SERVINT_DISABLED :Dezactivat STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES :Intervalul de întreținere implicit al vehiculelor rutiere: {STRING} STR_CONFIG_SETTING_SERVINT_ROAD_VEHICLES_HELPTEXT :Alege perioada de întreținere implicită pentru noi vehicule rutiere, dacă nu există un interval de întreținere stabilit pentru vehicul @@ -1518,13 +1543,17 @@ STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Ştirile color STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Anul începând cu care anunțurile din ziar sunt tipărite color. Înainte de acest an, anunturile sunt monocrome (alb/negru) STR_CONFIG_SETTING_STARTING_YEAR :Anul de început al jocului: {STRING} STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM} +STR_CONFIG_SETTING_ENDING_YEAR_ZERO :Niciodată +STR_CONFIG_SETTING_ECONOMY_TYPE :Tipul economiei: {STRING} +STR_CONFIG_SETTING_ECONOMY_TYPE_ORIGINAL :Original +STR_CONFIG_SETTING_ECONOMY_TYPE_SMOOTH :Lin +STR_CONFIG_SETTING_ECONOMY_TYPE_FROZEN :Înghețată STR_CONFIG_SETTING_ALLOW_SHARES :Permite cumpărarea de acţiuni de la alte companii: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES_HELPTEXT :Dacă este activată, se permite cumpărarea și vânzarea de acțiuni ale companiilor. Acțiunile devin disponibile doar când compania depășește o anumită vârstă STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE :Procentul din profitul pe secţiune care să fie plătit pentru alimentare: {STRING} STR_CONFIG_SETTING_FEEDER_PAYMENT_SHARE_HELPTEXT :Procentul din câştig care este oferit legăturilor intermediare pentru alimentare, oferind mai mult control asupra încasărilor STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY :Când se trage cu mouse-ul, plasează semnale la fiecare: {STRING} -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Configurează distanţa la care se vor construi semnale pe şină până la următorul obstacol (semnal, intersecţie), dacâ se trage cu mouse-ul -STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_VALUE :{COMMA} pătrăţel{P 0 "" e} +STR_CONFIG_SETTING_DRAG_SIGNALS_DENSITY_HELPTEXT :Configurează distanța la care se vor construi semnale pe șină până la următorul obstacol (semnal, intersecție), dacă se trage cu mausul STR_CONFIG_SETTING_DRAG_SIGNALS_FIXED_DISTANCE :La plasarea mai multor semale, păstrează distanţa fixă între acestea: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE :Construieşte automat semafoare înainte de: {STRING} STR_CONFIG_SETTING_SEMAPHORE_BUILD_BEFORE_DATE_HELPTEXT :Alege anul din care se vor folosi semnale electrice pe calea feroviară. Înainte de acest an, se vor folosi semnale non-electrice care au aceeasi funcționalitate dar arată diferit @@ -1566,13 +1595,15 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :Liniar STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT :Poziţionarea copacilor în joc: {STRING} STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_HELPTEXT :Controlează apariția aleatoare a copacilor în joc. Este posibil ca această opțiune să afecteze industrii care depind de creșterea copacilor, cum ar fi fabricile de cherestea +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_NO_SPREAD :Cresc dar nu se extind {RED}(strică fabrica de cherestea) +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_RAINFOREST :Cresc dar se extind doar în păduri tropicale +STR_CONFIG_SETTING_EXTRA_TREE_PLACEMENT_SPREAD_ALL :Cresc și se extind peste tot STR_CONFIG_SETTING_TOOLBAR_POS :Poziţia barei principale de instrumente: {STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :Poziţia orizontală a barei principale în partea de sus a ecranului STR_CONFIG_SETTING_STATUSBAR_POS :Poziţia barei de stare: {STRING} STR_CONFIG_SETTING_STATUSBAR_POS_HELPTEXT :Poziţia orizontală a barei principale în partea de jos a ecranului STR_CONFIG_SETTING_SNAP_RADIUS :Raza "magnetică" a ferestrelor: {STRING} -STR_CONFIG_SETTING_SNAP_RADIUS_VALUE :{COMMA} pixel{P 0 "" i} STR_CONFIG_SETTING_SNAP_RADIUS_DISABLED :Dezactivat STR_CONFIG_SETTING_SOFT_LIMIT :Numărul maxim de ferestre nefixate: {STRING} STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA} @@ -1580,12 +1611,14 @@ STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :dezactivat STR_CONFIG_SETTING_ZOOM_MIN :Nivelul maxim de apropiere imagine: {STRING} STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Nivelul maxim de apropiere a câmpului vizual. Luați aminte că nivelele înalte ridică necesarul de memorie STR_CONFIG_SETTING_ZOOM_MAX :Nivelul maxim de îndepărtare imagine: {STRING} +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN :Rezoluția maximă pentru sprite-uri: {STRING} STR_CONFIG_SETTING_ZOOM_LVL_MIN :x4 STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :x2 STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :Normal STR_CONFIG_SETTING_ZOOM_LVL_OUT_2X :x2 STR_CONFIG_SETTING_ZOOM_LVL_OUT_4X :x4 STR_CONFIG_SETTING_ZOOM_LVL_OUT_8X :x8 +STR_CONFIG_SETTING_SPRITE_ZOOM_LVL_IN_2X :2x STR_CONFIG_SETTING_TOWN_GROWTH :Viteza de dezvoltare a oraşului: {STRING} STR_CONFIG_SETTING_TOWN_GROWTH_HELPTEXT :Viteza creşterii oraşelor STR_CONFIG_SETTING_TOWN_GROWTH_NONE :Deloc @@ -1600,8 +1633,7 @@ STR_CONFIG_SETTING_LARGER_TOWNS_DISABLED :deloc STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER :Multiplicator iniţial dimensiune oraş: {STRING} STR_CONFIG_SETTING_CITY_SIZE_MULTIPLIER_HELPTEXT :Dimensiunea medie a oraşelor mari relativ la oraşele normale, la începutul jocului -STR_CONFIG_SETTING_LINKGRAPH_INTERVAL :Actualizează graficul de distribuţie la fiecare {STRING} zi{P 0:2 "" le} -STR_CONFIG_SETTING_LINKGRAPH_TIME :Acordă {STRING} zi{P 0:2 "" le} pentru recalcularea graficului de distribuţie +STR_CONFIG_SETTING_LINKGRAPH_INTERVAL_HELPTEXT :Interval de timp între recalculările graficului de conexiuni. Fiecare recalculare calculează planurile unei componente ale graficului. Asta înseamnă că o valoare X pentru această setare nu va duce la actualizarea întregului grafic la fiecare X zile, ci doar o componentă va fi actualizată. Cu cât e mai mică valoarea, cu atât mai timp CPU va fi necesar pentru calcule. Cu cât e mai mare valoarea, cu atât va dura mai mult până va începe distribuția mărfii pe rute noi. STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :manual STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :asimetric STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :simetric @@ -1611,6 +1643,7 @@ STR_CONFIG_SETTING_DISTRIBUTION_MAIL :Modalitatea de STR_CONFIG_SETTING_DISTRIBUTION_MAIL_HELPTEXT :"simetric" înseamnă că aproximativ aceeași cantitate de poștă va fi expediată din stația A spre stația B, precum de la B la A. "asimetric" presupune expedierea de cantități arbitrare de poștă în fiecare direcție. "manual" înseamnă că repartizarea poștei nu va fi automatizată. STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED :Modalitatea de distribuire pentru clasa de cargo BLINDAT: {STRING} STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Modalitatea de distribuire pentru alte clase de cargo: {STRING} +STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"asimetric" înseamnă că pot fi trimise cantități diferite de marfă în ambele direcții. "manual" înseamnă că nu se va face distribuție automată pentru acele mărfuri. STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Acurateţea distribuţiei: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE :Efectul distanţei asupra cererii: {STRING} STR_CONFIG_SETTING_DEMAND_DISTANCE_HELPTEXT :Dacă setezi această valoare peste 0, distanța dintre stația origine A al mărfii și o posibilă stație B va afecta cantitatea de marfă trimisă din punctul A în B. Cu cât e mai departe B de A cu atât va fi mai mică cantitatea de marfă transportată. Cu cât mărești această valoare, cu atât mai puțină marfă se livrează spre destinațiile îndepărtate si cu atât mai multă la cele mai apropiate. @@ -1622,6 +1655,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :Afişează vite STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :Imperial (mph) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :Metric (km/h) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :SI (m/s) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :Unități de joc (dale/zi) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Unitate putere vehicule: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Afişează puterea vehiculelor în interfaţă folosind unităţile selectate @@ -1664,7 +1698,9 @@ STR_CONFIG_SETTING_ADVISORS :{ORANGE}Știri STR_CONFIG_SETTING_COMPANY :{ORANGE}Companie STR_CONFIG_SETTING_ACCOUNTING :{ORANGE}Contabilitate STR_CONFIG_SETTING_VEHICLES :{ORANGE}Vehicule +STR_CONFIG_SETTING_VEHICLES_PHYSICS :{ORANGE}Fizică STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}Direcţionare +STR_CONFIG_SETTING_LIMITATIONS :{ORANGE}Limitări STR_CONFIG_SETTING_ACCIDENTS :{ORANGE}Dezastre / Accidente STR_CONFIG_SETTING_GENWORLD :{ORANGE}Generare lume STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}Mediu @@ -1710,6 +1746,7 @@ STR_CONFIG_ERROR_OUT_OF_MEMORY :{WHITE}Fără m STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Nu s-au putut rezerva {BYTES} pentru cache al sprite-urilor. Mărimea cache-ului a fost redusă la {BYTES}. Performanța OpenTTD va fi redusă. Pentru a micșora cerințele jocului cu privire la memorie, poți încerca să dezactivezi modul grafic 32bpp și/sau reducerea numărului de nivele zoom # Video initalization errors +STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION :{WHITE}... GPU incompatibil. Accelerarea hardware este dezactivată # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} @@ -1749,7 +1786,6 @@ STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}Verific STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}Afişează setările pentru Inteligența Artificială şi pentru Scripturi Joc STR_INTRO_TOOLTIP_QUIT :{BLACK}Ieşi din 'OpenTTD' -STR_INTRO_TRANSLATION :{BLACK}Acestei traduceri îi lipse{P 0 "şte" "sc"} {NUM} text{P "" e}. Te rugăm să ajuti la îmbunătățirea OpenTTD înrolându-te ca traducător. Citește fișierul readme.txt pentru detalii. # Quit window STR_QUIT_CAPTION :{WHITE}Ieşire din joc @@ -1758,9 +1794,9 @@ STR_QUIT_YES :{BLACK}Da STR_QUIT_NO :{BLACK}Nu # Abandon game -STR_ABANDON_GAME_CAPTION :{WHITE}Ieşire din joc -STR_ABANDON_GAME_QUERY :{YELLOW}Eşti sigur că vrei să renunţi la acest joc? -STR_ABANDON_SCENARIO_QUERY :{YELLOW}Eşti sigur că vrei să renunţi la acest scenariu? +STR_ABANDON_GAME_CAPTION :{WHITE}Ieșire din joc +STR_ABANDON_GAME_QUERY :{YELLOW}Sigur vrei să renunți la acest joc? +STR_ABANDON_SCENARIO_QUERY :{YELLOW}Sigur vrei să renunți la acest scenariu? # Cheat window STR_CHEATS :{WHITE}Cheat-uri @@ -1770,8 +1806,8 @@ STR_CHEAT_CHANGE_COMPANY :{LTBLUE}Joacă STR_CHEAT_EXTRA_DYNAMITE :{LTBLUE}Buldozer magic (demolează industrii şi lucruri amovibile): {ORANGE}{STRING} STR_CHEAT_CROSSINGTUNNELS :{LTBLUE}Tunelele se pot intersecta: {ORANGE}{STRING} STR_CHEAT_NO_JETCRASH :{LTBLUE}Avioanele cu reacţie nu se vor prăbuşi (frecvent) pe aeroporturile mici: {ORANGE}{STRING} -STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Schimbă înălţimea maximă a harţii: {ORANGE}{NUM} -STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Schimbă înălţimea maxima a munţilor pe hartă +STR_CHEAT_EDIT_MAX_HL :{LTBLUE}Schimbă înălțimea maximă a hărții: {ORANGE}{NUM} +STR_CHEAT_EDIT_MAX_HL_QUERY_CAPT :{WHITE}Schimbă înălțimea maximă a munților pe hartă STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE :peisajul temperat STR_CHEAT_SWITCH_CLIMATE_SUB_ARCTIC_LANDSCAPE :peisajul sub-arctic STR_CHEAT_SWITCH_CLIMATE_SUB_TROPICAL_LANDSCAPE :peisajul sub-tropical @@ -1874,6 +1910,7 @@ STR_FACE_TIE :Cravată: STR_FACE_EARRING :Cercei: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Schimbă cravata sau cerceii + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multiplayer STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Numele jucătorului: @@ -1916,6 +1953,10 @@ STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Intră STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Actualizează serverul STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Actualizează informaţiile despre server +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Caută pe internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Caută servere publice în internet +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Caută în LAN +STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Caută servere în rețeaua locală STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Adaugă un server STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Adaugă un server la lista care va fi verificată pentru jocuri active STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Porneşte serverul @@ -1932,17 +1973,10 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Numele j STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Pune parolă STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protejează-ţi jocul cu o parolă dacă nu vrei să intre jucători neautorizaţi -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Publicat -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Alege între un joc publicat (prin Internet) și unul privat (reț) game -STR_NETWORK_START_SERVER_UNADVERTISED :Nu -STR_NETWORK_START_SERVER_ADVERTISED :Da -STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} clien{P t ţi} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Număr maxim de clienţi: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Alege un număr maxim de clienţi. Nu trebuie ocupate toate locurile. -STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} compan{P ie ii} STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Companii maxim: STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Limitează serverul la un anumit număr de companii -STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} spectator{P "" i} STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Spectatori maxim: STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Limitează serverul la un anumit număr de spectatori STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Limba vorbită: @@ -1950,46 +1984,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Ceilalţ STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Introduceţi un nume pentru joc -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Oricare -STR_NETWORK_LANG_ENGLISH :Engleză -STR_NETWORK_LANG_GERMAN :Germană -STR_NETWORK_LANG_FRENCH :Franceză -STR_NETWORK_LANG_BRAZILIAN :Braziliană -STR_NETWORK_LANG_BULGARIAN :Bulgară -STR_NETWORK_LANG_CHINESE :Chineză -STR_NETWORK_LANG_CZECH :Cehă -STR_NETWORK_LANG_DANISH :Daneză -STR_NETWORK_LANG_DUTCH :Olandeză -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finlandeză -STR_NETWORK_LANG_HUNGARIAN :Maghiară -STR_NETWORK_LANG_ICELANDIC :Islandeză -STR_NETWORK_LANG_ITALIAN :Italiană -STR_NETWORK_LANG_JAPANESE :Japoneză -STR_NETWORK_LANG_KOREAN :Coreană -STR_NETWORK_LANG_LITHUANIAN :Lituaniană -STR_NETWORK_LANG_NORWEGIAN :Norvegiană -STR_NETWORK_LANG_POLISH :Poloneză -STR_NETWORK_LANG_PORTUGUESE :Portugheză -STR_NETWORK_LANG_ROMANIAN :Română -STR_NETWORK_LANG_RUSSIAN :Rusă -STR_NETWORK_LANG_SLOVAK :Slovacă -STR_NETWORK_LANG_SLOVENIAN :Slovenă -STR_NETWORK_LANG_SPANISH :Spaniolă -STR_NETWORK_LANG_SWEDISH :Suedeză -STR_NETWORK_LANG_TURKISH :Turcă -STR_NETWORK_LANG_UKRAINIAN :Ucrainiană -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Croată -STR_NETWORK_LANG_CATALAN :Catalană -STR_NETWORK_LANG_ESTONIAN :Estonă -STR_NETWORK_LANG_GALICIAN :Galiciană -STR_NETWORK_LANG_GREEK :Greacă -STR_NETWORK_LANG_LATVIAN :Letonă -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Chatul jocului multiplayer @@ -2029,7 +2023,6 @@ STR_NETWORK_CONNECTING_6 :{BLACK}(6/6) Î STR_NETWORK_CONNECTING_SPECIAL_1 :{BLACK}Preluare informaţii joc... STR_NETWORK_CONNECTING_SPECIAL_2 :{BLACK}Preluare informaţii companie... ############ End of leave-in-this-order -STR_NETWORK_CONNECTING_WAITING :{BLACK}{NUM} clien{P t ţi} înaintea noastră STR_NETWORK_CONNECTING_DOWNLOADING_1 :{BLACK}{BYTES} descărcat până acum STR_NETWORK_CONNECTING_DOWNLOADING_2 :{BLACK}{BYTES} / {BYTES} descărcaţi până acum @@ -2040,15 +2033,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Companie # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clienţi -STR_NETWORK_COMPANY_LIST_SPECTATE :Observă -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Companie nouă # Network client list -STR_NETWORK_CLIENTLIST_KICK :Dă afară -STR_NETWORK_CLIENTLIST_BAN :Interzice acces -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Vorbeşte către toţi -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Vorbeşte către companie -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mesaj privat + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Client @@ -2135,10 +2123,11 @@ STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION :{WHITE}În ulti STR_NETWORK_SERVER_MESSAGE :*** {1:STRING} ############ Leave those lines in this order!! STR_NETWORK_SERVER_MESSAGE_GAME_PAUSED :Joc în pauză ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Jocul este încă în pauză ({STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Jocul este încă în pauză ({STRING}, {STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Jocul este încă în pauză ({STRING}, {STRING}, {STRING}) -STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Jocul este încă în pauză ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_1 :Jocul încă este în pauză ({STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_2 :Jocul încă este în pauză ({STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_3 :Jocul încă este în pauză ({STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_4 :Jocul încă este în pauză ({STRING}, {STRING}, {STRING}, {STRING}) +STR_NETWORK_SERVER_MESSAGE_GAME_STILL_PAUSED_5 :Jocul încă este în pauză ({STRING}, {STRING}, {STRING}, {STRING}, {STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_UNPAUSED :Jocul continuă ({STRING}) STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :număr de jucători STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :conectare clienţi @@ -2156,6 +2145,7 @@ STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} ş STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} a dat {2:CURRENCY_LONG} către {1:STRING} STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Serverul a închis conexiunea STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Serverul este repornit...{}Vă rugăm aşteptaţi... +STR_NETWORK_MESSAGE_KICKED :*** {STRING} a fost dat afară. Motiv: ({STRING}) # Content downloading window STR_CONTENT_TITLE :{WHITE}Descărcare resurse online @@ -2178,7 +2168,7 @@ STR_CONTENT_FILTER_TITLE :{BLACK}Filtru n STR_CONTENT_OPEN_URL :{BLACK}Vizitează site-ul web STR_CONTENT_OPEN_URL_TOOLTIP :{BLACK}Vizitează site-ul web al acestei resurse STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Descarcă -STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Porneşte descărcarea resurselor selectate +STR_CONTENT_DOWNLOAD_CAPTION_TOOLTIP :{BLACK}Pornește descărcarea resurselor selectate STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total de descărcat: {WHITE}{BYTES} STR_CONTENT_DETAIL_TITLE :{SILVER}INFO RESURSĂ STR_CONTENT_DETAIL_SUBTITLE_UNSELECTED :{SILVER}Această resursă nu a fost selectată pentru descărcare @@ -2220,7 +2210,7 @@ STR_CONTENT_DOWNLOAD_PROGRESS_SIZE :{WHITE}{BYTES} # Content downloading error messages STR_CONTENT_ERROR_COULD_NOT_CONNECT :{WHITE}Conectare la server eşuată... -STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Descărcare eşuată +STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD :{WHITE}Descărcare eșuată STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_CONNECTION_LOST :{WHITE}... conexiune întreruptă STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE :{WHITE}... fişierul nu poate fi scris STR_CONTENT_ERROR_COULD_NOT_EXTRACT :{WHITE}Fişierul descărcat nu a putut fi decompresat @@ -2230,6 +2220,8 @@ STR_MISSING_GRAPHICS_SET_MESSAGE :{BLACK}OpenTTD STR_MISSING_GRAPHICS_YES_DOWNLOAD :{BLACK}Da, descarcă pachetele grafice STR_MISSING_GRAPHICS_NO_QUIT :{BLACK}Nu, ieși din OpenTTD +STR_MISSING_GRAPHICS_ERROR_TITLE :{WHITE}Descărcarea a eșuat +STR_MISSING_GRAPHICS_ERROR :{BLACK}Descărcarea graficii a eșuat.{}Vă rugăm descărcați manual grafica. # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Optiuni transparenţă @@ -2249,6 +2241,7 @@ STR_LINKGRAPH_LEGEND_CAPTION :{BLACK}Legenda STR_LINKGRAPH_LEGEND_ALL :{BLACK}Toate STR_LINKGRAPH_LEGEND_NONE :{BLACK}Nici una STR_LINKGRAPH_LEGEND_SELECT_COMPANIES :{BLACK}Alege companiile care vor fi afișate +STR_LINKGRAPH_LEGEND_COMPANY_TOOLTIP :{BLACK}{STRING}{}{COMPANY} # Linkgraph legend window and linkgraph legend in smallmap STR_LINKGRAPH_LEGEND_UNUSED :{TINY_FONT}{BLACK}nefolosit @@ -2375,7 +2368,10 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL :{BLACK}Construi STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL :{BLACK}Construieşte tunel pentru tramvaie. Shift comută între construire/afişare cost estimat STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD :{BLACK}Comutator pentru construcţie/înlăturare şosele STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS :{BLACK}Comută construcţie/înlăturare pentru şine de tramvai +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD :{BLACK}Convertește/Modernizează tipul drumului. Shift comută construcția/afișarea costului estimat +STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM :{BLACK}Convertește/Modernizează tipul tramvaiului. Shift comută construcția/afișarea costului estimat +STR_ROAD_NAME_TRAM :Șină de tramvai # Road depot construction window STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION :{WHITE}Orientarea autobazei @@ -2403,7 +2399,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construi STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Amplasează o baliză ce poate fi utilizată pentru direcţionare. Shift comută între amplasare/afişare cost estimat STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Construieşte apeduct. Shift comută între construire/afişare cost estimat STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Defineşte zona apei.{}Creează un canal, excepţie când Ctrl este apăsat la nivelul mării, ce va determina inundarea împrejurimilor -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Amplasează râuri +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Amplasează râuri. Ctrl selectează aria pe diagonală # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orientarea şantierului naval @@ -2463,6 +2459,11 @@ STR_TREES_RANDOM_TYPE :{BLACK}Arbori d STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}Plantează arbori din diverse specii la întâmplare. Shift comută între plantare/afişare cost estimat STR_TREES_RANDOM_TREES_BUTTON :{BLACK}Arbori aleatori STR_TREES_RANDOM_TREES_TOOLTIP :{BLACK}Plantează aleator arbori pe uscat +STR_TREES_MODE_NORMAL_BUTTON :{BLACK}Normal +STR_TREES_MODE_NORMAL_TOOLTIP :{BLACK}Plantează copaci trăgându-i peste peisaj. +STR_TREES_MODE_FOREST_SM_BUTTON :{BLACK}Dumbravă +STR_TREES_MODE_FOREST_LG_BUTTON :{BLACK}Pădure +STR_TREES_MODE_FOREST_LG_TOOLTIP :{BLACK}Plantează păduri întinse prin tragerea peste peisaj. # Land generation window (SE) STR_TERRAFORM_TOOLBAR_LAND_GENERATION_CAPTION :{WHITE}Generator suprafaţă uscat @@ -2519,6 +2520,8 @@ STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Cost: {Y STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospectează STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Construieşte STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Finanţează +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES :{BLACK}Elimină toate industriile +STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES_QUERY :{YELLOW}Sigur vrei să elimini toate industriile? # Industry cargoes window STR_INDUSTRY_CARGOES_INDUSTRY_CAPTION :{WHITE}Lanţ industrial pentru industria {STRING} @@ -2539,6 +2542,7 @@ STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}Alege in # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}Informaţii teren +STR_LAND_AREA_INFORMATION_LOCATION_TOOLTIP :{BLACK}Centrează vizorul principal pe locația dalei. Ctrl+clic deschide un vizor nou pe locația dalei STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}Costul demolării: {LTBLUE}nu este cazul STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}Costul demolării: {RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}Încasări după curăţare: {LTBLUE}{CURRENCY_LONG} @@ -2563,6 +2567,7 @@ STR_LANG_AREA_INFORMATION_RAIL_TYPE :{BLACK}Tip șin STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Tip de tramvai: {LTBLUE}{STRING} STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Limită viteză pe calea ferată: {LTBLUE}{VELOCITY} STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Viteza limită a drumului: {LTBLUE}{VELOCITY} +STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Limită de viteză tramvai: {LTBLUE}{VELOCITY} # Description of land area of different tiles STR_LAI_CLEAR_DESCRIPTION_ROCKS :Stânci @@ -2663,21 +2668,37 @@ STR_ABOUT_COPYRIGHT_OPENTTD :{BLACK}OpenTTD # Framerate display window STR_FRAMERATE_CAPTION :{WHITE}FPS +STR_FRAMERATE_CAPTION_SMALL :{STRING}{WHITE} ({DECIMAL}x) +STR_FRAMERATE_RATE_GAMELOOP :{BLACK}Viteza simulării: {STRING} STR_FRAMERATE_RATE_GAMELOOP_TOOLTIP :{BLACK}Număr de evenimente de joc simulate per secundă. +STR_FRAMERATE_RATE_BLITTER_TOOLTIP :{BLACK}Numărul de cadre video randate per secundă. +STR_FRAMERATE_SPEED_FACTOR :{BLACK}Factorul actual de viteză a jocului: {DECIMAL}x STR_FRAMERATE_AVERAGE :{WHITE}Medie STR_FRAMERATE_MEMORYUSE :{WHITE}Memorie STR_FRAMERATE_DATA_POINTS :{BLACK}Date bazate pe măsurători {COMMA} STR_FRAMERATE_MS_GOOD :{LTBLUE}{DECIMAL} ms +STR_FRAMERATE_FPS_GOOD :{LTBLUE}{DECIMAL} cadre/s +STR_FRAMERATE_FPS_WARN :{YELLOW}{DECIMAL} cadre/s STR_FRAMERATE_FPS_BAD :{RED}{DECIMAL} cadre/s STR_FRAMERATE_BYTES_WARN :{YELLOW}{BYTES} +STR_FRAMERATE_BYTES_BAD :{RED}{BYTES} STR_FRAMERATE_GRAPH_MILLISECONDS :{TINY_FONT}{COMMA} ms +STR_FRAMERATE_GRAPH_SECONDS :{TINY_FONT}{COMMA} s ############ Leave those lines in this order!! +STR_FRAMERATE_GL_LINKGRAPH :{BLACK} Decalaj grafic de conexiuni: +STR_FRAMERATE_DRAWING :{BLACK}Randare grafică: +STR_FRAMERATE_DRAWING_VIEWPORTS :{BLACK} Vizoare globale: STR_FRAMERATE_VIDEO :{BLACK}Ieșire video: STR_FRAMERATE_GAMESCRIPT :{BLACK} Script joc: +STR_FRAMERATE_AI :{BLACK} IA {NUM} {STRING} ############ End of leave-in-this-order ############ Leave those lines in this order!! STR_FRAMETIME_CAPTION_GAMELOOP :Buclă de joc STR_FRAMETIME_CAPTION_GL_ECONOMY :Manipularea încărcăturilor +STR_FRAMETIME_CAPTION_DRAWING :Randare grafică +STR_FRAMETIME_CAPTION_DRAWING_VIEWPORTS :Randarea vizorului global +STR_FRAMETIME_CAPTION_SOUND :Mixaj de sunet +STR_FRAMETIME_CAPTION_AI :IA {NUM} {STRING} ############ End of leave-in-this-order @@ -2704,6 +2725,8 @@ STR_SAVELOAD_DETAIL_NOT_AVAILABLE :{BLACK}Nicio in STR_SAVELOAD_DETAIL_COMPANY_INDEX :{SILVER}{COMMA}: {WHITE}{STRING} STR_SAVELOAD_DETAIL_GRFSTATUS :{SILVER}NewGRF: {WHITE}{STRING} STR_SAVELOAD_FILTER_TITLE :{BLACK}Filtrare după: +STR_SAVELOAD_OVERWRITE_TITLE :{WHITE}Suprascrie fișierul +STR_SAVELOAD_DIRECTORY :{STRING} (listă) STR_SAVELOAD_OSKTITLE :{BLACK}Introduceţi un nume pentru salvare @@ -2715,6 +2738,11 @@ STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Nr. de oraşe: STR_MAPGEN_DATE :{BLACK}Data: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Nr. de industrii: +STR_MAPGEN_HEIGHTMAP_HEIGHT :{BLACK}Cel mai înalt vârf: +STR_MAPGEN_SNOW_COVERAGE_UP :{BLACK}Mărește acoperirea cu zăpadă cu zece procente +STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}Mărește întinderea deșertului cu zece procente +STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}Reduce întinderea deșertului cu zece procente +STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_LAND_GENERATOR :{BLACK}Generator de teren: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Tip teren: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Nivelul mării: @@ -2740,6 +2768,9 @@ STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Nume har STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Dimensiune: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} x {NUM} +STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT :{WHITE}Cel mai înalt vârf +STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}Acoperire cu zăpadă (în %) +STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}Acoperire cu deșert (în %) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Modifică anul de început # SE Map generation @@ -2812,7 +2843,11 @@ STR_NEWGRF_SETTINGS_VERSION :{BLACK}Versiune STR_NEWGRF_SETTINGS_MIN_VERSION :{BLACK}Vers. minimă compatibilă: {SILVER}{NUM} STR_NEWGRF_SETTINGS_MD5SUM :{BLACK}MD5sum: {SILVER}{STRING} STR_NEWGRF_SETTINGS_PALETTE :{BLACK}Paletă: {SILVER}{STRING} +STR_NEWGRF_SETTINGS_PALETTE_DEFAULT :Implicit (D) +STR_NEWGRF_SETTINGS_PALETTE_DEFAULT_32BPP :Implicit (D) / 32 bpp +STR_NEWGRF_SETTINGS_PALETTE_LEGACY :Legacy (W) STR_NEWGRF_SETTINGS_PARAMETER :{BLACK}Parametri: {SILVER}{STRING} +STR_NEWGRF_SETTINGS_PARAMETER_NONE :Nimic STR_NEWGRF_SETTINGS_NO_INFO :{BLACK}Nicio informaţie disponibilă STR_NEWGRF_SETTINGS_NOT_FOUND :{RED}Niciun fisier potrivit @@ -2820,9 +2855,12 @@ STR_NEWGRF_SETTINGS_DISABLED :{RED}Dezactivat STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}Incompatibil cu această versiune de OpenTTD # NewGRF save preset window +STR_SAVE_PRESET_CAPTION :{WHITE}Salvează presetarea +STR_SAVE_PRESET_LIST_TOOLTIP :{BLACK}Lista presetărilor disponibile; alegeți una pentru salvare cu numele de mai jos STR_SAVE_PRESET_TITLE :{BLACK}Adaugă denumire presetare STR_SAVE_PRESET_CANCEL :{BLACK}Anulează STR_SAVE_PRESET_CANCEL_TOOLTIP :{BLACK}Nu schimba setarea implicită +STR_SAVE_PRESET_SAVE :{BLACK}Salvează STR_SAVE_PRESET_SAVE_TOOLTIP :{BLACK}Salvează setarea pe numele selectat # NewGRF parameters window @@ -2933,7 +2971,6 @@ STR_INVALID_VEHICLE : STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Jocul a fost salvat într-o versiune fără suport pentru tramvaie. Toate tramvaiele au fost eliminate @@ -4074,6 +4134,7 @@ STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Doar un STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Imagine de dimensiune foarte mare STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Imaginea capturată va avea o dimensiune de {COMMA} x {COMMA} pixeli. Realizarea unei capturi va dura ceva timp. Dorești să continui? +STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY :{WHITE}Harta înălțimilor s-a salvat cu succes ca '{STRING}'. Cel mai înalt vârf este {NUM} STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Imagine salvată cu succes pe disc în fişierul '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}Imaginea nu a putut fi capturată! @@ -4127,6 +4188,7 @@ STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... nu a STR_ERROR_CURRENCY_REQUIRED :{WHITE}... ai nevoie de {CURRENCY_LONG} STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Nu poţi plăti creditul... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Nu poţi dona din banii împrumutaţi de la bancă... +STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}Nu se pot da bani acestei companii... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Nu se poate cumpăra compania... STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Nu se poate construi sediul companiei... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Nu se pot cumpăra 25% din acţiunile acestei companii... @@ -4239,7 +4301,7 @@ STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT :{WHITE}Trenuril STR_ERROR_TRAIN_TOO_LONG :{WHITE}Tren prea lung STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE :{WHITE}Nu se poate inversa direcţia vehiculului... STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE_MULTIPLE_UNITS :{WHITE}... este alcătuit din mai multe unități -STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Tipuri de sine incompatibile +STR_ERROR_INCOMPATIBLE_RAIL_TYPES :Tipurile de șine sunt incompatibile STR_ERROR_CAN_T_MOVE_VEHICLE :{WHITE}Nu se poate muta vehiculul... STR_ERROR_REAR_ENGINE_FOLLOW_FRONT :{WHITE}Al doilea vagon+motor va avea mereu aceeasi destinatie ca si primul @@ -4252,6 +4314,7 @@ STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :Tip incorect de STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE} este prea lung după înlocuire STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}Nicio regulă autoînlocuire/reînnoire aplicată STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(fonduri limitate) +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO :{WHITE}Noul vehicul nu poate transporta {STRING} # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}Combinaţie de linii imposibilă @@ -4279,6 +4342,10 @@ STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Nu se po STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Nu pot înlătura şina de tramvai de aici... STR_ERROR_THERE_IS_NO_ROAD :{WHITE}...nu există drum aici STR_ERROR_THERE_IS_NO_TRAMWAY :{WHITE}...nu există şină de tramvai aici +STR_ERROR_CAN_T_CONVERT_ROAD :{WHITE}Tipul de drum nu poate fi convertit aici... +STR_ERROR_NO_SUITABLE_ROAD :{WHITE}Niciun drum adecvat +STR_ERROR_NO_SUITABLE_TRAMWAY :{WHITE}Niciun tramvai adecvat +STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... tramvai incompatibil # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Nu pot construi un canal aici... @@ -4407,8 +4474,8 @@ STR_ERROR_CAN_T_INSERT_NEW_ORDER :{WHITE}Nu se po STR_ERROR_CAN_T_DELETE_THIS_ORDER :{WHITE}Nu se poate şterge această comandă... STR_ERROR_CAN_T_MODIFY_THIS_ORDER :{WHITE}Nu se poate modifica această comandă... STR_ERROR_CAN_T_MOVE_THIS_ORDER :{WHITE}Nu pot muta acest ordin... -STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Nu pot renunta la comanda actuala... -STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Nu pot sări la ordinul selectat... +STR_ERROR_CAN_T_SKIP_ORDER :{WHITE}Nu se poate sări peste comanda actuală... +STR_ERROR_CAN_T_SKIP_TO_ORDER :{WHITE}Nu pot sări la comanda selectată... STR_ERROR_CAN_T_COPY_SHARE_ORDER :{WHITE}... vehiculul nu poate ajunge la toate staţiile STR_ERROR_CAN_T_ADD_ORDER :{WHITE}... vehiculul nu poate ajunge la acea staţie STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... un vehicul care are acest ordin nu poate ajunge la acea staţie @@ -4434,15 +4501,15 @@ STR_ERROR_CAN_T_DELETE_SIGN :{WHITE}Nu pot s STR_DESKTOP_SHORTCUT_COMMENT :Un joc de simulare bazat pe Transport Tycoon Deluxe # Translatable descriptions in media/baseset/*.ob* files -STR_BASEGRAPHICS_DOS_DESCRIPTION :Setul grafic original al Transport Tycoon Deluxe pentru DOS. -STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Setul grafic original al Transport Tycoon Deluxe pentru DOS (ediţia germană). -STR_BASEGRAPHICS_WIN_DESCRIPTION :Setul grafic original al Transport Tycoon Deluxe pentru Windows. -STR_BASESOUNDS_DOS_DESCRIPTION :Setul de sunete original al Transport Tycoon Deluxe pentru DOS. -STR_BASESOUNDS_WIN_DESCRIPTION :Setul de sunete original al Transport Tycoon Deluxe pentru Windows. +STR_BASEGRAPHICS_DOS_DESCRIPTION :Grafica originală a ediției Transport Tycoon Deluxe pentru DOS. +STR_BASEGRAPHICS_DOS_DE_DESCRIPTION :Grafica originală a Transport Tycoon Deluxe pentru DOS (ediția germană). +STR_BASEGRAPHICS_WIN_DESCRIPTION :Grafica originală a ediției Transport Tycoon Deluxe pentru Windows. +STR_BASESOUNDS_DOS_DESCRIPTION :Sunetele originale ale ediției Transport Tycoon Deluxe pentru DOS. +STR_BASESOUNDS_WIN_DESCRIPTION :Sunetele originale ale Transport Tycoon Deluxe pentru Windows. STR_BASESOUNDS_NONE_DESCRIPTION :Un set de sunete fără nici un sunet inclus. -STR_BASEMUSIC_WIN_DESCRIPTION :Setul de muzică original al Transport Tycoon Deluxe pentru Windows. -STR_BASEMUSIC_DOS_DESCRIPTION :Setul de muzică original al Transport Tycoon Deluxe pentru DOS. -STR_BASEMUSIC_TTO_DESCRIPTION :Setul de muzică original al Transport (Original/World Editor) pentru DOS. +STR_BASEMUSIC_WIN_DESCRIPTION :Muzica originală a ediției Transport Tycoon Deluxe pentru Windows. +STR_BASEMUSIC_DOS_DESCRIPTION :Muzica originală a ediției Transport Tycoon Deluxe pentru DOS. +STR_BASEMUSIC_TTO_DESCRIPTION :Setul original de muzică al Transport Tycoon (Original/World Editor) pentru DOS. STR_BASEMUSIC_NONE_DESCRIPTION :Un set de muzică fără muzică inclusă. ##id 0x2000 @@ -4831,6 +4898,7 @@ STR_FORMAT_BUOY_NAME :{TOWN} Baliza STR_FORMAT_BUOY_NAME_SERIAL :{TOWN} Baliza #{COMMA} STR_FORMAT_COMPANY_NUM :(Companie {COMMA}) STR_FORMAT_GROUP_NAME :Grup {COMMA} +STR_FORMAT_GROUP_VEHICLE_NAME :{GROUP} #{COMMA} STR_FORMAT_INDUSTRY_NAME :{TOWN} {STRING} STR_FORMAT_WAYPOINT_NAME :Halta {TOWN} STR_FORMAT_WAYPOINT_NAME_SERIAL :Halta {TOWN} #{COMMA} diff --git a/src/lang/russian.txt b/src/lang/russian.txt index 182d9d3f2b..ed8f4cfc8a 100644 --- a/src/lang/russian.txt +++ b/src/lang/russian.txt @@ -1098,7 +1098,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Малайзи STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Левостороннее STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Правостороннее -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Названия городов +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Названия городов: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Язык, который будет использоваться для выбора названий населённых пунктов ############ start of townname region @@ -1138,6 +1138,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Каждый г STR_GAME_OPTIONS_LANGUAGE :{BLACK}Язык STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Язык пользовательского интерфейса +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% перевед{P ён ено ено}) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Полноэкранный режим STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Включить/выключить полноэкранный режим @@ -1148,9 +1149,12 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :Другое STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Аппаратное ускорение -STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Поставьте отметку, чтобы включить аппаратное ускорение в OpenTTD. Но для этого игру придётся перезапустить. +STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Включить/выключить аппаратное ускорение. После этого игру потребуется перезапустить. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Эта настройка будет применена только после перезапуска игры +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Вертикальная синхронизация +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Включить/выключить вертикальную синхронизацию. После этого игру потребуется перезапустить. Работает только при включённом аппаратном ускорении. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Размер элементов интерфейса STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Выберите размер элементов интерфейса @@ -1263,7 +1267,7 @@ STR_DISASTER_NONE :нет STR_DISASTER_REDUCED :сниженная STR_DISASTER_NORMAL :обычная -STR_SUBSIDY_X1_5 :x1.5 +STR_SUBSIDY_X1_5 :x1,5 STR_SUBSIDY_X2 :x2 STR_SUBSIDY_X3 :x3 STR_SUBSIDY_X4 :x4 @@ -1273,6 +1277,8 @@ STR_TERRAIN_TYPE_FLAT :Равнинн STR_TERRAIN_TYPE_HILLY :Холмистый STR_TERRAIN_TYPE_MOUNTAINOUS :Преимущественно горный STR_TERRAIN_TYPE_ALPINIST :Исключительно горный +STR_TERRAIN_TYPE_CUSTOM :Установить высоту вручную +STR_TERRAIN_TYPE_CUSTOM_VALUE :Установленная высота ({NUM}) STR_CITY_APPROVAL_PERMISSIVE :дозволяющее STR_CITY_APPROVAL_TOLERANT :терпимое @@ -1285,6 +1291,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Расш STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Фильтр: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Развернуть всё STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Свернуть всё +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Сбросить все значения STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(нет описания) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Значение по умолчанию: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Тип настроек: {ORANGE}{STRING} @@ -1293,6 +1300,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Настрой STR_CONFIG_SETTING_TYPE_GAME_INGAME :Настройки игры (содержатся в файлах сохранений; действительны только для текущей игры) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Настройки компании (содержатся в файлах сохранений; действительны только для новых игр) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Настройки компании (содержатся в файлах сохранений; действительны только для текущей игры) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Внимание! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Вы уверены, что хотите сбросить все настройки игры к значениям по умолчанию? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Категория: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Тип: @@ -1356,6 +1365,10 @@ STR_CONFIG_SETTING_DISASTERS_HELPTEXT :Включен STR_CONFIG_SETTING_CITY_APPROVAL :Отношение городского совета к реструктуризации окрестностей: {STRING} STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :Выберите уровень влияния шума и загрязнения окружающей среды компаниями на их рейтинг в городах и возможность дальнейшего строительства около городов +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :Максимальная высота объектов на карте: {STRING} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT :Установить максимальное значение высоты гор на карте. «(Автовыбор)» подберёт приемлемое значение после создания ландшафта. +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE :{NUM} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_AUTO :(автовыбор) STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}Невозможно изменить максимальную высоту. На карте есть горы выше этого значения. STR_CONFIG_SETTING_AUTOSLOPE :Разрешить изм. ландшафта под зданиями, дорогами и т. д. (автоспуски): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :Разрешить изменение ландшафта под домами и дорогами, не требуя их сноса @@ -1500,8 +1513,13 @@ STR_CONFIG_SETTING_INDUSTRY_DENSITY_HELPTEXT :Выберит STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :Макс. расстояние от края карты до предприятий нефтяной индустрии: {STRING} STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :Эта настройка ограничивает расстояние от края карты до нефтяных платформ и нефтеперерабатывающих заводов. Таким образом, на краях карты, оканчивающихся водой, они будут строиться у берега. На картах размером более 256 это значение будет соответственно увеличено. STR_CONFIG_SETTING_SNOWLINE_HEIGHT :Высота снеговой линии: {STRING} -STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Укажите, на какой высоте в субарктическом климате устанавливается снеговой покров. Наличие снега влияет на расстановку предприятий и на условия роста городов. -STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Укажите приблизительное количество пустыни на тропическом ландшафте. Пустыня также влияет на промышленное производство. Используется только во время создания карты +STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :Это значение определяет, на какой высоте в субарктическом климате устанавливается снеговой покров. Наличие снега влияет на расстановку предприятий и на условия роста городов.{}Значение может быть установлено только в редакторе сценариев; иначе оно рассчитывается в зависимости от значения «снежного покрытия». +STR_CONFIG_SETTING_SNOW_COVERAGE :Снежное покрытие: {STRING} +STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :Это значение определяет примерную относительную площадь суши, покрытой снегом в субарктическом климате.Наличие снега влияет на расстановку предприятий и на условия роста городов.{}Используется только при создании карты. Земля чуть выше уровня моря никогда не покрывается снегом. +STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% +STR_CONFIG_SETTING_DESERT_COVERAGE :Песчаное покрытие: {STRING} +STR_CONFIG_SETTING_DESERT_COVERAGE_HELPTEXT :Это значение определяет примерную относительную площадь суши, покрытой песком в тропическом климате. Пустыни влияют на расположение предприятий.{}Используется только при создании карты. +STR_CONFIG_SETTING_DESERT_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :Грубость ландшафта: {STRING} STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(Только для TerraGenesis){}Выберите количество гор и холмов на карте. На гладком ландшафте холмов немного и они более пологие. На грубом - много гор, и ландшафт может показаться слишком однообразным. STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :Очень гладкий @@ -2124,6 +2142,9 @@ STR_FACE_TIE :Галстук: STR_FACE_EARRING :Серьга: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Изменить галстук или серьгу +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Публичный +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Частный + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Сетевая игра STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Имя игрока: @@ -2186,10 +2207,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Назв STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Установить пароль STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Защитите вашу игру паролем, если не хотите, чтобы к ней могли подключиться посторонние. -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Интернет -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Выберите между игрой через Интернет, либо в локальной сети -STR_NETWORK_START_SERVER_UNADVERTISED :Нет -STR_NETWORK_START_SERVER_ADVERTISED :Да +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Видимость +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Видимость вашего сервера в публичном списке STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клиент{P "" а ов} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. количество клиентов: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Выбор максимального числа клиентов. Не все места должны быть заняты @@ -2204,46 +2223,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Друг STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Введите название сетевой игры -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Любой -STR_NETWORK_LANG_ENGLISH :Английский -STR_NETWORK_LANG_GERMAN :Немецкий -STR_NETWORK_LANG_FRENCH :Французский -STR_NETWORK_LANG_BRAZILIAN :Бразильский -STR_NETWORK_LANG_BULGARIAN :Болгарский -STR_NETWORK_LANG_CHINESE :Китайский -STR_NETWORK_LANG_CZECH :Чешский -STR_NETWORK_LANG_DANISH :Датский -STR_NETWORK_LANG_DUTCH :Нидерландский -STR_NETWORK_LANG_ESPERANTO :Эсперанто -STR_NETWORK_LANG_FINNISH :Финский -STR_NETWORK_LANG_HUNGARIAN :Венгерский -STR_NETWORK_LANG_ICELANDIC :Исландский -STR_NETWORK_LANG_ITALIAN :Итальянский -STR_NETWORK_LANG_JAPANESE :Японский -STR_NETWORK_LANG_KOREAN :Корейский -STR_NETWORK_LANG_LITHUANIAN :Литовский -STR_NETWORK_LANG_NORWEGIAN :Норвежский -STR_NETWORK_LANG_POLISH :Польский -STR_NETWORK_LANG_PORTUGUESE :Португальский -STR_NETWORK_LANG_ROMANIAN :Румынский -STR_NETWORK_LANG_RUSSIAN :Русский -STR_NETWORK_LANG_SLOVAK :Словацкий -STR_NETWORK_LANG_SLOVENIAN :Словенский -STR_NETWORK_LANG_SPANISH :Испанский -STR_NETWORK_LANG_SWEDISH :Шведский -STR_NETWORK_LANG_TURKISH :Турецкий -STR_NETWORK_LANG_UKRAINIAN :Украинский -STR_NETWORK_LANG_AFRIKAANS :Африкаанс -STR_NETWORK_LANG_CROATIAN :Хорватский -STR_NETWORK_LANG_CATALAN :Каталанский -STR_NETWORK_LANG_ESTONIAN :Эстонский -STR_NETWORK_LANG_GALICIAN :Галисийский -STR_NETWORK_LANG_GREEK :Греческий -STR_NETWORK_LANG_LATVIAN :Латвийский -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Состояние сетевой игры @@ -2291,19 +2270,23 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Откл STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Сервер защищён. Введите пароль. STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Компания защищена. Введите пароль. -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Список клиентов # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Список клиентов -STR_NETWORK_COMPANY_LIST_SPECTATE :Наблюдать -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Новая компания # Network client list -STR_NETWORK_CLIENTLIST_KICK :Отключить -STR_NETWORK_CLIENTLIST_BAN :Бан -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Сказать всем -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Говорить с компанией -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Личное сообщение +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Сетевая игра +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Имя +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Ваше игровое имя +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Ваше игровое имя +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Действия администратора, применимые к этому клиенту + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Отключить +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Заблокировать + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Подтверждение действия +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}Отключить игрока «{STRING}»? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}Заблокировать игрока «{STRING}»? STR_NETWORK_SERVER :Сервер STR_NETWORK_CLIENT :Клиент @@ -2348,6 +2331,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}Не у STR_NETWORK_ERROR_CLIENT_START :{WHITE}Не удалось соединиться STR_NETWORK_ERROR_TIMEOUT :{WHITE}Истекло время ожидания соединения #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Произошла ошибка протокола, и соединение было закрыто +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Не указано имя игрока. Его можно ввести в верхней части окна «Сетевая игра». STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Версия этого клиента не совместима с версией сервера STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Неверный пароль STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Сервер переполнен @@ -2360,6 +2344,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Вы н STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Ваш компьютер работает слишком медленно и не поспевает за сервером STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Ваш компьютер тратит много времени на загрузку карты STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Ваш компьютер тратит много времени на подключение к серверу +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Неверно указано имя игрока ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :общая ошибка @@ -2382,6 +2367,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :пароль н STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :время вышло STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :загрузка карты заняла слишком много времени STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :обработка карты заняла слишком много времени +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :имя клиента некорректно ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Подключение утеряно @@ -2691,7 +2677,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Стро STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Буи помогают в навигации на больших расстояниях; используйте их как маршрутные точки. При нажатом Shift - оценка стоимости строительства. STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Строительство акведуков. При нажатом Shift - оценка стоимости строительства. STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Создать канал.{}При зажатом Ctrl клетка на уровне моря наполняется водой. -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Разместить реки. +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Создание рек на карте. При нажатом Ctrl они создаются по диагонали. # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Направление дока @@ -3066,6 +3052,17 @@ STR_MAPGEN_BY :{BLACK}× STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}Количество городов: STR_MAPGEN_DATE :{BLACK}Дата: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}Кол-во предпр.: +STR_MAPGEN_HEIGHTMAP_HEIGHT :{BLACK}Высочайшая вершина: +STR_MAPGEN_HEIGHTMAP_HEIGHT_UP :{BLACK}Увеличить максимальную высоту гор на карте на 1 +STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN :{BLACK}Уменьшить максимальную высоту гор на карте на 1 +STR_MAPGEN_SNOW_COVERAGE :{BLACK}Снежное покрытие: +STR_MAPGEN_SNOW_COVERAGE_UP :{BLACK}Увеличить площадь снежного покрытия на 10% +STR_MAPGEN_SNOW_COVERAGE_DOWN :{BLACK}Уменьшить площадь снежного покрытия на 10% +STR_MAPGEN_SNOW_COVERAGE_TEXT :{BLACK}{NUM}% +STR_MAPGEN_DESERT_COVERAGE :{BLACK}Песчаное покрытие: +STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}Увеличить площадь песчаного покрытия на 10% +STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}Уменьшить площадь песчаного покрытия на 10% +STR_MAPGEN_DESERT_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_LAND_GENERATOR :{BLACK}Генератор ландшафта: STR_MAPGEN_TERRAIN_TYPE :{BLACK}Тип ландшафта: STR_MAPGEN_QUANTITY_OF_SEA_LAKES :{BLACK}Количество морей и озёр: @@ -3091,7 +3088,10 @@ STR_MAPGEN_HEIGHTMAP_NAME :{BLACK}Назв STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}Размер: STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} × {NUM} +STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT :{WHITE}Максимальная высота STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT :{WHITE}Cамая высокая вершина +STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}Снежное покрытие (в %) +STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}Песчаное покрытие (в %) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}Изменить год начала игры # SE Map generation @@ -3277,7 +3277,7 @@ STR_NEWGRF_BROKEN :{WHITE}Файл STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Меняется состояние локомотива «{1:ENGINE}», находящегося вне депо STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Меняется длина транспорта «{1:ENGINE}», находящегося вне депо STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Он изменил ёмкость ТС «{1:ENGINE}» за пределами депо или без задания на переоборудование -STR_BROKEN_VEHICLE_LENGTH :{WHITE}Поезд «{VEHICLE}», принадлежащий «{COMPANY}», имеет неправильную длину. Вероятно, это вызвано проблемами в файле новой графики (NewGRF). Игра может рассинхронизироваться или вылететь. +STR_BROKEN_VEHICLE_LENGTH :{WHITE}Поезд «{VEHICLE}», принадлежащий «{COMPANY}», имеет неправильную длину. Вероятно, это вызвано ошибками в одном из модулей NewGRF. Игра может рассинхронизироваться или вылететь. STR_NEWGRF_BUGGY :{WHITE}NewGRF «{0:STRING}» предоставляет неверную информацию. STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Информация о вместимости/переоборудовании для локомотива «{1:ENGINE}» после постройки отличается от сведений в списке покупки, что может помешать функции автообновления/автозамены корректно произвести переоборудование. @@ -4520,6 +4520,7 @@ STR_WARNING_FALLBACK_SOUNDSET :{WHITE}Теку STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}Огромный снимок экрана STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}Снимок экрана будет иметь размер {COMMA}{NBSP}х{NBSP}{COMMA}{NBSP}пиксел{P ь я ей}. Его создание займёт некоторое время. Продолжить? +STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY :{WHITE}Карта высот успешно сохранена под именем «{STRING}». Максимальная высота - {NUM}. STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}Снимок экрана сохранён под именем «{STRING}» STR_ERROR_SCREENSHOT_FAILED :{WHITE}Не удалось сделать снимок экрана diff --git a/src/lang/serbian.txt b/src/lang/serbian.txt index fecc5964af..a3e9cbc0cb 100644 --- a/src/lang/serbian.txt +++ b/src/lang/serbian.txt @@ -1201,6 +1201,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardvers STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Označavanje ove opcije čini da OpenTTD pokuša da koristi hardversko ubrzanje. Promena ovog podešavanja će imati efekta tek nakon ponvnog pokretanja igre STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Podešavanje će imati efekta tek nakon ponovnog pokretanja igre + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Veličina interfejsa STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Izaberite većinu elementa koja će se koristiti @@ -2179,6 +2180,7 @@ STR_FACE_TIE :Kravata: STR_FACE_EARRING :Minđuše: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Promena kravate ili minđuša + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Mrežna partija STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ime igrača: @@ -2241,10 +2243,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Naziv pa STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Postavi lozinku STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Ukoliko ne želite da bude javno dostupna zaštitite Vašu partiju lozinkom -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK} Sa reklamama -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Odaberite između igre s oglasima (internet) i bez oglasa (Local Area Network, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Ne -STR_NETWORK_START_SERVER_ADVERTISED :Da STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} igrač{P "" a a} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Najviše igrača: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Odaberite koliko najviše može da ima igrača. Nemoraju sva mesta da budu popunjena @@ -2259,46 +2257,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Drugi ig STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Unos naziva mrežne partije -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Bilo koji -STR_NETWORK_LANG_ENGLISH :Engleski -STR_NETWORK_LANG_GERMAN :Nemački -STR_NETWORK_LANG_FRENCH :Francuski -STR_NETWORK_LANG_BRAZILIAN :Brazilski -STR_NETWORK_LANG_BULGARIAN :Bugarski -STR_NETWORK_LANG_CHINESE :Kineski -STR_NETWORK_LANG_CZECH :Češki -STR_NETWORK_LANG_DANISH :Danski -STR_NETWORK_LANG_DUTCH :Holandski -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finski -STR_NETWORK_LANG_HUNGARIAN :Mađarski -STR_NETWORK_LANG_ICELANDIC :Islandski -STR_NETWORK_LANG_ITALIAN :Italijanski -STR_NETWORK_LANG_JAPANESE :Japanski -STR_NETWORK_LANG_KOREAN :Koreanski -STR_NETWORK_LANG_LITHUANIAN :Litvanski -STR_NETWORK_LANG_NORWEGIAN :Norveški -STR_NETWORK_LANG_POLISH :Poljski -STR_NETWORK_LANG_PORTUGUESE :Portugalski -STR_NETWORK_LANG_ROMANIAN :Rumunski -STR_NETWORK_LANG_RUSSIAN :Ruski -STR_NETWORK_LANG_SLOVAK :Slovački -STR_NETWORK_LANG_SLOVENIAN :Slovenački -STR_NETWORK_LANG_SPANISH :Španski -STR_NETWORK_LANG_SWEDISH :Švedski -STR_NETWORK_LANG_TURKISH :Turski -STR_NETWORK_LANG_UKRAINIAN :Ukrajinski -STR_NETWORK_LANG_AFRIKAANS :Afrikans -STR_NETWORK_LANG_CROATIAN :Hrvatski -STR_NETWORK_LANG_CATALAN :Katalonski -STR_NETWORK_LANG_ESTONIAN :Estonski -STR_NETWORK_LANG_GALICIAN :Galicijski -STR_NETWORK_LANG_GREEK :Grčki -STR_NETWORK_LANG_LATVIAN :Letonski -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Predvorje partije sa više igrača @@ -2346,19 +2304,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Isključ STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server je zaštićen. Unesite lozinku STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Preduzeće je zaštićeno. Unesite lozinku -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Spisak klijenata # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Spisak klijenata -STR_NETWORK_COMPANY_LIST_SPECTATE :Praćenje -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Novo preduzeće # Network client list -STR_NETWORK_CLIENTLIST_KICK :Izbaci -STR_NETWORK_CLIENTLIST_BAN :Zabrani pristup -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Razgovaraj sa svima -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Razgovaraj sa ekipom -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privatna poruka + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Igrač diff --git a/src/lang/simplified_chinese.txt b/src/lang/simplified_chinese.txt index fa941b3a69..de2e704c34 100644 --- a/src/lang/simplified_chinese.txt +++ b/src/lang/simplified_chinese.txt @@ -946,6 +946,7 @@ STR_GAME_OPTIONS_CURRENCY_NTD :新台币 (NTD) STR_GAME_OPTIONS_CURRENCY_CNY :中国人民币 (CNY) STR_GAME_OPTIONS_CURRENCY_HKD :港币 (HKD) STR_GAME_OPTIONS_CURRENCY_INR :印度卢布(INR) +STR_GAME_OPTIONS_CURRENCY_IDR :印尼盾 (IDR) STR_GAME_OPTIONS_CURRENCY_MYR :马来西亚林吉特 (MYR) ############ end of currency region @@ -1005,6 +1006,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}硬件 STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}点击该复选框,让 OpenTTD 尝试使用硬件加速。修改后的设置将在游戏重启后生效 STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}修改后的设置将在游戏重启后生效 +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}垂直同步 +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}点击该复选框开启垂直同步(V-sync)。修改后的设置将在游戏重启后生效。仅开启硬件加速时有效 + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}界面大小 STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}选择使用的界面元素大小 @@ -1021,9 +1025,12 @@ STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_NORMAL :正常 STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_2X_ZOOM :两倍大小 STR_GAME_OPTIONS_FONT_ZOOM_DROPDOWN_4X_ZOOM :四倍大小 +STR_GAME_OPTIONS_GRAPHICS :{BLACK}图像 STR_GAME_OPTIONS_REFRESH_RATE :{BLACK}显示刷新率 STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :{BLACK}选择需要的屏幕刷新率 +STR_GAME_OPTIONS_REFRESH_RATE_OTHER :其他 +STR_GAME_OPTIONS_REFRESH_RATE_ITEM :{NUM}Hz STR_GAME_OPTIONS_REFRESH_RATE_WARNING :{WHITE}高于 60Hz 的刷新率可能会影响性能。 STR_GAME_OPTIONS_BASE_GRF :{BLACK}基础图形组 @@ -1134,6 +1141,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}设置 STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}关键字过滤: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}展开全部 STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}关闭全部 +STR_CONFIG_SETTING_RESET_ALL :{BLACK}重置所有值 STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(没有可用的提示) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}默认值: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}设置类型: {ORANGE}{STRING} @@ -1142,6 +1150,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :当前游戏设 STR_CONFIG_SETTING_TYPE_GAME_INGAME :当前游戏设置(可保存在存档中,仅对当前游戏生效) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :当前公司设置(可保存在存档中,仅对新游戏生效) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :当前公司设置(可保存在存档中,仅对现行公司生效) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}注意! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}该操作将重置所有游戏设置为默认值。{}确认继续? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}筛选设定: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}适用范围: @@ -1204,7 +1214,10 @@ STR_CONFIG_SETTING_CITY_APPROVAL :地区政府对 STR_CONFIG_SETTING_CITY_APPROVAL_HELPTEXT :设置相关参数以决定各公司造成的噪音及环境破坏时,各城镇对该公司的评价及未来区域建设的影响。 STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT :地图高度限制:{STRING} -STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}您不能把最高地面高度设为这个值,因为地图上至少有一座山丘的高度比这个值还大 +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_HELPTEXT :设置高原的最大高度。选择 "(自动)" 则在地形生成后自动选取合适的值 +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_VALUE :{NUM} +STR_CONFIG_SETTING_MAP_HEIGHT_LIMIT_AUTO :(自动) +STR_CONFIG_SETTING_TOO_HIGH_MOUNTAIN :{WHITE}您不能把最高地面高度限制设为这个值,因为地图上至少有一座山的高度大于该值 STR_CONFIG_SETTING_AUTOSLOPE :允许在建筑、轨道等下方改变地形(自动斜坡): {STRING} STR_CONFIG_SETTING_AUTOSLOPE_HELPTEXT :允许在建筑和轨道下方改变地形而不需要拆除他们 STR_CONFIG_SETTING_CATCHMENT :允许更真实的客源范围:{STRING} @@ -1349,6 +1362,7 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE :石油工业距 STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :限制炼油厂和油井到地图边缘或海岛海岸的最大距离。对于大于 256 格的地图,该值将按比例放大。 STR_CONFIG_SETTING_SNOWLINE_HEIGHT :雪线高度:{STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :控制在寒带气候中雪线高度。大雪会影响工业和城镇发展需求。只能在场景编辑器中更改或由“积雪覆盖率”计算得到。 +STR_CONFIG_SETTING_SNOW_COVERAGE :积雪覆盖率:{STRING} STR_CONFIG_SETTING_SNOW_COVERAGE_HELPTEXT :控制寒带气候中大致的雪量。雪会影响工业和城镇发展需求。只在地图生成时使用。海平面以上一格的土地永远没有积雪 STR_CONFIG_SETTING_SNOW_COVERAGE_VALUE :{NUM}% STR_CONFIG_SETTING_DESERT_COVERAGE :沙漠覆盖率:{STRING} @@ -1468,6 +1482,11 @@ STR_CONFIG_SETTING_PERSISTENT_BUILDINGTOOLS_HELPTEXT :“打开”时 STR_CONFIG_SETTING_EXPENSES_LAYOUT :企业财政窗口中的组群支出:{STRING} STR_CONFIG_SETTING_EXPENSES_LAYOUT_HELPTEXT :“打开”时公司财务报表将分组显示 STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS :建造铁路时自动移除信号灯:{STRING} +STR_CONFIG_SETTING_AUTO_REMOVE_SIGNALS_HELPTEXT :建造铁路时自动移除路过的信号灯。注意,这可能导致火车事故。 +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT :快进速度上限:{STRING} +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_HELPTEXT :限制快进时的最大速度。0 = 无限制(在您计算机允许的范围内)。低于 100% 的值将使游戏变慢。上限取决于您计算机的配置,并随着游戏情况浮动。 +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_VAL :{NUM}% 正常游戏速度 +STR_CONFIG_SETTING_FAST_FORWARD_SPEED_LIMIT_ZERO :无限制(在您计算机允许的范围内) STR_CONFIG_SETTING_SOUND_TICKER :产业新闻: {STRING} STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :每月初产业新闻音效 @@ -1637,7 +1656,10 @@ STR_CONFIG_SETTING_TOWN_CARGOGENMODE_BITCOUNT :线性 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_TOOLBAR_POS :主工具栏位置:{STRING} STR_CONFIG_SETTING_TOOLBAR_POS_HELPTEXT :主工具栏在屏幕上方的位置 @@ -1655,6 +1677,8 @@ STR_CONFIG_SETTING_ZOOM_MIN :最大放大倍 STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :画面的最大放大倍数,注意:提高放大倍数增加内存需求 STR_CONFIG_SETTING_ZOOM_MAX :最大视角缩小倍数: {STRING} STR_CONFIG_SETTING_ZOOM_MAX_HELPTEXT :画面的最大缩小倍数,过大的缩放级别在使用时会引起延迟 +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN :贴图的最高分辨率:{STRING} +STR_CONFIG_SETTING_SPRITE_ZOOM_MIN_HELPTEXT :限制贴图的最高分辨率。限制贴图分辨率将避免使用高分辨率贴图,即使它们可用。有助于在混用有/无高分辨率图形的 GRF 文件时保持游戏外观的统一。 STR_CONFIG_SETTING_ZOOM_LVL_MIN :4倍 STR_CONFIG_SETTING_ZOOM_LVL_IN_2X :2倍 STR_CONFIG_SETTING_ZOOM_LVL_NORMAL :普通 @@ -1707,6 +1731,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_HELPTEXT :在界面上以 STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_IMPERIAL :英制(英里/小时) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_METRIC :公制(千米/小时) STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_SI :国际单位制(米/秒) +STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :游戏单位 (格/日) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :运输工具功率单位:{STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :在界面上以所选择的单位表示运输工具的功率 @@ -1965,6 +1990,7 @@ STR_FACE_TIE :领带 STR_FACE_EARRING :耳环 STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}选择领带或是耳环 + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}联机游戏 STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}玩家名称: @@ -2027,10 +2053,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}游戏 STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}设置密码: STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}如果不希望你的游戏被外人加入,请设置一个密码 -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}发布到互联网 -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}选择是否将游戏发布到官方服务器列表。发布的话,可以让互联网上的玩家找到你的服务器并加入游戏,否则进行局域网内的游戏。 -STR_NETWORK_START_SERVER_UNADVERTISED :否 -STR_NETWORK_START_SERVER_ADVERTISED :是 STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} 客户端 STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}玩家数目: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}选择可以参加的玩家上限(达不到此数量仍然可以开始游戏) @@ -2045,46 +2067,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}其他 STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}为您的联机游戏取名 -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :任意 -STR_NETWORK_LANG_ENGLISH :英语 -STR_NETWORK_LANG_GERMAN :德语 -STR_NETWORK_LANG_FRENCH :法语 -STR_NETWORK_LANG_BRAZILIAN :巴西语 -STR_NETWORK_LANG_BULGARIAN :保加利亚语 -STR_NETWORK_LANG_CHINESE :中文 -STR_NETWORK_LANG_CZECH :捷克语 -STR_NETWORK_LANG_DANISH :丹麦语 -STR_NETWORK_LANG_DUTCH :荷兰语 -STR_NETWORK_LANG_ESPERANTO :世界语 -STR_NETWORK_LANG_FINNISH :芬兰语 -STR_NETWORK_LANG_HUNGARIAN :匈牙利语 -STR_NETWORK_LANG_ICELANDIC :冰岛语 -STR_NETWORK_LANG_ITALIAN :意大利语 -STR_NETWORK_LANG_JAPANESE :日语 -STR_NETWORK_LANG_KOREAN :韩文 -STR_NETWORK_LANG_LITHUANIAN :立陶宛语 -STR_NETWORK_LANG_NORWEGIAN :挪威语 -STR_NETWORK_LANG_POLISH :波兰语 -STR_NETWORK_LANG_PORTUGUESE :葡萄牙语 -STR_NETWORK_LANG_ROMANIAN :罗马尼亚语 -STR_NETWORK_LANG_RUSSIAN :俄语 -STR_NETWORK_LANG_SLOVAK :斯洛伐克语 -STR_NETWORK_LANG_SLOVENIAN :斯洛文尼亚语 -STR_NETWORK_LANG_SPANISH :西班牙语 -STR_NETWORK_LANG_SWEDISH :瑞典语 -STR_NETWORK_LANG_TURKISH :土耳其语 -STR_NETWORK_LANG_UKRAINIAN :乌克兰语 -STR_NETWORK_LANG_AFRIKAANS :南非荷兰语 -STR_NETWORK_LANG_CROATIAN :克罗地亚语 -STR_NETWORK_LANG_CATALAN :加泰罗尼亚语 -STR_NETWORK_LANG_ESTONIAN :爱沙尼亚语 -STR_NETWORK_LANG_GALICIAN :加利西亚语 -STR_NETWORK_LANG_GREEK :希腊语 -STR_NETWORK_LANG_LATVIAN :拉脱维亚语 -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}联机游戏大厅 @@ -2132,19 +2114,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}断开 STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}服务器需要密码: STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}公司需要密码: -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}客户端列表 # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :客户端列表 -STR_NETWORK_COMPANY_LIST_SPECTATE :旁观 -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :新公司 # Network client list -STR_NETWORK_CLIENTLIST_KICK :踢出 -STR_NETWORK_CLIENTLIST_BAN :禁止 -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :向全体人广播 -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :向本公司广播 -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :私聊 + + STR_NETWORK_SERVER :服务器 STR_NETWORK_CLIENT :客户端 @@ -2512,7 +2488,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}建造 STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}放置一个浮标,该浮标可以用作路点,按住 Shift 键操作可以显示所需资金 STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}建设水渠,按住 Shift 键操作可以显示所需资金 STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}修建运河{}当地形处于海平面时{}按住 Ctrl键 可以定义水域 -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}放置河流 +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}放置河流。按住Ctrl键选择对角线区域 # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}船坞方向…… @@ -2572,7 +2548,12 @@ STR_TREES_RANDOM_TYPE :{BLACK}随机 STR_TREES_RANDOM_TYPE_TOOLTIP :{BLACK}种植随机类型的树木,按住 Shift 键可以显示所需资金 STR_TREES_RANDOM_TREES_BUTTON :{BLACK}随机树木 STR_TREES_RANDOM_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}生成土地 @@ -2623,7 +2604,7 @@ STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM :{BLACK}随机 # Fund new industry window STR_FUND_INDUSTRY_CAPTION :{WHITE}建设新的工业设施 STR_FUND_INDUSTRY_SELECTION_TOOLTIP :{BLACK}请选择工业设施 -STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :大量随机工业 +STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES :{BLACK}生成随机工业 STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}在地图上创建大量随机的工业设施 STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_CAPTION :{WHITE}生成随机工业 STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_QUERY :{YELLOW}你确定要生成大量随机工业吗? @@ -2655,6 +2636,7 @@ STR_INDUSTRY_CARGOES_SELECT_INDUSTRY_TOOLTIP :{BLACK}选择 # Land area window STR_LAND_AREA_INFORMATION_CAPTION :{WHITE}地块信息 +STR_LAND_AREA_INFORMATION_LOCATION_TOOLTIP :{BLACK}将屏幕中心移动到地块所在的位置。单击的同时按住Ctrl会在新视点中显示地块位置 STR_LAND_AREA_INFORMATION_COST_TO_CLEAR_N_A :{BLACK}清除费用:{LTBLUE}N/A 不能清除 STR_LAND_AREA_INFORMATION_COST_TO_CLEAR :{BLACK}清除费用:{RED}{CURRENCY_LONG} STR_LAND_AREA_INFORMATION_REVENUE_WHEN_CLEARED :{BLACK}清除收入: {LTBLUE}{CURRENCY_LONG} @@ -2879,8 +2861,11 @@ STR_MAPGEN_DATE :{BLACK}日期: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}工业数量: STR_MAPGEN_HEIGHTMAP_HEIGHT :{BLACK}最高峰: STR_MAPGEN_HEIGHTMAP_HEIGHT_UP :{BLACK}提高最高峰的最大高度一格 +STR_MAPGEN_HEIGHTMAP_HEIGHT_DOWN :{BLACK}降低最高峰的最大高度一格 +STR_MAPGEN_SNOW_COVERAGE :{BLACK}积雪覆盖率: STR_MAPGEN_SNOW_COVERAGE_UP :{BLACK}增加 10% 积雪覆盖率 STR_MAPGEN_SNOW_COVERAGE_DOWN :{BLACK}减少 10% 积雪覆盖率 +STR_MAPGEN_SNOW_COVERAGE_TEXT :{BLACK}{NUM}% STR_MAPGEN_DESERT_COVERAGE :{BLACK}沙漠覆盖率: STR_MAPGEN_DESERT_COVERAGE_UP :{BLACK}增加 10% 沙漠覆盖率 STR_MAPGEN_DESERT_COVERAGE_DOWN :{BLACK}减少 10% 沙漠覆盖率 @@ -2911,6 +2896,7 @@ STR_MAPGEN_HEIGHTMAP_SIZE_LABEL :{BLACK}地图 STR_MAPGEN_HEIGHTMAP_SIZE :{ORANGE}{NUM} × {NUM} STR_MAPGEN_TERRAIN_TYPE_QUERY_CAPT :{WHITE}最高峰目标高度 +STR_MAPGEN_HEIGHTMAP_HEIGHT_QUERY_CAPT :{WHITE}最高峰 STR_MAPGEN_SNOW_COVERAGE_QUERY_CAPT :{WHITE}积雪覆盖率 (百分比) STR_MAPGEN_DESERT_COVERAGE_QUERY_CAPT :{WHITE}沙漠覆盖率 (百分比) STR_MAPGEN_START_DATE_QUERY_CAPT :{WHITE}改变游戏开始的日期 @@ -3129,6 +3115,7 @@ STR_SIGN_LIST_MATCH_CASE_TOOLTIP :{BLACK}显示 # Sign window STR_EDIT_SIGN_CAPTION :{WHITE}标记标志文字 +STR_EDIT_SIGN_LOCATION_TOOLTIP :{BLACK}将屏幕中心移动到标志的位置. 单击的同时按住Ctrl会在新视点中显示标志位置 STR_EDIT_SIGN_NEXT_SIGN_TOOLTIP :{BLACK}前往下个标记 STR_EDIT_SIGN_PREVIOUS_SIGN_TOOLTIP :{BLACK}前往上个标记 @@ -3189,13 +3176,13 @@ STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :资助新房屋 STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :购买运输专营权 STR_LOCAL_AUTHORITY_ACTION_BRIBE :贿赂地方政府 -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}进行小型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务.{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}进行中型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务.{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}进行大型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务.{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}资助市政道路进行重建,将造成市内交通阻断 6 个月。{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}以公司的名义设立一尊塑像。{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}资助市内建设新的商业设施。{}费用:{CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}购买该市一年的运输专营权, 其间该市的乘客及货物只允许选用贵公司的运输服务。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}进行小型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务。{}为位于该城镇中心较近距离内的车站提供暂时的评分增益。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}进行中型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务。{}为位于该城镇中心中等距离内的车站提供暂时的评分增益。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}进行大型的广告宣传,以吸引更多的旅客和货物选择贵公司的服务。{}为位于该城镇中心较远距离内的车站提供暂时的评分增益。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}资助市政道路进行重建。{}将造成市内交通阻断 6 个月。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}以公司的名义设立一尊塑像。{}为位于该城镇的车站提供永久的评分增益。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}资助市内建设新的商业设施。{}为城镇提供暂时的成长速度增益。{}费用:{CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}购买该市一年的运输专营权。{}其间该市的乘客及货物只允许选用贵公司的运输服务。{}费用:{CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}贿赂地方政府以提高评价,但有被发现后严厉惩罚的风险。{}费用:{CURRENCY_LONG} # Goal window @@ -3213,10 +3200,10 @@ STR_GOALS_PROGRESS_COMPLETE :{GREEN}{STRING} STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}点击使得视图移动到该工业/城镇/地块. Ctrl+左键 在该处创建一个视点. # Goal question window -STR_GOAL_QUESTION_CAPTION_QUESTION :帮助索引 -STR_GOAL_QUESTION_CAPTION_INFORMATION :信息 -STR_GOAL_QUESTION_CAPTION_WARNING :警告 -STR_GOAL_QUESTION_CAPTION_ERROR :错误 +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 :取消 @@ -3425,6 +3412,7 @@ STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP :{BLACK}出售 STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION :公司名称 STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION :总裁姓名 +STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION :输入你要给予的金额 STR_BUY_COMPANY_MESSAGE :{WHITE}我们正在寻找一家愿意收购我们的公司。{}{}您愿意收购 {COMPANY} ({CURRENCY_LONG}) 吗? @@ -3787,6 +3775,7 @@ STR_REPLACE_REMOVE_WAGON_HELP :{BLACK}当车 STR_VEHICLE_VIEW_CAPTION :{WHITE}{VEHICLE} STR_VEHICLE_VIEW_TRAIN_CENTER_TOOLTIP :{BLACK}将主视角中心移动到列车所在的位置。双击将会在主视角中跟踪列车。单击的同时按住Ctrl会在新视点中显示列车位置 +STR_VEHICLE_VIEW_ROAD_VEHICLE_CENTER_TOOLTIP :{BLACK} 将主视角中心移动到车辆所在的位置。双击将会在主视角中跟踪车辆。单击的同时按住 Ctrl 会在新视点中显示车辆位置 STR_VEHICLE_VIEW_SHIP_CENTER_TOOLTIP :{BLACK}将主视角中心移动到船只所在的位置。双击将会在主视角中跟踪船只。单击的同时按住Ctrl会在新视点中显示船只位置 STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}将主视角中心移动到飞机所在的位置。双击将会在主视角中跟踪飞机。单击的同时按住Ctrl会在新视点中显示飞机位置 @@ -3823,7 +3812,9 @@ STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}显示 STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}当前列车动作 - 点击以 停止/启动 列车 STR_VEHICLE_VIEW_ROAD_VEHICLE_STATUS_START_STOP_TOOLTIP :{BLACK}当前车辆动作 - 点击以 停止/启动 车辆 STR_VEHICLE_VIEW_SHIP_STATE_STATUS_STOP_TOOLTIP :{BLACK}当前船只动作 - 点击以 停止/启动 船只 +STR_VEHICLE_VIEW_AIRCRAFT_STATUS_START_STOP_TOOLTIP :{BLACK}当前飞机动作 - 点击以 停止/启动 飞机 +STR_VEHICLE_VIEW_ORDER_LOCATION_TOOLTIP :{BLACK}将屏幕中心移动到当前指令的目的地。单击的同时按住Ctrl会在新视点中显示指令目的地的位置 # Messages in the start stop button in the vehicle view STR_VEHICLE_STATUS_LOADING_UNLOADING :{LTBLUE}装载/卸货 @@ -3957,8 +3948,8 @@ STR_ORDERS_END_OF_SHARED_ORDERS :- - 共享调 STR_ORDER_NON_STOP :{BLACK}不停车 STR_ORDER_GO_TO :前往 STR_ORDER_GO_NON_STOP_TO :不停车前往 -STR_ORDER_GO_VIA :通过 -STR_ORDER_GO_NON_STOP_VIA :前往不停车 +STR_ORDER_GO_VIA :经由 +STR_ORDER_GO_NON_STOP_VIA :经由(不停车) STR_ORDER_TOOLTIP_NON_STOP :{BLACK}改变当前选中车站停车时的执行动作 STR_ORDER_TOGGLE_FULL_LOAD :{BLACK}装满任意货物 @@ -4051,6 +4042,7 @@ STR_ORDER_REFIT_STOP_ORDER :(改装为{STRI STR_ORDER_STOP_ORDER :(停留) STR_ORDER_GO_TO_STATION :{STRING} {STATION} {STRING} +STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(不能使用车站){POP_COLOUR} {STRING} {STATION} {STRING} STR_ORDER_IMPLICIT :(自动) @@ -4295,6 +4287,7 @@ STR_GAME_SAVELOAD_ERROR_TOO_NEW_SAVEGAME :该存档是新 STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE :文件无法读取 STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE :文件无法写入 STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED :数据完整性检查失败 +STR_GAME_SAVELOAD_ERROR_PATCHPACK :该存档是来自修改版的游戏 STR_GAME_SAVELOAD_NOT_AVAILABLE :<不可用> STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}游戏已保存为无电车版。所有电车已被去除。 @@ -4322,6 +4315,7 @@ STR_WARNING_FALLBACK_SOUNDSET :{WHITE}只找 STR_WARNING_SCREENSHOT_SIZE_CAPTION :{WHITE}超大截图 STR_WARNING_SCREENSHOT_SIZE_MESSAGE :{YELLOW}屏幕截图需要 {COMMA} x {COMMA} 像素。 截图将需要一段时间。确认继续截图? +STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY :{WHITE}高度图已经被成功保存为 '{STRING}'。最高峰高度是 {NUM} STR_MESSAGE_SCREENSHOT_SUCCESSFULLY :{WHITE}屏幕截图已经被成功保存为{} '{STRING}' STR_ERROR_SCREENSHOT_FAILED :{WHITE}屏幕截图失败! @@ -4375,6 +4369,7 @@ STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}没有 STR_ERROR_CURRENCY_REQUIRED :{WHITE}需要{CURRENCY_LONG} STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}不能偿还贷款…… STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}不能将银行的贷款送给别人…… +STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}不能给予该公司资金…… STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}不能收购公司…… STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}不能设置公司总部 STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}不能购买此公司的股份…… @@ -4501,6 +4496,8 @@ STR_ERROR_DEPOT_WRONG_DEPOT_TYPE :车库类型错 STR_ERROR_TRAIN_TOO_LONG_AFTER_REPLACEMENT :{WHITE}{VEHICLE}在更新后总长会过长 STR_ERROR_AUTOREPLACE_NOTHING_TO_DO :{WHITE}当前没有进行中的车辆更新计划. STR_ERROR_AUTOREPLACE_MONEY_LIMIT :(现金不够) +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_CARGO :{WHITE}新车辆不能装载 {STRING} +STR_ERROR_AUTOREPLACE_INCOMPATIBLE_REFIT :{WHITE}新车辆无法在调度计划 {NUM} 时改装 # Rail construction errors STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION :{WHITE}不可能的轨道组合 @@ -4650,7 +4647,7 @@ STR_ERROR_NO_VEHICLES_AVAILABLE_YET_EXPLANATION :{WHITE}在{DATE # Specific vehicle errors STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL :{WHITE}不能让列车冒险通过信号... STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN :{WHITE}不能命令列车调头... -STR_ERROR_TRAIN_START_NO_POWER :木有接触网! +STR_ERROR_TRAIN_START_NO_POWER :没有接触网! STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN :{WHITE}车辆无法调头... diff --git a/src/lang/slovak.txt b/src/lang/slovak.txt index bb72d6bf3e..dd154d6ba3 100644 --- a/src/lang/slovak.txt +++ b/src/lang/slovak.txt @@ -1074,6 +1074,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hardvér STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Zaškrtnutím políčka dovolíte, aby sa OpenTTD pokúsilo použiť hardvérové zrýchlenie. Zmena nastavenia sa uplatní až po reštartovaní hry STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Nastavenie sa uplatní až po reštartovaní hry + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Veľkosť rozhrania STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Výber veľkosti prvkov rozhrania @@ -2052,6 +2053,7 @@ STR_FACE_TIE :Kravata: STR_FACE_EARRING :Náušnica: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Zmeniť kravatu alebo náušnicu + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Hra pre viac hráčov STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Meno hráča: @@ -2114,10 +2116,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Názov h STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Nastaviť heslo STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Zabezpeč hru heslom, ak nechceš povoliť verejný prístup -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Zverejnené -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Vyberte medzi zverejnenou (internet) alebo nezverejnenou (lokálna sieť, LAN) hrou -STR_NETWORK_START_SERVER_UNADVERTISED :Nie -STR_NETWORK_START_SERVER_ADVERTISED :Áno STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" i ov} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Maximálny počet klientov: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Zvoľ maximálny počet klientov. Môže sa ich pripojiť aj menej. @@ -2132,46 +2130,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Aby osta STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Zadajte názov sieťovej hry -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Lubovolny -STR_NETWORK_LANG_ENGLISH :Anglicky -STR_NETWORK_LANG_GERMAN :Nemecky -STR_NETWORK_LANG_FRENCH :Francuzsky -STR_NETWORK_LANG_BRAZILIAN :Brazílsky -STR_NETWORK_LANG_BULGARIAN :Bulharsky -STR_NETWORK_LANG_CHINESE :Cinsky -STR_NETWORK_LANG_CZECH :Cesky -STR_NETWORK_LANG_DANISH :Dánsky -STR_NETWORK_LANG_DUTCH :Holadnsky -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fínsky -STR_NETWORK_LANG_HUNGARIAN :Madarsky -STR_NETWORK_LANG_ICELANDIC :Islandsky -STR_NETWORK_LANG_ITALIAN :Taliansky -STR_NETWORK_LANG_JAPANESE :Japonsky -STR_NETWORK_LANG_KOREAN :Kórejsky -STR_NETWORK_LANG_LITHUANIAN :Litovksy -STR_NETWORK_LANG_NORWEGIAN :Nórsky -STR_NETWORK_LANG_POLISH :Polsky -STR_NETWORK_LANG_PORTUGUESE :Portugalsky -STR_NETWORK_LANG_ROMANIAN :Rumunsky -STR_NETWORK_LANG_RUSSIAN :Rusky -STR_NETWORK_LANG_SLOVAK :Slovenský -STR_NETWORK_LANG_SLOVENIAN :Slovinsky -STR_NETWORK_LANG_SPANISH :Spanielsky -STR_NETWORK_LANG_SWEDISH :Svédsky -STR_NETWORK_LANG_TURKISH :Turecky -STR_NETWORK_LANG_UKRAINIAN :Ukrajinsky -STR_NETWORK_LANG_AFRIKAANS :Africky -STR_NETWORK_LANG_CROATIAN :Chorvátsky -STR_NETWORK_LANG_CATALAN :Katalánsky -STR_NETWORK_LANG_ESTONIAN :Estónsky -STR_NETWORK_LANG_GALICIAN :Gálsky -STR_NETWORK_LANG_GREEK :Grécky -STR_NETWORK_LANG_LATVIAN :Litovsky -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sieťová hra - čakáreň @@ -2219,19 +2177,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Odpojiť STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server je chránený. Zadaj heslo STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Spoločnosť je chránená. Zadaj heslo -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Zoznam klientov # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Zoznam klientov -STR_NETWORK_COMPANY_LIST_SPECTATE :Pozorovať -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nová spoločnosť # Network client list -STR_NETWORK_CLIENTLIST_KICK :Vyhodit -STR_NETWORK_CLIENTLIST_BAN :Ban -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Napísať správu všetkým -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Napísať spoločnosti správu -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Súkromná správa + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klient @@ -4475,14 +4427,14 @@ STR_ERROR_CAN_T_CHANGE_COMPANY_NAME :{WHITE}Názov s STR_ERROR_CAN_T_CHANGE_PRESIDENT :{WHITE}Meno prezidenta sa nedá zmeniť... STR_ERROR_MAXIMUM_PERMITTED_LOAN :{WHITE}... úverovy limit je {CURRENCY_LONG} -STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Nemôžeš si požičať viac peňazí... +STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY :{WHITE}Nemôžete si požičať viac peňazí... STR_ERROR_LOAN_ALREADY_REPAYED :{WHITE}... úver už bol splatený STR_ERROR_CURRENCY_REQUIRED :{WHITE}... {CURRENCY_LONG} potrebuješ STR_ERROR_CAN_T_REPAY_LOAN :{WHITE}Úver sa nedá splatiť... STR_ERROR_INSUFFICIENT_FUNDS :{WHITE}Nie je možné presunúť peniaze, ktoré sú požičané z banky... STR_ERROR_CAN_T_GIVE_MONEY :{WHITE}Nie je možné presunúť peniaze tejto spoločnosti... STR_ERROR_CAN_T_BUY_COMPANY :{WHITE}Spoločnosť nie je možné kúpiť ... -STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Nemôžeš postaviť sídlo spoločnosti... +STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS :{WHITE}Nemôžete tu postaviť sídlo spoločnosti... STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS :{WHITE}Nemôžeš kúpiť 25% podiel v tejto spoločnosti... STR_ERROR_CAN_T_SELL_25_SHARE_IN :{WHITE}25% podiel v tejto spoločnosti sa nedá predať ... STR_ERROR_PROTECTED :{WHITE}S akciami tejto spoločnosti nie je zatiaľ možné obchodovať... @@ -4505,10 +4457,10 @@ STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... v ce STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... príliš veľa priemyslu STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Nemožno vygenerovať priemysel... STR_ERROR_CAN_T_BUILD_HERE :{WHITE}{STRING} sa tu nedá postaviť... -STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Nemôžeš tu postaviť tento typ priemyslu... +STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Nemôžete tu postaviť tento typ priemyslu... STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... príliš blízko iného priemyslu STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... najskôr je potrebné založiť mesto -STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... povolené len jedno pre 1mesto +STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... povolené len jedno pre každé mesto STR_ERROR_CAN_ONLY_BE_BUILT_IN_TOWNS_WITH_POPULATION_OF_1200 :{WHITE}... môže byť postavené v mestách z populáciou väčšou ako 1200 STR_ERROR_CAN_ONLY_BE_BUILT_IN_RAINFOREST :{WHITE}... môže byť postavené len v dažďovom pralese STR_ERROR_CAN_ONLY_BE_BUILT_IN_DESERT :{WHITE}... môže byť postavené len v púšti @@ -4524,13 +4476,13 @@ STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nenašli STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Pre získanie lepšej mapy zmeňte parametre jej generovania # Station construction related errors -STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Nemôžeš tu postaviť železničnú stanicu... -STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Nemôžeš tu postaviť autobusovú zastávku... +STR_ERROR_CAN_T_BUILD_RAILROAD_STATION :{WHITE}Nemôžete tu postaviť železničnú stanicu... +STR_ERROR_CAN_T_BUILD_BUS_STATION :{WHITE}Nemôžete tu postaviť autobusovú zastávku... STR_ERROR_CAN_T_BUILD_TRUCK_STATION :{WHITE}Nemôžeš tu postaviť vykládku... -STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Nemôžeš postaviť električkovú osobnú stanicu... -STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Nemôžeš postaviť električkovú nákladnú stanicu... -STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Nemôžeš tu postaviť prístav... -STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Nemôžeš tu postaviť letisko... +STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION :{WHITE}Nemôžete tu postaviť električkovú zastávku... +STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION :{WHITE}Nemôžete tu postaviť električkovú vykládku... +STR_ERROR_CAN_T_BUILD_DOCK_HERE :{WHITE}Nemôžete tu postaviť prístav... +STR_ERROR_CAN_T_BUILD_AIRPORT_HERE :{WHITE}Nemôžete tu postaviť letisko... STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Susedí z viacerými stanicami/výkladkami STR_ERROR_STATION_TOO_SPREAD_OUT :{WHITE}... stanica je príliš veľká @@ -4578,8 +4530,8 @@ STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... bój STR_ERROR_BUOY_IS_IN_USE :{WHITE}... bóju používa iná spoločnosť! # Depot related errors -STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Nemôžeš tu postaviť vlakové depo... -STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Nemôžeš tu postaviť garáž... +STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT :{WHITE}Nemôžete tu postaviť vlakové depo... +STR_ERROR_CAN_T_BUILD_ROAD_DEPOT :{WHITE}Nemôžete tu postaviť garáž... STR_ERROR_CAN_T_BUILD_TRAM_DEPOT :{WHITE}Nemôžeš tu postaviť električkové depo... STR_ERROR_CAN_T_BUILD_SHIP_DEPOT :{WHITE}Nemôžeš tu postaviť lodenicu... @@ -4619,7 +4571,7 @@ STR_ERROR_CROSSING_ON_ONEWAY_ROAD :{WHITE}Cesta je STR_ERROR_CROSSING_DISALLOWED_RAIL :{WHITE}Nie sú povolené priecestia pre tento typ železnice STR_ERROR_CROSSING_DISALLOWED_ROAD :{WHITE}Nie sú povolené priecestia pre tento typ cesty STR_ERROR_CAN_T_BUILD_SIGNALS_HERE :{WHITE}Nemôžeš tu umiestniť návestidlá... -STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nemôžeš tu stavať železničné koľaje... +STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK :{WHITE}Nemôžete tu postaviť železničnú trať... STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK :{WHITE}Nemôžeš tu odstrániť železničné koľaje... STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM :{WHITE}Nemôžeš tu odstrániť návestidlá... STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE :{WHITE}Tu nie je možné zameniť návestidlá... @@ -4631,7 +4583,7 @@ STR_ERROR_CAN_T_CONVERT_RAIL :{WHITE}Nemôže # Road construction errors STR_ERROR_MUST_REMOVE_ROAD_FIRST :{WHITE}Najprv treba odstrániť cestu STR_ERROR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION :{WHITE}... na jednosmerných cestách nie sú dovolené križovatky -STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Nemôžeš tu postaviť cestu... +STR_ERROR_CAN_T_BUILD_ROAD_HERE :{WHITE}Nemôžete tu postaviť cestu... STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE :{WHITE}Nemôžeš tu stavať električkovú trať... STR_ERROR_CAN_T_REMOVE_ROAD_FROM :{WHITE}Nemôžeš tu odstrániť cestu... STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM :{WHITE}Nemôžeš tu odstrániť električkovú trať... @@ -4645,15 +4597,15 @@ STR_ERROR_INCOMPATIBLE_TRAMWAY :{WHITE}... neko # Waterway construction errors STR_ERROR_CAN_T_BUILD_CANALS :{WHITE}Tu sa nedá postaviť vodný kanál... -STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Tu sa nedá postaviť stavidlo... +STR_ERROR_CAN_T_BUILD_LOCKS :{WHITE}Nemôžete tu postaviť stavidlá... STR_ERROR_CAN_T_PLACE_RIVERS :{WHITE}Tu nie je možné umiestniť rieku... STR_ERROR_MUST_BE_BUILT_ON_WATER :{WHITE}... musíš postaviť na vode -STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... nemôžeš postaviť na vode -STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... nemôžeš postaviť na otvorenom mori +STR_ERROR_CAN_T_BUILD_ON_WATER :{WHITE}... nemôže byť postavené na vode +STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... nemôže byť postavené na otvorenom mori STR_ERROR_CAN_T_BUILD_ON_CANAL :{WHITE}... nemôže byť postavené na vodnom kanále STR_ERROR_CAN_T_BUILD_ON_RIVER :{WHITE}... nemôže byť postavené na rieke STR_ERROR_MUST_DEMOLISH_CANAL_FIRST :{WHITE}Najprv sa musí zbúrať vodný kanál -STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Tu nie je možné postaviť akvadukt... +STR_ERROR_CAN_T_BUILD_AQUEDUCT_HERE :{WHITE}Nemôžete tu postaviť akvadukt... # Tree related errors STR_ERROR_TREE_ALREADY_HERE :{WHITE}... strom tu už je @@ -4661,7 +4613,7 @@ STR_ERROR_TREE_WRONG_TERRAIN_FOR_TREE_TYPE :{WHITE}... zlý STR_ERROR_CAN_T_PLANT_TREE_HERE :{WHITE}Nemôžeš tu zasadiť strom... # Bridge related errors -STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Nemôžeš tu postaviť most... +STR_ERROR_CAN_T_BUILD_BRIDGE_HERE :{WHITE}Nemôžete tu postaviť most... STR_ERROR_MUST_DEMOLISH_BRIDGE_FIRST :{WHITE}Most musíš najskôr zbúrať STR_ERROR_CAN_T_START_AND_END_ON :{WHITE}Nemožno začať a skončiť na tom istom mieste STR_ERROR_BRIDGEHEADS_NOT_SAME_HEIGHT :{WHITE}Konce mosta nie sú v rovnakej výške @@ -4779,7 +4731,7 @@ STR_ERROR_CAN_T_ADD_ORDER_SHARED :{WHITE}... vozi STR_ERROR_CAN_T_SHARE_ORDER_LIST :{WHITE}Nemožno zdieľať zoznam príkazov ... STR_ERROR_CAN_T_STOP_SHARING_ORDER_LIST :{WHITE}Nie je možné prestať zdieľať zoznam príkazov... -STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Nemozno kopirovat zoznam prikazov ... +STR_ERROR_CAN_T_COPY_ORDER_LIST :{WHITE}Nemožno kopírovať zoznam príkazov ... STR_ERROR_TOO_FAR_FROM_PREVIOUS_DESTINATION :{WHITE}... príliš ďaleko z predchádzajúceho cieľa STR_ERROR_AIRCRAFT_NOT_ENOUGH_RANGE :{WHITE}... lietadlo nemá dostatočný dosah diff --git a/src/lang/slovenian.txt b/src/lang/slovenian.txt index 1c42b38d66..185677db07 100644 --- a/src/lang/slovenian.txt +++ b/src/lang/slovenian.txt @@ -1123,6 +1123,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Izberi l STR_GAME_OPTIONS_RESOLUTION_OTHER :drugo + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Velikost vmesnika STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Izberi velikost elementa vmesnika @@ -2024,6 +2025,7 @@ STR_FACE_TIE :Kravata: STR_FACE_EARRING :Uhani: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Spremeni kravato ali uhane + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Več igralcev STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ime igralca: @@ -2082,10 +2084,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Ime bo p STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Nastavi geslo STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Zaščiti igro z geslom, če želiš preprečiti dostop nepovabljenim -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Oglaševano -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Izberi med oglaševano (internet) in neoglaševano (Local Area Network, LAN) igro -STR_NETWORK_START_SERVER_UNADVERTISED :Ne -STR_NETWORK_START_SERVER_ADVERTISED :Da STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} gost{P "" a i ov} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Dovoljeno število gostov: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Izberite največje število gostov. Ni potrebno, da so vsi prisotni @@ -2100,46 +2098,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Drugi ig STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Vpiši ime za mrežno igro -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Kakršen koli -STR_NETWORK_LANG_ENGLISH :Angleški -STR_NETWORK_LANG_GERMAN :Nemški -STR_NETWORK_LANG_FRENCH :Francoski -STR_NETWORK_LANG_BRAZILIAN :Brazilski -STR_NETWORK_LANG_BULGARIAN :Bolgarski -STR_NETWORK_LANG_CHINESE :Kitajski -STR_NETWORK_LANG_CZECH :Češki -STR_NETWORK_LANG_DANISH :Danski -STR_NETWORK_LANG_DUTCH :Nizozemski -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finski -STR_NETWORK_LANG_HUNGARIAN :Madžarski -STR_NETWORK_LANG_ICELANDIC :Islandski -STR_NETWORK_LANG_ITALIAN :Italijanski -STR_NETWORK_LANG_JAPANESE :Japonski -STR_NETWORK_LANG_KOREAN :Korejski -STR_NETWORK_LANG_LITHUANIAN :Litvijski -STR_NETWORK_LANG_NORWEGIAN :Norveški -STR_NETWORK_LANG_POLISH :Poljski -STR_NETWORK_LANG_PORTUGUESE :Portugalski -STR_NETWORK_LANG_ROMANIAN :Romunski -STR_NETWORK_LANG_RUSSIAN :Ruski -STR_NETWORK_LANG_SLOVAK :Slovaški -STR_NETWORK_LANG_SLOVENIAN :Slovenski -STR_NETWORK_LANG_SPANISH :Španski -STR_NETWORK_LANG_SWEDISH :Švedski -STR_NETWORK_LANG_TURKISH :Turški -STR_NETWORK_LANG_UKRAINIAN :Ukrajinski -STR_NETWORK_LANG_AFRIKAANS :Afriški -STR_NETWORK_LANG_CROATIAN :Hrvaški -STR_NETWORK_LANG_CATALAN :Katalonski -STR_NETWORK_LANG_ESTONIAN :Estonski -STR_NETWORK_LANG_GALICIAN :Galijski -STR_NETWORK_LANG_GREEK :Grški -STR_NETWORK_LANG_LATVIAN :Latvijski -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Seje večigralskih iger @@ -2190,15 +2148,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Podjetje # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Seznam gostov -STR_NETWORK_COMPANY_LIST_SPECTATE :Opazuj -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Novo podjetje # Network client list -STR_NETWORK_CLIENTLIST_KICK :Brcni -STR_NETWORK_CLIENTLIST_BAN :Blokiraj -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Pogovor vsem -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Pogovor podjetju -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Zasebno sporočilo + + STR_NETWORK_SERVER :Strežnik STR_NETWORK_CLIENT :Gost diff --git a/src/lang/spanish.txt b/src/lang/spanish.txt index 847986a93a..f6ba798ee2 100644 --- a/src/lang/spanish.txt +++ b/src/lang/spanish.txt @@ -119,7 +119,7 @@ STR_QUANTITY_SUGAR :{WEIGHT_LONG} d STR_QUANTITY_TOYS :{COMMA}{NBSP}juguete{P "" s} STR_QUANTITY_SWEETS :{COMMA}{NBSP}bolsa{P "" s} de caramelos STR_QUANTITY_COLA :{VOLUME_LONG} de cola -STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} de algodón dulce +STR_QUANTITY_CANDYFLOSS :{WEIGHT_LONG} de algodón de azúcar STR_QUANTITY_BUBBLES :{COMMA} burbuja{P "" s} STR_QUANTITY_TOFFEE :{WEIGHT_LONG} de tofe{P "" s} STR_QUANTITY_BATTERIES :{COMMA} pila{P "" s} @@ -149,14 +149,14 @@ STR_ABBREV_PAPER :{TINY_FONT}PP STR_ABBREV_GOLD :{TINY_FONT}OR STR_ABBREV_WATER :{TINY_FONT}AG STR_ABBREV_WHEAT :{TINY_FONT}TG -STR_ABBREV_RUBBER :{TINY_FONT}GM +STR_ABBREV_RUBBER :{TINY_FONT}CA STR_ABBREV_SUGAR :{TINY_FONT}AZ STR_ABBREV_TOYS :{TINY_FONT}JG STR_ABBREV_SWEETS :{TINY_FONT}DC STR_ABBREV_COLA :{TINY_FONT}CL STR_ABBREV_CANDYFLOSS :{TINY_FONT}AA STR_ABBREV_BUBBLES :{TINY_FONT}BU -STR_ABBREV_TOFFEE :{TINY_FONT}CM +STR_ABBREV_TOFFEE :{TINY_FONT}TF STR_ABBREV_BATTERIES :{TINY_FONT}PI STR_ABBREV_PLASTIC :{TINY_FONT}PL STR_ABBREV_FIZZY_DRINKS :{TINY_FONT}RF @@ -195,7 +195,7 @@ STR_COLOUR_DEFAULT :Por Defecto STR_UNITS_VELOCITY_IMPERIAL :{COMMA}{NBSP}mph STR_UNITS_VELOCITY_METRIC :{COMMA}{NBSP}km/h STR_UNITS_VELOCITY_SI :{COMMA}{NBSP}m/s -STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL} {NBSP}casillas/día +STR_UNITS_VELOCITY_GAMEUNITS :{DECIMAL}{NBSP}casillas/día STR_UNITS_POWER_IMPERIAL :{COMMA}{NBSP}hp STR_UNITS_POWER_METRIC :{COMMA}{NBSP}cv @@ -242,8 +242,8 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Cierra l STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Título de la ventana - arrastra para moverla STR_TOOLTIP_SHADE :{BLACK}Oculta la ventana - muestra sólo el título de la ventana STR_TOOLTIP_DEBUG :{BLACK}Muestra la información de depuración NewGRF -STR_TOOLTIP_DEFSIZE :{BLACK}Redimensionar ventana al tamaño por defecto. Ctrl+Clic permite almacenar el tamaño actual como tamaño por defecto -STR_TOOLTIP_STICKY :{BLACK}Esta ventana no se cerrará tras usar el comando 'Cerrar Todas las Ventanas'. Ctrl+Clic permite guardar el estado como estado por defecto +STR_TOOLTIP_DEFSIZE :{BLACK}Redimensionar ventana al tamaño por defecto. Ctrl+clic permite almacenar el tamaño actual como tamaño por defecto +STR_TOOLTIP_STICKY :{BLACK}Esta ventana no se cerrará tras usar el comando 'Cerrar Todas las Ventanas'. Ctrl+clic permite guardar el estado como estado por defecto STR_TOOLTIP_RESIZE :{BLACK}Clica y arrastra para redimensionar la ventana STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Alterna el tamaño de ventana entre grande/pequeño STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST :{BLACK}Barra de desplazamiento - mueve la lista hacia arriba/abajo @@ -315,7 +315,7 @@ STR_SORT_BY_RANGE :Alcance STR_SORT_BY_POPULATION :Población STR_SORT_BY_RATING :Calificación STR_SORT_BY_NUM_VEHICLES :Número de vehículos -STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Beneficios total del último año +STR_SORT_BY_TOTAL_PROFIT_LAST_YEAR :Beneficio total del último año STR_SORT_BY_TOTAL_PROFIT_THIS_YEAR :Beneficio total este año STR_SORT_BY_AVERAGE_PROFIT_LAST_YEAR :Beneficio medio el año pasado STR_SORT_BY_AVERAGE_PROFIT_THIS_YEAR :Beneficio medio este año @@ -340,10 +340,10 @@ STR_TOOLBAR_TOOLTIP_DISPLAY_GOALS_LIST :{BLACK}Muestra STR_TOOLBAR_TOOLTIP_DISPLAY_GRAPHS :{BLACK}Mostrar gráficas STR_TOOLBAR_TOOLTIP_DISPLAY_COMPANY_LEAGUE :{BLACK}Mostrar tabla de clasificación de empresas STR_TOOLBAR_TOOLTIP_FUND_CONSTRUCTION_OF_NEW :{BLACK}Financiar la construcción de una industria nueva o mostrar lista de industrias -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Mostrar lista de trenes de la empresa. Ctrl+Clic hace que no aparezca la lista de grupos -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Mostrar lista de vehículos de carretera de la empresa. Ctrl+Clic hace que no aparezca la lista de grupos -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Mostrar lista de barcos de la empresa. Ctrl+Clic hace que no aparezca la lista de grupos -STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Mostrar lista de aeronaves de la empresa. Ctrl+Clic hace que no aparezca la lista de grupos +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_TRAINS :{BLACK}Mostrar lista de trenes de la empresa. Ctrl+clic hace que no aparezca la lista de grupos +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_ROAD_VEHICLES :{BLACK}Mostrar lista de vehículos de carretera de la empresa. Ctrl+clic hace que no aparezca la lista de grupos +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_SHIPS :{BLACK}Mostrar lista de barcos de la empresa. Ctrl+clic hace que no aparezca la lista de grupos +STR_TOOLBAR_TOOLTIP_DISPLAY_LIST_OF_COMPANY_AIRCRAFT :{BLACK}Mostrar lista de aeronaves de la empresa. Ctrl+clic hace que no aparezca la lista de grupos STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN :{BLACK}Acercar vista STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT :{BLACK}Alejar vista STR_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}Construir ferrocarril @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit malasio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Conducir por la izquierda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Conducir por la derecha -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de municipios +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de municipios: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Selección del estilo del nombre de los municipios ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Selecciona el idioma a emplear en interfaz del juego +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completo) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Marca esta opción para jugar OpenTTD a pantalla completa @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelerac STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Marca esta casilla para permitir que OpenTTD intente usar aceleración por hardware. El cambio de configuración sólo tendrá efecto después de reiniciar el juego STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}El ajuste sólo tendrá efecto después de reiniciar el juego +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}Sincronización vertical +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Marca esta casilla para activar la sincronización vertical en la pantalla. El cambio sólo se aplicará después de reiniciar el juego. Sólo funciona si la aceleración por hardware está activada. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamaño de la interfaz STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Selecciona el tamaño de los elementos de la interfaz a usar @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configur STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Patrón de filtrado: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Expandir todos STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Colapsar todos +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Restablecer valores STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(no hay explicación disponible) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valor por defecto: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Tipo de opción: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Opción de part STR_CONFIG_SETTING_TYPE_GAME_INGAME :Opción de partida (almacenada en la partida guardada, afecta solamente a la partida actual) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Opción de empresa (se almacena en las partidas guardadas, afecta solamente a las nuevas partidas) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Opción de empresa (almacenada en la partida guardada, afecta solamente a la empresa actual) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}¡Advertencia! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Esta acción restablecerá todos los ajustes del juego a sus valores por defecto.{}¿Deseas proceder? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categoría: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipo: @@ -1730,7 +1737,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_VELOCITY_GAMEUNITS :Unidad del jueg STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER :Unidad de potencia de vehículos: {STRING} STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_HELPTEXT :Cada vez que se muestre la potencia de un vehículo en la interfaz de usuario, se empleará la unidad seleccionada -STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (cv) +STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_IMPERIAL :Imperial (hp) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_METRIC :Métrico (cv) STR_CONFIG_SETTING_LOCALISATION_UNITS_POWER_SI :SI (kW) @@ -1901,7 +1908,7 @@ STR_LIVERY_SHIP_TOOLTIP :{BLACK}Muestra STR_LIVERY_AIRCRAFT_TOOLTIP :{BLACK}Muestra el esquema de color de las aeronaves STR_LIVERY_PRIMARY_TOOLTIP :{BLACK}Selecciona el color primario para el esquema seleccionado. Ctrl+clic fijará este color para todo el esquema STR_LIVERY_SECONDARY_TOOLTIP :{BLACK}Selecciona el color secundario para el esquema seleccionado. Ctrl+clic fijará este color para todo el esquema -STR_LIVERY_PANEL_TOOLTIP :{BLACK}Selecciona un esquema de color a modificar, o selecciona varios pulsando Ctrl+Clic. Pulsa en la caja para cambiar el uso del esquema +STR_LIVERY_PANEL_TOOLTIP :{BLACK}Selecciona un esquema de color a modificar, o selecciona varios pulsando Ctrl+clic. Pulsa en la caja para cambiar el uso del esquema STR_LIVERY_DEFAULT :Estación Normal STR_LIVERY_STEAM :Locomotora a Vapor @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Pendientes: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambiar corbata o pendientes +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nombre del jugador: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}La parti STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Establecer contraseña STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Protege tu partida con una contraseña si no quieres que sea universalmente accesible -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Público -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Permite escoger entre una partida pública (internet) y una partida privada (LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Sí +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidad +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Establece si otras personas pueden ver el servidor en la lista de servidores públicos STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Número máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Selecciona el número máximo de clientes. No es necesario ocupar todos los espacios @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Los otro STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Introduce un nombre para el juego en red -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Cualquiera -STR_NETWORK_LANG_ENGLISH :Inglés -STR_NETWORK_LANG_GERMAN :Alemán -STR_NETWORK_LANG_FRENCH :Francés -STR_NETWORK_LANG_BRAZILIAN :Brasileño -STR_NETWORK_LANG_BULGARIAN :Búlgaro -STR_NETWORK_LANG_CHINESE :Chino -STR_NETWORK_LANG_CZECH :Checo -STR_NETWORK_LANG_DANISH :Danés -STR_NETWORK_LANG_DUTCH :Alemán -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fines -STR_NETWORK_LANG_HUNGARIAN :Húngaro -STR_NETWORK_LANG_ICELANDIC :Islandés -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Japonés -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Noruego -STR_NETWORK_LANG_POLISH :Polaco -STR_NETWORK_LANG_PORTUGUESE :Portugués -STR_NETWORK_LANG_ROMANIAN :Rumano -STR_NETWORK_LANG_RUSSIAN :Ruso -STR_NETWORK_LANG_SLOVAK :Eslovaco -STR_NETWORK_LANG_SLOVENIAN :Esloveno -STR_NETWORK_LANG_SPANISH :Español -STR_NETWORK_LANG_SWEDISH :Sueco -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraniano -STR_NETWORK_LANG_AFRIKAANS :Africano -STR_NETWORK_LANG_CROATIAN :Croata -STR_NETWORK_LANG_CATALAN :Catalán -STR_NETWORK_LANG_ESTONIAN :Estonio -STR_NETWORK_LANG_GALICIAN :Gallego -STR_NETWORK_LANG_GREEK :Griego -STR_NETWORK_LANG_LATVIAN :Letón -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sala de espera de la partida multijugador @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desconec STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor protegido. Introduce la contraseña STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introduce la contraseña -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista de Clientes # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes -STR_NETWORK_COMPANY_LIST_SPECTATE :Observar -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nueva empresa +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadores en línea # Network client list -STR_NETWORK_CLIENTLIST_KICK :Expulsar (Kick) -STR_NETWORK_CLIENTLIST_BAN :Prohibir (Ban) -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Hablar a todos -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Hablar a empresa -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mensaje privado +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nombre del servidor en el que estás jugando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Modifica el nombre de tu servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidad +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Establece si otras personas pueden ver el servidor en la lista de servidores públicos +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Modifica tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Acciones de administrador a realizar para este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Acciones de administrador a realizar para esta compañía +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Unirse a esta compañía +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Manda un mensaje a este jugador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Manda un mensaje a todos los jugadores de esta compañía +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Manda un mensaje a todos los observadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Observadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva compañía) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crea una nueva companía y te une a ella +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Éste eres tú +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Éste es el servidor de la partida + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Prohibir el acceso +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Eliminar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Eliminar contraseña + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acción de administrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}¿Estás seguro de que deseas expulsar al jugador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}¿Estás seguro de que deseas prohibir el acceso al jugador '{STRING}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}¿Estás seguro de que quieres eliminar la compañía '{COMPANY}'? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}¿Estás seguro de que quieres eliminar la contraseña de la compañía '{COMPANY}'? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}No se ha STR_NETWORK_ERROR_CLIENT_START :{WHITE}No se pudo conectar STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tiempo de espera agotado en conexión #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Se ha producido un error de protocolo y la conexión ha sido cerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}No se ha establecido tu nombre de jugador. El nombre se puede establecer en la parte superior de la ventana de Multijugador STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La versión de este cliente no corresponde con la versión del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contraseña incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor está completo @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Has tard STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Su ordenador es demasiado lento para seguir la velocidad del servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Su ordenador necesitó demasiado tiempo para descargar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Su ordenador necesitó demasiado tiempo para conectar al servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Tu nombre de jugador no es válido ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :no se ha recibi STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :tiempo agotado en general STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :la descarga del mapa ha necesitado demasiado tiempo STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :el procesado del mapa ha necesitado demasiado tiempo +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nombre de cliente inválido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Posible pérdida de conexión @@ -2356,15 +2354,15 @@ STR_MISSING_GRAPHICS_ERROR_QUIT :{BLACK}Salir de # Transparency settings window STR_TRANSPARENCY_CAPTION :{WHITE}Opciones de Transparencia -STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Ajustar transparencia para carteles. Ctrl+Clic para bloquear -STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Ajustar transparencia para árboles. Ctrl+Clic para bloquear -STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Ajustar transparencia para casas. Ctrl+Clic para bloquear -STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Ajustar transparencia para industrias. Ctrl+Clic para bloquear -STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Ajustar transparencia para construcciones como estaciones, depósitos o puntos de ruta. Ctrl+Clic para bloquear -STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Ajustar transparencia para puentes. Ctrl+Clic para bloquear -STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Ajustar transparencia para estructuras como faros o antenas. Ctrl+Clic para bloquear -STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Ajustar transparencia para catenaria. Ctrl+Clic para bloquear -STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Ajustar transparencia para los indicadores de carga. Ctrl+Clic para bloquear +STR_TRANSPARENT_SIGNS_TOOLTIP :{BLACK}Ajustar transparencia para carteles. Ctrl+clic para bloquear +STR_TRANSPARENT_TREES_TOOLTIP :{BLACK}Ajustar transparencia para árboles. Ctrl+clic para bloquear +STR_TRANSPARENT_HOUSES_TOOLTIP :{BLACK}Ajustar transparencia para casas. Ctrl+clic para bloquear +STR_TRANSPARENT_INDUSTRIES_TOOLTIP :{BLACK}Ajustar transparencia para industrias. Ctrl+clic para bloquear +STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Ajustar transparencia para construcciones como estaciones, depósitos o puntos de ruta. Ctrl+clic para bloquear +STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Ajustar transparencia para puentes. Ctrl+clic para bloquear +STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Ajustar transparencia para estructuras como faros o antenas. Ctrl+clic para bloquear +STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Ajustar transparencia para catenaria. Ctrl+clic para bloquear +STR_TRANSPARENT_LOADING_TOOLTIP :{BLACK}Ajustar transparencia para los indicadores de carga. Ctrl+clic para bloquear STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Establece los objetos como invisibles en vez de transparentes # Linkgraph legend window @@ -3066,7 +3064,7 @@ STR_SPRITE_ALIGNER_GOTO_TOOLTIP :{BLACK}Va al sp STR_SPRITE_ALIGNER_PREVIOUS_BUTTON :{BLACK}Sprite anterior STR_SPRITE_ALIGNER_PREVIOUS_TOOLTIP :{BLACK}Salta al sprite anterior (ignorando pseudosprites, sprites recoloreados y sprites de fuente) y pasa del primer al último sprite STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Representa el sprite seleccionado. Su alineamiento es ignorado al dibujarlo -STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Mover el sprite, cambiando los ajustes X e Y. Ctrl+Clic mueve el sprite ocho unidades de una sola vez +STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Mover el sprite, cambiando los ajustes X e Y. Ctrl+clic mueve el sprite ocho unidades de una sola vez STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Reiniciar coordenadas relativas STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Reinicia las coordenadas relativas actuales STR_SPRITE_ALIGNER_OFFSETS_ABS :{BLACK}Coordenada X: {NUM}, Coordenada Y: {NUM} (Absoluta) @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atención: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Error Fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ha ocurrido un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ha ocurrido un error de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionará con la con la versión de TTDPatch informada por OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} es para la versión {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} está diseñado para ser usado con {STRING} @@ -3170,7 +3169,7 @@ STR_TOWN_DIRECTORY_CAPTION :{WHITE}Municipi STR_TOWN_DIRECTORY_NONE :{ORANGE}- Ninguna - STR_TOWN_DIRECTORY_TOWN :{ORANGE}{TOWN}{BLACK} ({COMMA}) STR_TOWN_DIRECTORY_CITY :{ORANGE}{TOWN}{YELLOW} (Ciudad){BLACK} ({COMMA}) -STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Nombres de los municipios - Clic sobre un nombre para centrar la vista principal en él. Ctrl+Clic abre una ventana de visualización en dicha posición +STR_TOWN_DIRECTORY_LIST_TOOLTIP :{BLACK}Nombres de los municipios - Clic sobre un nombre para centrar la vista principal en él. Ctrl+clic abre una ventana de visualización en dicha posición STR_TOWN_POPULATION :{BLACK}Población mundial: {COMMA} # Town view window @@ -3188,7 +3187,7 @@ STR_TOWN_VIEW_TOWN_GROWS_EVERY :{BLACK}El munic STR_TOWN_VIEW_TOWN_GROWS_EVERY_FUNDED :{BLACK}El municipio crece cada {ORANGE}{COMMA}{BLACK}{NBSP}día{P "" s} (edificios financiados) STR_TOWN_VIEW_TOWN_GROW_STOPPED :{BLACK}El municipio {RED}no{BLACK} está creciendo STR_TOWN_VIEW_NOISE_IN_TOWN :{BLACK}Nivel de ruido en el municipio: {ORANGE}{COMMA}{BLACK} Máx.: {ORANGE}{COMMA} -STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista sobre el municipio. Ctrl+Clic abre un punto de vista en dicha posición +STR_TOWN_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista sobre el municipio. Ctrl+clic abre un punto de vista en dicha posición STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON :{BLACK}Autoridad local STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP :{BLACK}Muestra la información sobre las autoridades locales STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Cambia el nombre del municipio @@ -3220,12 +3219,12 @@ STR_LOCAL_AUTHORITY_ACTION_NEW_BUILDINGS :Financiar la co STR_LOCAL_AUTHORITY_ACTION_EXCLUSIVE_TRANSPORT :Comprar derechos de transporte exclusivos STR_LOCAL_AUTHORITY_ACTION_BRIBE :Sobornar a la autoridad local -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Iniciar una pequeña campaña publicitaria local para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio pequeño alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Iniciar una campaña publicitaria local mediana para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio mediano alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Iniciar una gran campaña publicitaria local para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio grande alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Pagar la reconstrucción de las carreteras locales.{}Provoca considerables complicaciones de tráfico durante 6 meses.{}Coste: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_SMALL_ADVERTISING :{YELLOW}Iniciar una campaña publicitaria local pequeña para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio pequeño alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_MEDIUM_ADVERTISING :{YELLOW}Inicia una campaña publicitaria local mediana para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio mediano alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_LARGE_ADVERTISING :{YELLOW}Iniciar una campaña publicitaria local grande para atraer más pasajeros y carga a sus servicios de transporte.{}Proporciona un incremento temporal en la calificación de las estaciones en un radio grande alrededor del centro del municipio.{}Coste: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_ROAD_RECONSTRUCTION :{YELLOW}Paga la reconstrucción de las carreteras locales.{}Provoca considerables complicaciones de tráfico durante 6 meses.{}Coste: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_STATUE_OF_COMPANY :{YELLOW}Construye una estatua en honor a su empresa.{}Proporciona un incremento permanente en la calificación de las estaciones de este municipio.{}Coste: {CURRENCY_LONG} -STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Pagar la construcción de nuevos edificios comerciales en el municipio.{}Proporciona un incremento temporal en el crecimiento del municipio.{}Coste: {CURRENCY_LONG} +STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS :{YELLOW}Paga la construcción de nuevos edificios comerciales en el municipio.{}Proporciona un incremento temporal en el crecimiento del municipio.{}Coste: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_EXCLUSIVE_TRANSPORT :{YELLOW}Compra derechos de transporte exclusivos en este municipio durante un año.{}Las autoridades no permitirán el uso de las estaciones de la competencia.{}Coste: {CURRENCY_LONG} STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE :{YELLOW}Soborna a las autoridades locales para aumentar su calificación, con el riesgo de sufrir una penalización severa si es descubierto.{}Coste: {CURRENCY_LONG} @@ -3277,7 +3276,7 @@ STR_SUBSIDIES_OFFERED_FROM_TO :{ORANGE}{STRING STR_SUBSIDIES_NONE :{ORANGE}- Ninguno - STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Líneas ya subvencionadas: STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} desde {STRING} a {STRING}{YELLOW} ({COMPANY}{YELLOW}, hasta {DATE_SHORT}) -STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Clic sobre el servicio para centrar la vista principal en esta industria/municipio. Ctrl+Clic abre un punto de vista en dicha posición +STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Clic sobre el servicio para centrar la vista principal en esta industria/municipio. Ctrl+clic abre un punto de vista en dicha posición # Story book window STR_STORY_BOOK_CAPTION :{WHITE}Historia de {COMPANY} @@ -3293,7 +3292,7 @@ STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Ir a la STR_STORY_BOOK_INVALID_GOAL_REF :{RED}Referencia de objetivo inválida # Station list window -STR_STATION_LIST_TOOLTIP :{BLACK}Nombres de estación - Clic sobre un nombre para centrar la vista principal en la estación. Ctrl+Clic abre un punto de vista en dicha posición +STR_STATION_LIST_TOOLTIP :{BLACK}Nombres de estación - Clic sobre un nombre para centrar la vista principal en la estación. Ctrl+clic abre un punto de vista en dicha posición STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Mantén pulsado Ctrl para seleccionar más de un elemento STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Estaciones STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATION_FEATURES} @@ -3355,7 +3354,7 @@ STR_CARGO_RATING_EXCELLENT :Excelente STR_CARGO_RATING_OUTSTANDING :Excepcional ############ range for rating ends -STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista en la posición de la estación. Ctrl+Clic abre un punto de vista en dicha posición +STR_STATION_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista en la posición de la estación. Ctrl+clic abre un punto de vista en dicha posición STR_STATION_VIEW_RENAME_TOOLTIP :{BLACK}Cambia el nombre de la estación STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP :{BLACK}Muestra todos los trenes que tienen esta estación en su horario @@ -3370,7 +3369,7 @@ STR_STATION_VIEW_CLOSE_AIRPORT_TOOLTIP :{BLACK}Evita qu # Waypoint/buoy view window STR_WAYPOINT_VIEW_CAPTION :{WHITE}{WAYPOINT} -STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista en posición del punto de ruta. Ctrl+Clic abre un punto de vista en dicha posición +STR_WAYPOINT_VIEW_CENTER_TOOLTIP :{BLACK}Centrar vista en posición del punto de ruta. Ctrl+clic abre un punto de vista en dicha posición STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME :{BLACK}Cambiar nombre del punto de ruta STR_BUOY_VIEW_CENTER_TOOLTIP :{BLACK}Centra la vista en posición de la boya. Ctrl+clic abre un punto de vista en dicha posición STR_BUOY_VIEW_CHANGE_BUOY_NAME :{BLACK}Cambiar nombre de boya @@ -3823,15 +3822,15 @@ STR_VEHICLE_VIEW_ROAD_VEHICLE_CENTER_TOOLTIP :{BLACK}Centra l STR_VEHICLE_VIEW_SHIP_CENTER_TOOLTIP :{BLACK}Centra la vista principal en la posición del barco. Doble clic seguirá al barco en la vista principal. Ctrl+clic abre un nuevo punto de vista en dicha posición. STR_VEHICLE_VIEW_AIRCRAFT_CENTER_TOOLTIP :{BLACK}Centra la vista principal en la posición de la aeronave. Doble clic seguirá la aeronave en la vista principal. Ctrl+clic abre un nuevo punto de vista en dicha posición. -STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar tren al depósito. Ctrl+Clic para realizar solamente mantenimiento -STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar vehículo al depósito. Ctrl+Clic para realizar solamente mantenimiento -STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar barco al astillero. Ctrl+Clic para realizar solamente mantenimiento -STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar aeronave al hangar. Ctrl+Clic para realizar solamente mantenimiento +STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar tren al depósito. Ctrl+clic para realizar solamente mantenimiento +STR_VEHICLE_VIEW_ROAD_VEHICLE_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar vehículo al depósito. Ctrl+clic para realizar solamente mantenimiento +STR_VEHICLE_VIEW_SHIP_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar barco al astillero. Ctrl+clic para realizar solamente mantenimiento +STR_VEHICLE_VIEW_AIRCRAFT_SEND_TO_DEPOT_TOOLTIP :{BLACK}Enviar aeronave al hangar. Ctrl+clic para realizar solamente mantenimiento -STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Esto comprará una copia del tren incluyendo sus vagones. Ctrl+Clic compartirá las órdenes. Mayús+Clic muestra una estimación del precio sin realizar la compra -STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Esto comprará una copia del vehículo. Ctrl+Clic compartirá las órdenes. Mayús+Clic muestra una estimación del precio sin realizar la compra -STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Esto comprará una copia del barco. Ctrl+Clic compartirá las órdenes. Mayús+Clic muestra una estimación del precio sin realizar la compra -STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Esto comprará una copia de la aeronave. Ctrl+Clic compartirá las órdenes. Mayús+Clic muestra una estimación del precio sin realizar la compra +STR_VEHICLE_VIEW_CLONE_TRAIN_INFO :{BLACK}Esto comprará una copia del tren incluyendo sus vagones. Ctrl+clic compartirá las órdenes. Mayús+clic muestra una estimación del precio sin realizar la compra +STR_VEHICLE_VIEW_CLONE_ROAD_VEHICLE_INFO :{BLACK}Esto comprará una copia del vehículo. Ctrl+clic compartirá las órdenes. Mayús+clic muestra una estimación del precio sin realizar la compra +STR_VEHICLE_VIEW_CLONE_SHIP_INFO :{BLACK}Esto comprará una copia del barco. Ctrl+clic compartirá las órdenes. Mayús+clic muestra una estimación del precio sin realizar la compra +STR_VEHICLE_VIEW_CLONE_AIRCRAFT_INFO :{BLACK}Esto comprará una copia de la aeronave. Ctrl+clic compartirá las órdenes. Mayús+clic muestra una estimación del precio sin realizar la compra STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP :{BLACK}Fuerza al tren a proceder sin esperar a la apertura de señal @@ -3843,10 +3842,10 @@ STR_VEHICLE_VIEW_AIRCRAFT_REFIT_TOOLTIP :{BLACK}Reforma STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP :{BLACK}Cambia la dirección del tren STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP :{BLACK}Fuerza al vehículo a dar la vuelta -STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Ver órdenes del tren. Ctrl+Clic muestra su horario -STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Ver órdenes del vehículo Ctrl+Clic muestra su horario -STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Ver órdenes del barco. Ctrl+Clic muestra su horario -STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Ver órdenes de la aeronave. Ctrl+Clic muestra su horario +STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP :{BLACK}Ver órdenes del tren. Ctrl+clic muestra su horario +STR_VEHICLE_VIEW_ROAD_VEHICLE_ORDERS_TOOLTIP :{BLACK}Ver órdenes del vehículo Ctrl+clic muestra su horario +STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Ver órdenes del barco. Ctrl+clic muestra su horario +STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Ver órdenes de la aeronave. Ctrl+clic muestra su horario STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Muestra los detalles del tren STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Muestra los detalles del vehículo @@ -3916,8 +3915,8 @@ STR_VEHICLE_INFO_FEEDER_CARGO_VALUE :{BLACK}Crédito STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS :{BLACK}Intervalo de mantenimiento: {LTBLUE}{COMMA}{NBSP}días{BLACK} Último mantenimiento: {LTBLUE}{DATE_LONG} STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT :{BLACK}Intervalo de mantenimiento: {LTBLUE}{COMMA}%{BLACK} Último mantenimiento: {LTBLUE}{DATE_LONG} -STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Incrementar intervalo de mantenimiento en 10. Ctrl+Clic incrementa el intervalo de mantenimiento en 5 -STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Reducir intervalo de mantenimiento en 10. Ctrl+Clic reduce el intervalo de mantenimiento en 5 +STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Incrementar intervalo de mantenimiento en 10. Ctrl+clic incrementa el intervalo de mantenimiento en 5 +STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP :{BLACK}Reducir intervalo de mantenimiento en 10. Ctrl+clic reduce el intervalo de mantenimiento en 5 STR_SERVICE_INTERVAL_DROPDOWN_TOOLTIP :{BLACK}Cambia el tipo de intervalo de mantenimiento STR_VEHICLE_DETAILS_DEFAULT :Por defecto diff --git a/src/lang/spanish_MX.txt b/src/lang/spanish_MX.txt index 71c3a00d46..ee8d73a7d2 100644 --- a/src/lang/spanish_MX.txt +++ b/src/lang/spanish_MX.txt @@ -954,7 +954,7 @@ STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit malasio STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_LEFT :Manejar por la izquierda STR_GAME_OPTIONS_ROAD_VEHICLES_DROPDOWN_RIGHT :Manejar por la derecha -STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de pueblos +STR_GAME_OPTIONS_TOWN_NAMES_FRAME :{BLACK}Nombres de pueblos: STR_GAME_OPTIONS_TOWN_NAMES_DROPDOWN_TOOLTIP :{BLACK}Elegir el estilo de nombres para pueblos ############ start of townname region @@ -994,6 +994,7 @@ STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_EVERY_12_MONTHS :Cada 12 meses STR_GAME_OPTIONS_LANGUAGE :{BLACK}Idioma STR_GAME_OPTIONS_LANGUAGE_TOOLTIP :{BLACK}Elegir el idioma de la interfaz +STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE :{STRING} ({NUM}% completado) STR_GAME_OPTIONS_FULLSCREEN :{BLACK}Pantalla completa STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}Jugar OpenTTD en pantalla completa @@ -1007,6 +1008,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Acelerac STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Activar esta casilla para intentar emplear la aceleración por hardware. Este cambio solo tiene efecto tras reiniciar el juego STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Esta configuración solo tendrá efecto después de reiniciar el juego +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Activar esta casilla para realizar sincronización vertical de pantalla (VSync). Este cambio solo tiene efecto tras reiniciar el juego y si la aceleración por hardware está activada. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Tamaño de la interfaz STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Elegir el tamaño de los elementos de la interfaz @@ -1139,6 +1143,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Configur STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Filtrar texto: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Desplegar todo STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Plegar todo +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Restablecer todos los ajustes STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(sin explicación disponible) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Valor por defecto: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Tipo de opción: {ORANGE}{STRING} @@ -1147,6 +1152,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Opción de part STR_CONFIG_SETTING_TYPE_GAME_INGAME :Opción de partida (almacenada en la partida guardada, afecta solamente la partida actual) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Opción de empresa (se almacena en las partidas guardadas, afecta solamente las partidas nuevas) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Opción de empresa (almacenada en la partida guardada, afecta solamente la empresa actual) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}¡Advertencia! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Esta acción restablecerá todos los ajustes del juego a sus valores originales.{}¿Deseas proceder? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Categoría: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Tipo: @@ -1985,6 +1992,9 @@ STR_FACE_TIE :Corbata: STR_FACE_EARRING :Aretes: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Cambiar corbata o aretes +STR_NETWORK_SERVER_VISIBILITY_PRIVATE :Privado +STR_NETWORK_SERVER_VISIBILITY_PUBLIC :Público + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Multijugador STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Nombre del jugador: @@ -2047,10 +2057,8 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}La parti STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Establecer contraseña STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Proteger la partida con una contraseña para prevenir el acceso a otras personas -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Público -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Permitir escoger entre una partida pública (Internet) y una partida privada (LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :No -STR_NETWORK_START_SERVER_ADVERTISED :Sí +STR_NETWORK_START_SERVER_VISIBILITY_LABEL :{BLACK}Visibilidad +STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP :{BLACK}Quién puede ver tu servidor en la lista pública STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} cliente{P "" s} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Número máximo de clientes: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Elegir el número máximo de clientes. No es necesario que se conecten todos @@ -2065,46 +2073,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Otros ju STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Introducir un nombre para la partida en red -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Cualquiera -STR_NETWORK_LANG_ENGLISH :Inglés -STR_NETWORK_LANG_GERMAN :Alemán -STR_NETWORK_LANG_FRENCH :Francés -STR_NETWORK_LANG_BRAZILIAN :Portugués (Brasil) -STR_NETWORK_LANG_BULGARIAN :Búlgaro -STR_NETWORK_LANG_CHINESE :Chino -STR_NETWORK_LANG_CZECH :Checo -STR_NETWORK_LANG_DANISH :Danés -STR_NETWORK_LANG_DUTCH :Alemán -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Finés -STR_NETWORK_LANG_HUNGARIAN :Húngaro -STR_NETWORK_LANG_ICELANDIC :Islandés -STR_NETWORK_LANG_ITALIAN :Italiano -STR_NETWORK_LANG_JAPANESE :Japonés -STR_NETWORK_LANG_KOREAN :Coreano -STR_NETWORK_LANG_LITHUANIAN :Lituano -STR_NETWORK_LANG_NORWEGIAN :Noruego -STR_NETWORK_LANG_POLISH :Polaco -STR_NETWORK_LANG_PORTUGUESE :Portugués -STR_NETWORK_LANG_ROMANIAN :Rumano -STR_NETWORK_LANG_RUSSIAN :Ruso -STR_NETWORK_LANG_SLOVAK :Eslovaco -STR_NETWORK_LANG_SLOVENIAN :Esloveno -STR_NETWORK_LANG_SPANISH :Español -STR_NETWORK_LANG_SWEDISH :Sueco -STR_NETWORK_LANG_TURKISH :Turco -STR_NETWORK_LANG_UKRAINIAN :Ucraniano -STR_NETWORK_LANG_AFRIKAANS :Afrikáans -STR_NETWORK_LANG_CROATIAN :Croata -STR_NETWORK_LANG_CATALAN :Catalán -STR_NETWORK_LANG_ESTONIAN :Estonio -STR_NETWORK_LANG_GALICIAN :Gallego -STR_NETWORK_LANG_GREEK :Griego -STR_NETWORK_LANG_LATVIAN :Letón -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sala virtual de partidas multijugador @@ -2152,19 +2120,46 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Desconec STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servidor protegido. Introducir contraseña STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Empresa protegida. Introducir contraseña -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Lista de clientes # Network company list added strings -STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Lista de clientes -STR_NETWORK_COMPANY_LIST_SPECTATE :Observar -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nueva empresa +STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Jugadores conectados # Network client list -STR_NETWORK_CLIENTLIST_KICK :Expulsar -STR_NETWORK_CLIENTLIST_BAN :Prohibir acceso -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Hablar a todos -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Hablar a una empresa -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Mensaje privado +STR_NETWORK_CLIENT_LIST_CAPTION :{WHITE}Multijugador +STR_NETWORK_CLIENT_LIST_SERVER :{BLACK}Servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP :{BLACK}Nombre del servidor en el que estás jugando +STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP :{BLACK}Modificar nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION :Nombre del servidor +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY :{BLACK}Visibilidad +STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP :{BLACK}Quién puede ver tu servidor en la lista pública +STR_NETWORK_CLIENT_LIST_PLAYER :{BLACK}Jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME :{BLACK}Nombre +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP :{BLACK}Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP :{BLACK}Modificar nombre de jugador +STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION :Tu nombre de jugador +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP :{BLACK}Acciones administrativas para este cliente +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP :{BLACK}Acciones administrativas para esta empresa +STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP :{BLACK}Unirse a esta empresa +STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP :{BLACK}Enviar mensaje a este jugador +STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP :{BLACK}Enviar mensaje a todos los jugadores de la empresa +STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP :{BLACK}Enviar mensaje a los espectadores +STR_NETWORK_CLIENT_LIST_SPECTATORS :Espectadores +STR_NETWORK_CLIENT_LIST_NEW_COMPANY :(Nueva empresa) +STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP :{BLACK}Crear nueva empresa y unirse a ella +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP :{BLACK}Este eres tú +STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP :{BLACK}Este es el host del juego + +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK :Expulsar +STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN :Bloquear acceso +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET :Eliminar +STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK :Restablecer contraseña + +STR_NETWORK_CLIENT_LIST_ASK_CAPTION :{WHITE}Acción de aministrador +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK :{YELLOW}¿Sacar al jugador "{STRING}"? +STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN :{YELLOW}¿Bloquear acceso al jugador "{STRING}"? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET :{YELLOW}¿Eliminar la empresa "{COMPANY}"? +STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK :{YELLOW}¿Restablecer contraseña de la empresa "{COMPANY}"? STR_NETWORK_SERVER :Servidor STR_NETWORK_CLIENT :Cliente @@ -2209,6 +2204,7 @@ STR_NETWORK_ERROR_SERVER_START :{WHITE}No se pu STR_NETWORK_ERROR_CLIENT_START :{WHITE}No se pudo conectar STR_NETWORK_ERROR_TIMEOUT :{WHITE}Tiempo de espera agotado en conexión #{NUM} STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Se produjo un error de protocolo y la conexión fue cerrada +STR_NETWORK_ERROR_BAD_PLAYER_NAME :{WHITE}Aún no tienes nombre de jugador, pero lo puedes poner en la parte superior de la ventana de Multijugador. STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}La versión de este cliente no corresponde con la versión del servidor STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Contraseña incorrecta STR_NETWORK_ERROR_SERVER_FULL :{WHITE}El servidor está completo @@ -2221,6 +2217,7 @@ STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Tardaste STR_NETWORK_ERROR_TIMEOUT_COMPUTER :{WHITE}Tu computadora es demasiado lenta para seguir la velocidad del servidor STR_NETWORK_ERROR_TIMEOUT_MAP :{WHITE}Tu computadora tardó demasiado en descargar el mapa STR_NETWORK_ERROR_TIMEOUT_JOIN :{WHITE}Tu computadora tardó demasiado en conectarse al servidor +STR_NETWORK_ERROR_INVALID_CLIENT_NAME :{WHITE}Tu nombre de jugador no es válido ############ Leave those lines in this order!! STR_NETWORK_ERROR_CLIENT_GENERAL :error general @@ -2243,6 +2240,7 @@ STR_NETWORK_ERROR_CLIENT_TIMEOUT_PASSWORD :no se recibió STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER :tiempo agotado en general STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP :la descarga del mapa tardó demasiado STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN :el procesado del mapa tardó demasiado +STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME :nombre de cliente no válido ############ End of leave-in-this-order STR_NETWORK_ERROR_CLIENT_GUI_LOST_CONNECTION_CAPTION :{WHITE}Posible pérdida de conexión @@ -2532,7 +2530,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Construi STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Colocar boya para utilizar como punto de ruta marítimo. Mayús muestra una estimación del precio STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Construir acueducto. Mayús muestra una estimación del precio STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Definir cuerpo de agua.{}Crea un canal, a menos que se pulse Ctrl en un área al nivel del mar, en cuyo caso se inundarán los alrededores -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Colocar ríos +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Colocar ríos. Ctrl para seleccionar un área en diagonal # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Orientación del astillero @@ -3082,6 +3080,7 @@ STR_NEWGRF_ERROR_MSG_WARNING :{RED}Atención: STR_NEWGRF_ERROR_MSG_ERROR :{RED}Error: {SILVER}{STRING} STR_NEWGRF_ERROR_MSG_FATAL :{RED}Error fatal: {SILVER}{STRING} STR_NEWGRF_ERROR_FATAL_POPUP :{WHITE}Ocurrió un error fatal de NewGRF:{}{STRING} +STR_NEWGRF_ERROR_POPUP :{WHITE}Ocurrió un error de NewGRF:{}{STRING} STR_NEWGRF_ERROR_VERSION_NUMBER :{1:STRING} no funcionará con la con la versión de TTDPatch reportada por OpenTTD STR_NEWGRF_ERROR_DOS_OR_WINDOWS :{1:STRING} es la para la versión {STRING} de TTD STR_NEWGRF_ERROR_UNSET_SWITCH :{1:STRING} está diseñado para usarse con {STRING} diff --git a/src/lang/swedish.txt b/src/lang/swedish.txt index 3105163e73..449e42d9d7 100644 --- a/src/lang/swedish.txt +++ b/src/lang/swedish.txt @@ -1006,6 +1006,9 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Hårdvar STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Markera denna rutan för att tillåta OpenTTD att försöka använda hårdvaruacceleration. Ändrad inställning kommer bara att gälla efter omstart. STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Inställningen kommer bara att gälla efter omstart av spelet +STR_GAME_OPTIONS_VIDEO_VSYNC :{BLACK}VSync +STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :{BLACK}Markera den här rutan för att v-synka skärmen. Ändringar i den här inställningen kommer bara att tillämpas vid omstart av spelet. Fungerar bara med hårdvaruacceleration aktiverad. + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Gränssnittstorlek STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Välj vilken gränssnittsstorlek som ska användas @@ -1138,6 +1141,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Inställ STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Sökfilter: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Utöka alla STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Stäng alla +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Återställ alla värden STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(ingen förklaring tillgänglig) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Standardvärde: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Typ av inställning: {ORANGE}{STRING} @@ -1146,6 +1150,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Spelinställnin STR_CONFIG_SETTING_TYPE_GAME_INGAME :Spelinställning (sparad i spel-fil och påverkar enbart nuvarande spel) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Företagsinställning (sparad i spel-fil och påverkar enbart nya spel) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Företagsinställning (sparad i spel-fil och påverkar enbart nuvarande företag) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Varning! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Detta kommer att återställa alla spelinställningar till deras standardvärden.{}Är du säker på att du vill fortsätta? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Kategori: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Typ: @@ -1984,6 +1990,7 @@ STR_FACE_TIE :Slips: STR_FACE_EARRING :Örhänge: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Ändra slips eller örhänge + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Flera spelare STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Spelarnamn: @@ -2046,10 +2053,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Namnet p STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Bestäm lösenord STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Skydda spelet med ett lösenord så att inte andra än dem som har lösenordet kan gå med i spelet -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Publikt -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Välj mellan ett publikt (internet) eller icke publikt (Local Area Network. LAN) spel -STR_NETWORK_START_SERVER_UNADVERTISED :Nej -STR_NETWORK_START_SERVER_ADVERTISED :Ja STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} klient{P "" er} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Max antal tillåtna klienter: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Välj max antal tillåtna klienter. Alla platser måste inte fyllas. @@ -2064,46 +2067,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Andra sp STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Mata in ett namn för nätverksspelet -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Valfritt -STR_NETWORK_LANG_ENGLISH :Engelska -STR_NETWORK_LANG_GERMAN :Tyska -STR_NETWORK_LANG_FRENCH :Franska -STR_NETWORK_LANG_BRAZILIAN :Brasilianska -STR_NETWORK_LANG_BULGARIAN :Belgiska -STR_NETWORK_LANG_CHINESE :Kinesiska -STR_NETWORK_LANG_CZECH :Tjeckiska -STR_NETWORK_LANG_DANISH :Danska -STR_NETWORK_LANG_DUTCH :Holländska -STR_NETWORK_LANG_ESPERANTO :Spanska -STR_NETWORK_LANG_FINNISH :Finska -STR_NETWORK_LANG_HUNGARIAN :Ungerska -STR_NETWORK_LANG_ICELANDIC :Isländska -STR_NETWORK_LANG_ITALIAN :Italienska -STR_NETWORK_LANG_JAPANESE :Japanska -STR_NETWORK_LANG_KOREAN :Koreanska -STR_NETWORK_LANG_LITHUANIAN :Litauiska -STR_NETWORK_LANG_NORWEGIAN :Norska -STR_NETWORK_LANG_POLISH :Polska -STR_NETWORK_LANG_PORTUGUESE :Portugisiska -STR_NETWORK_LANG_ROMANIAN :Rumänska -STR_NETWORK_LANG_RUSSIAN :Ryska -STR_NETWORK_LANG_SLOVAK :Slovakiska -STR_NETWORK_LANG_SLOVENIAN :Slovenska -STR_NETWORK_LANG_SPANISH :Spanska -STR_NETWORK_LANG_SWEDISH :Svenska -STR_NETWORK_LANG_TURKISH :Turkiska -STR_NETWORK_LANG_UKRAINIAN :Ukrainska -STR_NETWORK_LANG_AFRIKAANS :Afrikaans -STR_NETWORK_LANG_CROATIAN :Kroatiska -STR_NETWORK_LANG_CATALAN :Katalanska -STR_NETWORK_LANG_ESTONIAN :Estniska -STR_NETWORK_LANG_GALICIAN :Galiciska -STR_NETWORK_LANG_GREEK :Grekiska -STR_NETWORK_LANG_LATVIAN :Lettiska -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Nätverksspel @@ -2151,19 +2114,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Koppla i STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Servern är skyddad. Ange lösenord STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Företaget är skyddat. Ange lösenord -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Klientlista # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Klientlista -STR_NETWORK_COMPANY_LIST_SPECTATE :Åskåda -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Nytt företag # Network client list -STR_NETWORK_CLIENTLIST_KICK :Kasta ut -STR_NETWORK_CLIENTLIST_BAN :Bannlys -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Prata med alla -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Prata med alla i företaget -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Privat meddelande + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Klient @@ -2531,7 +2488,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Bygg ham STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Placera en boj som kan som kan användas som riktmärke. Shift växlar mellan att bygga/visa beräknad kostnad STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Bygg akvedukt. Shift växlar mellan att bygga/visa beräknad kostnad STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Definiera vattenyta.{}Skapa en kanal, om inte CTRL är nedhållen vid havsnivå, då den kommer att översvämma närliggande områden istället -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Placera flod +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Placera flod. Ctrl markerar ytan diagonalt # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Riktning för skeppsvarv @@ -3883,7 +3840,7 @@ STR_VEHICLE_COMMAND_STARTED_SMALL :{TINY_FONT}{GRE STR_VEHICLE_COMMAND_STARTED :{GREEN}Startad # Vehicle details -STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Details) +STR_VEHICLE_DETAILS_CAPTION :{WHITE}{VEHICLE} (Detaljer) STR_VEHICLE_NAME_BUTTON :{BLACK}Namn STR_VEHICLE_DETAILS_TRAIN_RENAME :{BLACK}Byt namn på tåg diff --git a/src/lang/tamil.txt b/src/lang/tamil.txt index fb48a9d56c..f6c928e222 100644 --- a/src/lang/tamil.txt +++ b/src/lang/tamil.txt @@ -962,6 +962,8 @@ STR_GAME_OPTIONS_FULLSCREEN_TOOLTIP :{BLACK}OpenTTD- STR_GAME_OPTIONS_RESOLUTION :{BLACK}திரையின் அளவு STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}திரை அளவினைத் தேர்ந்தெடுக்கவும் STR_GAME_OPTIONS_RESOLUTION_OTHER :மற்றவை +STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}இடைமுக அளவு @@ -1696,6 +1698,7 @@ STR_FACE_LOAD :{BLACK}ஏற STR_FACE_LOAD_TOOLTIP :{BLACK}பிடித்த முகத்தினை பதிவேற்று STR_FACE_LOAD_DONE :{WHITE}உங்களுடைய பிடித்த முகம் OpenTTD உள்ளமைவு கோப்பிலிருந்து ஏற்றப்பட்டுள்ளது STR_FACE_FACECODE :{BLACK}விளையாடுபவர் முக எண் +STR_FACE_FACECODE_TOOLTIP :{BLACK}நிறுவனரின் முக எண்னை பார் மற்றும்/அல்லது அமை STR_FACE_FACECODE_CAPTION :{WHITE}நிறுவனரின் முக எண்னை பார் அல்லது அமை STR_FACE_FACECODE_SET :{WHITE}புதிய முக எண் குறி அமைக்கப்பட்டது STR_FACE_SAVE :{BLACK}சேமி @@ -1731,6 +1734,7 @@ STR_FACE_TIE :Tie: STR_FACE_EARRING :கம்மல்: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Tie அல்லது காதணியை மாற்றவும் + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}பல்வீரர் STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}விளையாடுபவரின் பெயர்: @@ -1786,9 +1790,6 @@ STR_NETWORK_START_SERVER_CAPTION :{WHITE}பு STR_NETWORK_START_SERVER_NEW_GAME_NAME :{BLACK}விளையாட்டு பெயர்: STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}கடவுச்சொல்லினை அமைக்கவும் -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}விளம்பரப்படுத்தப்பட்ட -STR_NETWORK_START_SERVER_UNADVERTISED :இல்லை -STR_NETWORK_START_SERVER_ADVERTISED :ஆம் STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} விளையாடுபவர்{P "" கள்} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}அதிகபட்ச வீரர்கள்: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}வாடிக்கையாளர்களின் அதிகபட்ச எண்ணிக்கையைத் தேர்வுசெய்க. எல்லா இடங்களும் நிரப்பப்பட வேண்டியதில்லை @@ -1802,46 +1803,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}பே STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}இணைய ஆட்டத்திற்கு ஒரு பெயரினை இடு -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :எதுவும் -STR_NETWORK_LANG_ENGLISH :ஆங்கிலம் -STR_NETWORK_LANG_GERMAN :ஜெர்மன் -STR_NETWORK_LANG_FRENCH :பிரெஞ்சு -STR_NETWORK_LANG_BRAZILIAN :பிரசில்லியன் -STR_NETWORK_LANG_BULGARIAN :பல்கேரியன் -STR_NETWORK_LANG_CHINESE :சீன மொழி -STR_NETWORK_LANG_CZECH :செக் -STR_NETWORK_LANG_DANISH :டேனிஷ் -STR_NETWORK_LANG_DUTCH :டச் -STR_NETWORK_LANG_ESPERANTO :உலகப் பொதுச் செயற்கைமொழி -STR_NETWORK_LANG_FINNISH :பின்னிஷ் -STR_NETWORK_LANG_HUNGARIAN :ஹங்கேரியன் -STR_NETWORK_LANG_ICELANDIC :இஸ்லாந்திய மொழி -STR_NETWORK_LANG_ITALIAN :இத்தாலியன் -STR_NETWORK_LANG_JAPANESE :ஜப்பானிய மொழி -STR_NETWORK_LANG_KOREAN :கோரிய மொழி -STR_NETWORK_LANG_LITHUANIAN :லிதுவேனியன் -STR_NETWORK_LANG_NORWEGIAN :நார்வேஜியன் -STR_NETWORK_LANG_POLISH :போலிஷ் -STR_NETWORK_LANG_PORTUGUESE :போர்த்துகீசியம் -STR_NETWORK_LANG_ROMANIAN :ரோமானிய மொழி -STR_NETWORK_LANG_RUSSIAN :ரஷ்ய மொழி -STR_NETWORK_LANG_SLOVAK :ஸ்லவோனிய மொழி -STR_NETWORK_LANG_SLOVENIAN :ஸ்லவோனிய மொழி -STR_NETWORK_LANG_SPANISH :ஸ்பானிஷ் -STR_NETWORK_LANG_SWEDISH :சவீடிஷ் -STR_NETWORK_LANG_TURKISH :டர்கிஷ் -STR_NETWORK_LANG_UKRAINIAN :உக்ரேனியம் -STR_NETWORK_LANG_AFRIKAANS :ஆப்ரிகான்ஸ் -STR_NETWORK_LANG_CROATIAN :குரோஏசியன் -STR_NETWORK_LANG_CATALAN :கடலான் -STR_NETWORK_LANG_ESTONIAN :எஸ்தோனியம் -STR_NETWORK_LANG_GALICIAN :கலிசியம் -STR_NETWORK_LANG_GREEK :கிரேக்க மொழி -STR_NETWORK_LANG_LATVIAN :லாத்வியன் -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_PREPARE_TO_JOIN :{BLACK}சேர தொடங்கப்படுகிறது: {ORANGE}{STRING} @@ -1887,19 +1848,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}இண STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}சர்வர் காக்கப்பட்டுள்ளது. கடவுச்சொல்லினை இடவும் STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}நிற்வனம் காக்கப்பட்டுள்ளது. கடவுச்சொல்லினை இடவும் -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}விளையாடுவோர் பட்டியல் # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :விளையாடுவோர் பட்டியல் -STR_NETWORK_COMPANY_LIST_SPECTATE :கவனி -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :புதிய நிறுவனம் # Network client list -STR_NETWORK_CLIENTLIST_KICK :உதை -STR_NETWORK_CLIENTLIST_BAN :அனுமதிக்காதே -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :அனைவருடனும் பேசு -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :நிறுவனத்திடம் பேசு -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :இரகசிய தகவல் + + STR_NETWORK_SERVER :சர்வர் STR_NETWORK_CLIENT :Client @@ -2117,6 +2072,7 @@ STR_RAIL_TOOLBAR_MAGLEV_CONSTRUCTION_CAPTION :மேக்ல STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK :{BLACK}இரயில்வே இருப்புப் பாதையினை கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING :{BLACK}இரயில் பணிமனையினைக் (இரயில்களை வாங்க மற்றும் பழுதுபார்க்க) கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் +STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT :{BLACK}இரயில் தடத்தை வழிப்புள்ளியாக மாற்றும். வழிப்புள்ளிகளை இணைக்க Ctrl-ஐ அழுத்தவும். கட்டுமான/செலவு மதிப்பீட்டினை காட்டShift-ஐ அழுத்தவும். STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION :{BLACK}இரயில் நிலையத்தினை கட்டவும். Ctrl அழுத்தினால் நிலையங்களினை இணைக்கலாம். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS :{BLACK}இரயில்வே சிக்னல்களைக் கட்டவும். Ctrl அழுத்தினால் சிக்னல் வகைகளை மாற்றலாம்{}இரயில் தடத்தின்மேல் இழுத்தினால் சிக்னல்களை அமைக்கலாம். Ctrl அழுத்தினால் அடுத்த எணைப்பு வரை சிக்னல்கள் அமைக்கப்படும்{}Ctrl+Click அழுத்தினால் சிக்னல் தேர்ந்தெடுக்கும் திரை தெரியும்/மரையும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE :{BLACK}இரயில்வே பாலத்தினை கட்டவும். Shift அழுத்தினால் கட்டுமான/செலவு மதிப்பீடு காட்டப்படும் diff --git a/src/lang/thai.txt b/src/lang/thai.txt index 5649ec07d9..269f5e5f29 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -960,6 +960,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}เล STR_GAME_OPTIONS_RESOLUTION_OTHER :อื่นๆ + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}ขนาดของแผงควบคุม @@ -1819,6 +1820,7 @@ STR_FACE_TIE :เนคไท STR_FACE_EARRING :ต่างหู: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}เปลี่ยนเนคไทหรือต่างหู + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}เล่นหลายคน STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}ชื่อผู้เล่น: @@ -1877,10 +1879,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}ชื STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}กำหนดรหัสผ่าน STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}ป้องกันเกมด้วยรหัสผ่านหากไม่ต้องการให้มีการเข้าร่วมจากบุคคลทั่วไป -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}การประกาศ -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}เลือกระหว่างการโฆษณา (internet) หรือไม่โฆษณา (Local Area Network, LAN) เกม -STR_NETWORK_START_SERVER_UNADVERTISED :ไม่ใช่ -STR_NETWORK_START_SERVER_ADVERTISED :ใช่ STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} ลูกข่าย STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}ลูกข่ายสูงสุด: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}เลือกจำนวนมากสุดของลูกข่าย (ไม่จำเป็นต้องครบตามจำนวนนี้) @@ -1895,46 +1893,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}ผู STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}พิมพ์ชื่อสำหรับเล่นในเครือข่าย -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :อะไรก็ได้ -STR_NETWORK_LANG_ENGLISH :ภาษาอังกฤษ -STR_NETWORK_LANG_GERMAN :ภาษาเยอรมัน -STR_NETWORK_LANG_FRENCH :ภาษาฝรั่งเศส -STR_NETWORK_LANG_BRAZILIAN :ภาษาบราซิล -STR_NETWORK_LANG_BULGARIAN :ภาษาบัลกาเรีย -STR_NETWORK_LANG_CHINESE :จีน -STR_NETWORK_LANG_CZECH :เช็ก -STR_NETWORK_LANG_DANISH :เดนมาร์ก -STR_NETWORK_LANG_DUTCH :เนเธอร์แลนด์ -STR_NETWORK_LANG_ESPERANTO :ภาษาโลก(Esperanto) -STR_NETWORK_LANG_FINNISH :ฟินแลนด์ -STR_NETWORK_LANG_HUNGARIAN :ฮังการี -STR_NETWORK_LANG_ICELANDIC :ไอร์แลนด์ -STR_NETWORK_LANG_ITALIAN :อิตาลี -STR_NETWORK_LANG_JAPANESE :ญี่ปุ่น -STR_NETWORK_LANG_KOREAN :เกาหลี -STR_NETWORK_LANG_LITHUANIAN :ลิทัวเนีย -STR_NETWORK_LANG_NORWEGIAN :นอร์เวย์ -STR_NETWORK_LANG_POLISH :โปแลนด์ -STR_NETWORK_LANG_PORTUGUESE :โปรตุเกส -STR_NETWORK_LANG_ROMANIAN :โรมาเนีย -STR_NETWORK_LANG_RUSSIAN :รัสเซีย -STR_NETWORK_LANG_SLOVAK :สโลวัก -STR_NETWORK_LANG_SLOVENIAN :สโลวาเนีย -STR_NETWORK_LANG_SPANISH :สเปน -STR_NETWORK_LANG_SWEDISH :สวีเดน -STR_NETWORK_LANG_TURKISH :ตุรกี -STR_NETWORK_LANG_UKRAINIAN :ยูเครน -STR_NETWORK_LANG_AFRIKAANS :อัฟกานิสถาน -STR_NETWORK_LANG_CROATIAN :โครเอเชีย -STR_NETWORK_LANG_CATALAN :คาตาลัน -STR_NETWORK_LANG_ESTONIAN :เอสโตเนีย -STR_NETWORK_LANG_GALICIAN :กาลีเซีย -STR_NETWORK_LANG_GREEK :กรีก -STR_NETWORK_LANG_LATVIAN :ลัทเวีย -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}ห้องรับรองโหมดผู้เล่นหลายคน @@ -1985,15 +1943,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}บร # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :รายการลูกข่าย -STR_NETWORK_COMPANY_LIST_SPECTATE :ผู้ชม -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :บริษัทใหม่ # Network client list -STR_NETWORK_CLIENTLIST_KICK :เตะ -STR_NETWORK_CLIENTLIST_BAN :แบน -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :พูดกับผู้เล่นทั้งหมด -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :พูดกับผู้เล่นในบริษัทเดียวกัน -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :ข้อความส่วนตัว + + STR_NETWORK_SERVER :เซิฟเวอร์ STR_NETWORK_CLIENT :ลูกข่าย diff --git a/src/lang/traditional_chinese.txt b/src/lang/traditional_chinese.txt index 241f4537c2..b59dd4b30f 100644 --- a/src/lang/traditional_chinese.txt +++ b/src/lang/traditional_chinese.txt @@ -974,6 +974,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}選擇 STR_GAME_OPTIONS_RESOLUTION_OTHER :其它 + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}介面大小 STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}選擇使用的介面元素大小 @@ -1878,6 +1879,7 @@ STR_FACE_TIE :領帶: STR_FACE_EARRING :耳飾: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}改變領帶或耳飾 + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}多人遊戲 STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}玩家名稱: @@ -1938,10 +1940,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}遊戲 STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}設定密碼 STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}如果您不想讓大眾連線的話,可以用密碼保護遊戲 -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}已啟用宣傳 -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}選擇是否在互聯網上宣傳此遊戲 -STR_NETWORK_START_SERVER_UNADVERTISED :否 -STR_NETWORK_START_SERVER_ADVERTISED :是 STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} 玩家 STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}用戶端上限: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}選擇連線人數上限,但不是每個名額都要有人連線 @@ -1956,46 +1954,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}讓其 STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}為連線遊戲輸入一個名稱 -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :不限 -STR_NETWORK_LANG_ENGLISH :英語 -STR_NETWORK_LANG_GERMAN :德語 -STR_NETWORK_LANG_FRENCH :法語 -STR_NETWORK_LANG_BRAZILIAN :巴西葡萄牙語 -STR_NETWORK_LANG_BULGARIAN :保加利亞語 -STR_NETWORK_LANG_CHINESE :中文 -STR_NETWORK_LANG_CZECH :捷克語 -STR_NETWORK_LANG_DANISH :丹麥語 -STR_NETWORK_LANG_DUTCH :荷蘭語 -STR_NETWORK_LANG_ESPERANTO :世界語 -STR_NETWORK_LANG_FINNISH :芬蘭語 -STR_NETWORK_LANG_HUNGARIAN :匈牙利語 -STR_NETWORK_LANG_ICELANDIC :冰島語 -STR_NETWORK_LANG_ITALIAN :義大利語 -STR_NETWORK_LANG_JAPANESE :日文 -STR_NETWORK_LANG_KOREAN :韓文 -STR_NETWORK_LANG_LITHUANIAN :立陶宛語 -STR_NETWORK_LANG_NORWEGIAN :挪威語 -STR_NETWORK_LANG_POLISH :波蘭語 -STR_NETWORK_LANG_PORTUGUESE :葡萄牙語 -STR_NETWORK_LANG_ROMANIAN :羅馬尼亞語 -STR_NETWORK_LANG_RUSSIAN :俄語 -STR_NETWORK_LANG_SLOVAK :斯洛伐克語 -STR_NETWORK_LANG_SLOVENIAN :斯洛維尼亞語 -STR_NETWORK_LANG_SPANISH :西班牙語 -STR_NETWORK_LANG_SWEDISH :瑞典語 -STR_NETWORK_LANG_TURKISH :土耳其語 -STR_NETWORK_LANG_UKRAINIAN :烏克蘭語 -STR_NETWORK_LANG_AFRIKAANS :南非荷蘭語 -STR_NETWORK_LANG_CROATIAN :克羅埃西亞語 -STR_NETWORK_LANG_CATALAN :加泰隆語 (西班牙) -STR_NETWORK_LANG_ESTONIAN :愛沙尼亞語 -STR_NETWORK_LANG_GALICIAN :加里西亞語 (西班牙) -STR_NETWORK_LANG_GREEK :現代希臘語 -STR_NETWORK_LANG_LATVIAN :拉脫維亞語 -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}多人遊戲大廳 @@ -2046,15 +2004,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}公司 # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :用戶端清單 -STR_NETWORK_COMPANY_LIST_SPECTATE :旁觀者 -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :新公司 # Network client list -STR_NETWORK_CLIENTLIST_KICK :踢除 -STR_NETWORK_CLIENTLIST_BAN :封鎖 -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :對全員說話 -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :對公司說話 -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :私人訊息 + + STR_NETWORK_SERVER :伺服器 STR_NETWORK_CLIENT :用戶端 diff --git a/src/lang/turkish.txt b/src/lang/turkish.txt index 6b08256674..cef6a3ff1f 100644 --- a/src/lang/turkish.txt +++ b/src/lang/turkish.txt @@ -993,6 +993,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :diğer STR_GAME_OPTIONS_RESOLUTION_ITEM :{NUM}x{NUM} + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Arayüz boyutu STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Kullanmak üzere arayüz bileşen boyutunu seçin @@ -1927,6 +1928,7 @@ STR_FACE_TIE :Kravat: STR_FACE_EARRING :Küpe: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Kravatı veya küpeyi değiştir + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Çok Oyunculu STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Oyuncu adı: @@ -1985,10 +1987,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Bu oyun STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Parola koy STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Erişimi kısıtlamak için oyuna parola koy -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Duyurulan -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Duyurulan (internet) ve duyurulmayan (yerel ağ, LAN) oyun türlerinden birini seçin -STR_NETWORK_START_SERVER_UNADVERTISED :Hayır -STR_NETWORK_START_SERVER_ADVERTISED :Evet STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} istemci STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Azami istemci sayısı: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}İzin verilen en fazla oyuncu sayısını seç. Her yerin dolması gerekmez @@ -2003,46 +2001,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Diğer o STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Ağ oyunu için bir isim girin -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Farketmez -STR_NETWORK_LANG_ENGLISH :İngilizce -STR_NETWORK_LANG_GERMAN :Almanca -STR_NETWORK_LANG_FRENCH :Fransızca -STR_NETWORK_LANG_BRAZILIAN :Brezilyaca -STR_NETWORK_LANG_BULGARIAN :Bulgarca -STR_NETWORK_LANG_CHINESE :Çince -STR_NETWORK_LANG_CZECH :Çekce -STR_NETWORK_LANG_DANISH :Danimarkaca -STR_NETWORK_LANG_DUTCH :Hollandaca -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Fince -STR_NETWORK_LANG_HUNGARIAN :Bulgarca -STR_NETWORK_LANG_ICELANDIC :İzlandaca -STR_NETWORK_LANG_ITALIAN :İtalyanca -STR_NETWORK_LANG_JAPANESE :Japonca -STR_NETWORK_LANG_KOREAN :Korece -STR_NETWORK_LANG_LITHUANIAN :Litvanyaca -STR_NETWORK_LANG_NORWEGIAN :Norveççe -STR_NETWORK_LANG_POLISH :Lehçe -STR_NETWORK_LANG_PORTUGUESE :Portekizce -STR_NETWORK_LANG_ROMANIAN :Romanca -STR_NETWORK_LANG_RUSSIAN :Rusça -STR_NETWORK_LANG_SLOVAK :Slovakça -STR_NETWORK_LANG_SLOVENIAN :Slovence -STR_NETWORK_LANG_SPANISH :İspanyolca -STR_NETWORK_LANG_SWEDISH :İsveççe -STR_NETWORK_LANG_TURKISH :Türkçe -STR_NETWORK_LANG_UKRAINIAN :Ukraynaca -STR_NETWORK_LANG_AFRIKAANS :Afrikaanca -STR_NETWORK_LANG_CROATIAN :Hırvatça -STR_NETWORK_LANG_CATALAN :Katalanca -STR_NETWORK_LANG_ESTONIAN :Estonyaca -STR_NETWORK_LANG_GALICIAN :Galiçyaca -STR_NETWORK_LANG_GREEK :Yunanca -STR_NETWORK_LANG_LATVIAN :Letonca -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Çok oyunculu oyun lobisi @@ -2090,19 +2048,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Bağlant STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Sunucu korumalı. Parola girin STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Şirket korumalı. Parola girin -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}İstemci listesi # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Oyuncu listesi -STR_NETWORK_COMPANY_LIST_SPECTATE :Gözlemle -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Yeni şirket # Network client list -STR_NETWORK_CLIENTLIST_KICK :At -STR_NETWORK_CLIENTLIST_BAN :Yasakla -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Herkesle konuş -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Şirketle konuş -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Özel mesaj + + STR_NETWORK_SERVER :Sunucu STR_NETWORK_CLIENT :İstemci diff --git a/src/lang/ukrainian.txt b/src/lang/ukrainian.txt index 5b57ddf960..026e990f40 100644 --- a/src/lang/ukrainian.txt +++ b/src/lang/ukrainian.txt @@ -1134,6 +1134,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Прис STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Увімкнутий прапорець дозволить використання грою прискорення апаратного забезпечення. Налаштування запрацює тільки після перезапуску гри STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Налаштування запрацює тільки після перезапуску гри + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Розмір інтерфейсу STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Оберіть розмір елементів інтерфейсу @@ -2112,6 +2113,7 @@ STR_FACE_TIE :Краватк STR_FACE_EARRING :Сережки: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Змінити комір або сережки + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Мережева гра STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Ім'я гравця: @@ -2174,10 +2176,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Назв STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Встановити пароль STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Захистіть вашу гру паролем, якщо не бажаєте загального доступу -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Інтернет -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Вибір між рекламованою (інтернет) і не рекламованою (локальна мережа, LAN) грою -STR_NETWORK_START_SERVER_UNADVERTISED :Ні -STR_NETWORK_START_SERVER_ADVERTISED :Так STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} клієнт{P "" а ів} STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Макс. клієнтів: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Виберіть максимальну кількість клієнтів. Не всі слоти мають бути зайняті @@ -2192,46 +2190,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Інші STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Введіть назву мережевої гри -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Будь-яка -STR_NETWORK_LANG_ENGLISH :Англійська -STR_NETWORK_LANG_GERMAN :Німецька -STR_NETWORK_LANG_FRENCH :Французька -STR_NETWORK_LANG_BRAZILIAN :Бразильська -STR_NETWORK_LANG_BULGARIAN :Болгарська -STR_NETWORK_LANG_CHINESE :Китайська -STR_NETWORK_LANG_CZECH :Чеська -STR_NETWORK_LANG_DANISH :Данська -STR_NETWORK_LANG_DUTCH :Нідерландська -STR_NETWORK_LANG_ESPERANTO :Есперанто -STR_NETWORK_LANG_FINNISH :Фінська -STR_NETWORK_LANG_HUNGARIAN :Угорська -STR_NETWORK_LANG_ICELANDIC :Ісландська -STR_NETWORK_LANG_ITALIAN :Італійська -STR_NETWORK_LANG_JAPANESE :Японська -STR_NETWORK_LANG_KOREAN :Корейська -STR_NETWORK_LANG_LITHUANIAN :Литовська -STR_NETWORK_LANG_NORWEGIAN :Норвезька -STR_NETWORK_LANG_POLISH :Польська -STR_NETWORK_LANG_PORTUGUESE :Португальська -STR_NETWORK_LANG_ROMANIAN :Румунська -STR_NETWORK_LANG_RUSSIAN :Російська -STR_NETWORK_LANG_SLOVAK :Словацька -STR_NETWORK_LANG_SLOVENIAN :Словенська -STR_NETWORK_LANG_SPANISH :Іспанська -STR_NETWORK_LANG_SWEDISH :Шведська -STR_NETWORK_LANG_TURKISH :Турецька -STR_NETWORK_LANG_UKRAINIAN :Українська -STR_NETWORK_LANG_AFRIKAANS :Афрікаанс -STR_NETWORK_LANG_CROATIAN :Хорватська -STR_NETWORK_LANG_CATALAN :Каталонська -STR_NETWORK_LANG_ESTONIAN :Естонська -STR_NETWORK_LANG_GALICIAN :Галісійська -STR_NETWORK_LANG_GREEK :Грецька -STR_NETWORK_LANG_LATVIAN :Латвійська -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Мережева гра - кімната @@ -2279,19 +2237,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Роз' STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Сервер захищено паролем. Введіть пароль STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Компанія захищена паролем. Введіть пароль -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Список клієнтів # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Список клієнтів -STR_NETWORK_COMPANY_LIST_SPECTATE :Спостерігати -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Нова компанія # Network client list -STR_NETWORK_CLIENTLIST_KICK :Відключити гравця -STR_NETWORK_CLIENTLIST_BAN :Бан -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Повідомлення всім -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Повідомлення компанії -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Приватне повідомлення + + STR_NETWORK_SERVER :Сервер STR_NETWORK_CLIENT :Клієнт diff --git a/src/lang/unfinished/urdu.txt b/src/lang/urdu.txt similarity index 98% rename from src/lang/unfinished/urdu.txt rename to src/lang/urdu.txt index fc4fe0191f..330cf32824 100644 --- a/src/lang/unfinished/urdu.txt +++ b/src/lang/urdu.txt @@ -942,6 +942,7 @@ STR_GAME_OPTIONS_RESOLUTION_OTHER :دیگر + STR_GAME_OPTIONS_BASE_GRF :{BLACK}بُنیادی گرافک سیٹ STR_GAME_OPTIONS_BASE_GRF_TOOLTIP :{BLACK}بُنیادی گرافک سیٹ اختیار کریں STR_GAME_OPTIONS_BASE_GRF_STATUS :{RED}{NUM} missing/corrupted file{P "" s} @@ -1481,6 +1482,7 @@ STR_FACE_TIE :ٹائی: STR_FACE_EARRING :بالیاں: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}ٹائی یا بالیاں بدلیں + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}زیادہ کھلاڑی STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}کھلاڑی کا نام: @@ -1553,46 +1555,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}دوسر STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}نیٹ ورک والے کھیل کا نام لکھیں -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :کوئی بھی -STR_NETWORK_LANG_ENGLISH :انگریزی -STR_NETWORK_LANG_GERMAN :جرمن -STR_NETWORK_LANG_FRENCH :فرانسیسی -STR_NETWORK_LANG_BRAZILIAN :برازیلین -STR_NETWORK_LANG_BULGARIAN :بلغارین -STR_NETWORK_LANG_CHINESE :چائینیز -STR_NETWORK_LANG_CZECH :چیک -STR_NETWORK_LANG_DANISH :ڈینیش -STR_NETWORK_LANG_DUTCH :ڈچ -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :فِنش -STR_NETWORK_LANG_HUNGARIAN :ہنگرین -STR_NETWORK_LANG_ICELANDIC :Icelandic -STR_NETWORK_LANG_ITALIAN :اٹالین -STR_NETWORK_LANG_JAPANESE :جاپانی -STR_NETWORK_LANG_KOREAN :کورین -STR_NETWORK_LANG_LITHUANIAN :Lithuanian -STR_NETWORK_LANG_NORWEGIAN :ناورویجین -STR_NETWORK_LANG_POLISH :پولش -STR_NETWORK_LANG_PORTUGUESE :پُرتگیزی -STR_NETWORK_LANG_ROMANIAN :رومانین -STR_NETWORK_LANG_RUSSIAN :رشین -STR_NETWORK_LANG_SLOVAK :Slovak -STR_NETWORK_LANG_SLOVENIAN :Slovenian -STR_NETWORK_LANG_SPANISH :اسپینش -STR_NETWORK_LANG_SWEDISH :سویڈیش -STR_NETWORK_LANG_TURKISH :ترکش -STR_NETWORK_LANG_UKRAINIAN :یوکرانین -STR_NETWORK_LANG_AFRIKAANS :افریقین -STR_NETWORK_LANG_CROATIAN :کروشین -STR_NETWORK_LANG_CATALAN :Catalan -STR_NETWORK_LANG_ESTONIAN :Estonian -STR_NETWORK_LANG_GALICIAN :Galician -STR_NETWORK_LANG_GREEK :گریک -STR_NETWORK_LANG_LATVIAN :Latvian -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}زیادہ کھلاڑیوں والے کھیل کی لابی @@ -1643,15 +1605,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}کمپن # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :{WHITE}کلائینٹس کی فہرست -STR_NETWORK_COMPANY_LIST_SPECTATE :{WHITE}نظارہ کریں -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :{WHITE}نئی کمپنی # Network client list -STR_NETWORK_CLIENTLIST_KICK :ٹھڈا -STR_NETWORK_CLIENTLIST_BAN :پابندی -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :سب سے بات کریں -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :کمپنی سے بات کریں -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :پرائیویٹ پیغام + + STR_NETWORK_SERVER :سرور STR_NETWORK_CLIENT :کلائینٹ diff --git a/src/lang/vietnamese.txt b/src/lang/vietnamese.txt index 27c2a4da1a..20abfaf81c 100644 --- a/src/lang/vietnamese.txt +++ b/src/lang/vietnamese.txt @@ -1006,6 +1006,7 @@ STR_GAME_OPTIONS_VIDEO_ACCELERATION :{BLACK}Tăng t STR_GAME_OPTIONS_VIDEO_ACCELERATION_TOOLTIP :{BLACK}Đánh dấu vào ô này để cho phép OpenTTD thử sử dụng tăng tốc phần cứng. Sẽ có tác dụng sau khi khởi động lại trò chơi STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART :{WHITE}Thiết lập chỉ có tác dụng sau khi khởi động lại trò chơi + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Kích thước giao diện STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Chọn kích thước của các đối tượng trên giao diện @@ -1138,6 +1139,7 @@ STR_CONFIG_SETTING_TREE_CAPTION :{WHITE}Thiết STR_CONFIG_SETTING_FILTER_TITLE :{BLACK}Lọc chuỗi: STR_CONFIG_SETTING_EXPAND_ALL :{BLACK}Mở xuống tất cả STR_CONFIG_SETTING_COLLAPSE_ALL :{BLACK}Đóng lại tất cả +STR_CONFIG_SETTING_RESET_ALL :{BLACK}Thiết lập lại tất cả STR_CONFIG_SETTING_NO_EXPLANATION_AVAILABLE_HELPTEXT :(hiện không có giải thích nào) STR_CONFIG_SETTING_DEFAULT_VALUE :{LTBLUE}Giá trị mặc định: {ORANGE}{STRING} STR_CONFIG_SETTING_TYPE :{LTBLUE}Kiểu thiết lập: {ORANGE}{STRING} @@ -1146,6 +1148,8 @@ STR_CONFIG_SETTING_TYPE_GAME_MENU :Thiết lập t STR_CONFIG_SETTING_TYPE_GAME_INGAME :Thiết lập trò chơi (chứa trong save; chỉ tác động tới ván chơi hiện tại) STR_CONFIG_SETTING_TYPE_COMPANY_MENU :Thiết lập công ty (chứa trong save; chỉ tác động tới các ván chơi mới) STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :Thiết lập công ty (chứa trong save; chỉ tác động tới công ty hiện tại) +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION :{WHITE}Chú Ý! +STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT :{WHITE}Hành động này sẽ thiết lập lại tất cả các thông số về ban đầu.{}Bạn có muốn tiến hành? STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}Phân loại: STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}Kiểu: @@ -1984,6 +1988,7 @@ STR_FACE_TIE :Cà vạt: STR_FACE_EARRING :Bông tai: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Thay đổi cà vạt hoặc bông tai + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Ván Chơi Mạng STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Tên người chơi: @@ -2046,10 +2051,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Tên c STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Đặt mật khẩu STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Bảo vệ game của bạn bằng mật khẩu nếu bạn không muốn người khác vào tùy tiện -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Đã quảng bá -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Lựa chọn ván chơi quảng bá (ra ngoài internet) và không quảng bá (Local Area Network, LAN) -STR_NETWORK_START_SERVER_UNADVERTISED :Không -STR_NETWORK_START_SERVER_ADVERTISED :Có STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} máy trạm STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Số máy trạm tối đa: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Chọn số lượng máy trạm tối đa. Không nhất thiết phải chọn đầy các dòng @@ -2064,46 +2065,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Những STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Nhập tên của ván chơi mạng -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :bất kỳ -STR_NETWORK_LANG_ENGLISH :Tiếng Anh -STR_NETWORK_LANG_GERMAN :Tiếng Đức -STR_NETWORK_LANG_FRENCH :Tiếng Pháp -STR_NETWORK_LANG_BRAZILIAN :Tiếng Brazil -STR_NETWORK_LANG_BULGARIAN :Tiếng Bun-ga-ri -STR_NETWORK_LANG_CHINESE :Tiếng Trung Quốc -STR_NETWORK_LANG_CZECH :Tiếng Séc -STR_NETWORK_LANG_DANISH :Tiếng Đan Mạch -STR_NETWORK_LANG_DUTCH :Tiếng Hà Lan -STR_NETWORK_LANG_ESPERANTO :Tiếng Quốc tế ngữ Esperanto -STR_NETWORK_LANG_FINNISH :Tiếng Phần Lan -STR_NETWORK_LANG_HUNGARIAN :Tiếng Hung-ga-ri -STR_NETWORK_LANG_ICELANDIC :Tiếng Ai-len -STR_NETWORK_LANG_ITALIAN :Tiếng Ý -STR_NETWORK_LANG_JAPANESE :Tiếng Nhật Bản -STR_NETWORK_LANG_KOREAN :Tiếng Hàn Quốc -STR_NETWORK_LANG_LITHUANIAN :Tiếng Lát-vi -STR_NETWORK_LANG_NORWEGIAN :Tiếng Na-uy -STR_NETWORK_LANG_POLISH :Tiếng Ba Lan -STR_NETWORK_LANG_PORTUGUESE :Tiếng Bồ Đào Nha -STR_NETWORK_LANG_ROMANIAN :Tiếng Ru-ma-ni -STR_NETWORK_LANG_RUSSIAN :Tiếng Nga -STR_NETWORK_LANG_SLOVAK :Tiếng Slo-va-kia -STR_NETWORK_LANG_SLOVENIAN :Tiếng Slo-ven-nhi-a -STR_NETWORK_LANG_SPANISH :Tiếng Tây Ban Nha -STR_NETWORK_LANG_SWEDISH :Tiếng Thuỵ Điển -STR_NETWORK_LANG_TURKISH :Tiếng Thổ Nhĩ Kỳ -STR_NETWORK_LANG_UKRAINIAN :Tiếng U-crai-na -STR_NETWORK_LANG_AFRIKAANS :Tiếng Nam Phi -STR_NETWORK_LANG_CROATIAN :Tiếng Croa-ti-a -STR_NETWORK_LANG_CATALAN :Tiếng Catalan -STR_NETWORK_LANG_ESTONIAN :Tiếng Esto-nhi-a -STR_NETWORK_LANG_GALICIAN :Tiếng Galician -STR_NETWORK_LANG_GREEK :Tiếng Hy Lạp -STR_NETWORK_LANG_LATVIAN :Tiếng Lat-via -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Sảnh chơi game nhiều người @@ -2151,19 +2112,13 @@ STR_NETWORK_CONNECTION_DISCONNECT :{BLACK}Ngắt k STR_NETWORK_NEED_GAME_PASSWORD_CAPTION :{WHITE}Server yêu cầu xác thực. Nhập mật khẩu STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Công ty yêu cầu xác thực. Nhập mật khẩu -STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION :{WHITE}Danh sách máy trạm # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Danh sách máy trạm -STR_NETWORK_COMPANY_LIST_SPECTATE :Xem -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Công ty mới # Network client list -STR_NETWORK_CLIENTLIST_KICK :Đá -STR_NETWORK_CLIENTLIST_BAN :Cấm -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Nói với tất cả -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Nói cho công ty -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Thông điệp riêng + + STR_NETWORK_SERVER :Server STR_NETWORK_CLIENT :Máy trạm @@ -2531,7 +2486,7 @@ STR_WATERWAYS_TOOLBAR_BUILD_DOCK_TOOLTIP :{BLACK}Xây c STR_WATERWAYS_TOOLBAR_BUOY_TOOLTIP :{BLACK}Đặt một phao hàng hải như là điểm mốc trên đường đi. Shift+Click để xem chi phí dự tính STR_WATERWAYS_TOOLBAR_BUILD_AQUEDUCT_TOOLTIP :{BLACK}Xây cống. Shift+Click để xem chi phí dự tính STR_WATERWAYS_TOOLBAR_CREATE_LAKE_TOOLTIP :{BLACK}Đặt tên vùng biển.{}Tạo một kênh đào, nếu ấn Ctrl thì giữ xuống tới mực nước biển, không thì sẽ bị ngập nước -STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Đặt sông. +STR_WATERWAYS_TOOLBAR_CREATE_RIVER_TOOLTIP :{BLACK}Đặt sông. Giữ Ctrl để chọn đường chéo # Ship depot construction window STR_DEPOT_BUILD_SHIP_CAPTION :{WHITE}Hướng Xưởng Tàu diff --git a/src/lang/welsh.txt b/src/lang/welsh.txt index 10598af94b..67268b2b11 100644 --- a/src/lang/welsh.txt +++ b/src/lang/welsh.txt @@ -972,6 +972,7 @@ STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}Dewiswch STR_GAME_OPTIONS_RESOLUTION_OTHER :arall + STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Maint rhyngwyneb STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Dewis maint yr elfennau rhyngwyneb i'w defnyddio @@ -1876,6 +1877,7 @@ STR_FACE_TIE :Tei: STR_FACE_EARRING :Clustlws: STR_FACE_TIE_EARRING_TOOLTIP :{BLACK}Newid tei neu glustlws + # Network server list STR_NETWORK_SERVER_LIST_CAPTION :{WHITE}Amlchwaraewr STR_NETWORK_SERVER_LIST_PLAYER_NAME :{BLACK}Enw chwaraewr: @@ -1934,10 +1936,6 @@ STR_NETWORK_START_SERVER_NEW_GAME_NAME_TOOLTIP :{BLACK}Bydd y g STR_NETWORK_START_SERVER_SET_PASSWORD :{BLACK}Gosod cyfrinair STR_NETWORK_START_SERVER_PASSWORD_TOOLTIP :{BLACK}Diogelwch eich gêm â chyfrinair os nad ydych am i fynediad ato fod yn gyhoeddus -STR_NETWORK_START_SERVER_ADVERTISED_LABEL :{BLACK}Hysbys -STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP :{BLACK}Dewis rhwyd gêm a hysbysebir (rhyngrwyd) neu un anhysbys (rhwydwaith leol) -STR_NETWORK_START_SERVER_UNADVERTISED :Na -STR_NETWORK_START_SERVER_ADVERTISED :Ia STR_NETWORK_START_SERVER_CLIENTS_SELECT :{BLACK}{NUM} gwestai STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS :{BLACK}Uchafswm nifer gwesteion: STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Dewiswch uchafswm y gwesteion. Does dim rhaid llanw pob slot @@ -1952,46 +1950,6 @@ STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Rhoi gwy STR_NETWORK_START_SERVER_NEW_GAME_NAME_OSKTITLE :{BLACK}Rhowch enw ar gyfer y gêm rhwydwaith -# Network game languages -############ Leave those lines in this order!! -STR_NETWORK_LANG_ANY :Unrhyw -STR_NETWORK_LANG_ENGLISH :Saesneg -STR_NETWORK_LANG_GERMAN :Almaeneg -STR_NETWORK_LANG_FRENCH :Ffrangeg -STR_NETWORK_LANG_BRAZILIAN :Brasilaidd -STR_NETWORK_LANG_BULGARIAN :Bwlgaraidd -STR_NETWORK_LANG_CHINESE :Tseineeg -STR_NETWORK_LANG_CZECH :Tsiecaidd -STR_NETWORK_LANG_DANISH :Daneg -STR_NETWORK_LANG_DUTCH :Iseldireg -STR_NETWORK_LANG_ESPERANTO :Esperanto -STR_NETWORK_LANG_FINNISH :Ffineg -STR_NETWORK_LANG_HUNGARIAN :Hwngareg -STR_NETWORK_LANG_ICELANDIC :Islandaidd -STR_NETWORK_LANG_ITALIAN :Eidaleg -STR_NETWORK_LANG_JAPANESE :Siapaneaidd -STR_NETWORK_LANG_KOREAN :Coreeg -STR_NETWORK_LANG_LITHUANIAN :Lithiwaneg -STR_NETWORK_LANG_NORWEGIAN :Norwyeg -STR_NETWORK_LANG_POLISH :Pwyleg -STR_NETWORK_LANG_PORTUGUESE :Portiwgaleg -STR_NETWORK_LANG_ROMANIAN :Rwmaneg -STR_NETWORK_LANG_RUSSIAN :Rwsieg -STR_NETWORK_LANG_SLOVAK :Slofaceg -STR_NETWORK_LANG_SLOVENIAN :Slofeneg -STR_NETWORK_LANG_SPANISH :Sbaeneg -STR_NETWORK_LANG_SWEDISH :Swedeg -STR_NETWORK_LANG_TURKISH :Twrceg -STR_NETWORK_LANG_UKRAINIAN :Wcraneg -STR_NETWORK_LANG_AFRIKAANS :Affricâns -STR_NETWORK_LANG_CROATIAN :Croatieg -STR_NETWORK_LANG_CATALAN :Catalaneg -STR_NETWORK_LANG_ESTONIAN :Estoneg -STR_NETWORK_LANG_GALICIAN :Galiseg -STR_NETWORK_LANG_GREEK :Groeg -STR_NETWORK_LANG_LATVIAN :Latfieg -############ End of leave-in-this-order - # Network game lobby STR_NETWORK_GAME_LOBBY_CAPTION :{WHITE}Cyntedd Gemau Amlchwaraewr @@ -2042,15 +2000,10 @@ STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION :{WHITE}Mae'r cw # Network company list added strings STR_NETWORK_COMPANY_LIST_CLIENT_LIST :Rhestr Cleientiaid -STR_NETWORK_COMPANY_LIST_SPECTATE :Gwylio -STR_NETWORK_COMPANY_LIST_NEW_COMPANY :Cwmni newydd # Network client list -STR_NETWORK_CLIENTLIST_KICK :Cicio -STR_NETWORK_CLIENTLIST_BAN :Gwahardd -STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL :Siarad â phawb -STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY :Siarad a'r cwmni -STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Neges breifat + + STR_NETWORK_SERVER :Gweinydd STR_NETWORK_CLIENT :Gwestai diff --git a/src/language.h b/src/language.h index faac595613..9d2499068b 100644 --- a/src/language.h +++ b/src/language.h @@ -58,6 +58,7 @@ struct LanguagePackHeader { char cases[MAX_NUM_CASES][CASE_GENDER_LEN]; ///< the cases used by this translation bool IsValid() const; + bool IsReasonablyFinished() const; /** * Get the index for the given gender. diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp index ca929b82e1..f35a5e6d5a 100644 --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -383,7 +383,8 @@ NWidgetBase *MakeSaturationLegendLinkGraphGUI(int *biggest_index) NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE); for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS); ++i) { NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST); - wid->SetMinimalSize(50, FONT_HEIGHT_SMALL); + wid->SetMinimalSize(50, 0); + wid->SetMinimalTextLines(1, 0, FS_SMALL); wid->SetFill(1, 1); wid->SetResize(0, 0); panel->Add(wid); @@ -403,15 +404,17 @@ NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) row = new NWidgetHorizontal(NC_EQUALSIZE); } NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST); - wid->sizing_type = NWST_STEP; - wid->SetMinimalSize(25, FONT_HEIGHT_SMALL); + wid->sizing_type = NWST_BUTTON; + wid->SetMinimalSize(25, 0); + wid->SetMinimalTextLines(1, 0, FS_SMALL); wid->SetFill(1, 1); wid->SetResize(0, 0); row->Add(wid); } /* Fill up last row */ for (uint i = 0; i < 4 - (NUM_CARGO - 1) % 5; ++i) { - NWidgetSpacer *spc = new NWidgetSpacer(25, FONT_HEIGHT_SMALL); + NWidgetSpacer *spc = new NWidgetSpacer(25, 0); + spc->SetMinimalTextLines(1, 0, FS_SMALL); spc->SetFill(1, 1); spc->SetResize(0, 0); row->Add(spc); diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index caeacd19de..4913b5a357 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -367,6 +367,7 @@ public: static Path *invalid_path; Path(NodeID n, bool source = false); + virtual ~Path() = default; /** Get the node this leg passes. */ inline NodeID GetNode() const { return this->node; } diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt index 9ed598004f..ee2ca6a41c 100644 --- a/src/misc/CMakeLists.txt +++ b/src/misc/CMakeLists.txt @@ -1,7 +1,6 @@ add_files( array.hpp binaryheap.hpp - blob.hpp countedobj.cpp countedptr.hpp dbg_helpers.cpp @@ -11,5 +10,4 @@ add_files( getoptdata.h hashtable.hpp lrucache.hpp - str.hpp ) diff --git a/src/misc/array.hpp b/src/misc/array.hpp index d23fb7a0d9..aea58aba42 100644 --- a/src/misc/array.hpp +++ b/src/misc/array.hpp @@ -11,7 +11,7 @@ #define ARRAY_HPP #include "fixedsizearray.hpp" -#include "str.hpp" +#include "../string_func.h" /** * Flexible array with size limit. Implemented as fixed size @@ -103,14 +103,14 @@ public: */ template void Dump(D &dmp) const { - dmp.WriteLine("capacity = %d", Tcapacity); + dmp.WriteValue("capacity", Tcapacity); uint num_items = Length(); - dmp.WriteLine("num_items = %d", num_items); - CStrA name; + dmp.WriteValue("num_items", num_items); for (uint i = 0; i < num_items; i++) { const T &item = (*this)[i]; - name.Format("item[%d]", i); - dmp.WriteStructT(name.Data(), &item); + char name[32]; + seprintf(name, lastof(name), "item[%d]", i); + dmp.WriteStructT(name, &item); } } }; diff --git a/src/misc/blob.hpp b/src/misc/blob.hpp deleted file mode 100644 index 7784b6af6b..0000000000 --- a/src/misc/blob.hpp +++ /dev/null @@ -1,421 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file blob.hpp Support for storing random binary data. */ - -#ifndef BLOB_HPP -#define BLOB_HPP - -#include "../core/alloc_func.hpp" - -/** - * Base class for simple binary blobs. - * Item is byte. - * The word 'simple' means: - * - no configurable allocator type (always made from heap) - * - no smart deallocation - deallocation must be called from the same - * module (DLL) where the blob was allocated - * - no configurable allocation policy (how big blocks should be allocated) - * - no extra ownership policy (i.e. 'copy on write') when blob is copied - * - no thread synchronization at all - * - * Internal member layout: - * 1. The only class member is pointer to the first item (see union). - * 2. Allocated block contains the blob header (see BlobHeader) followed by the raw byte data. - * Always, when it allocates memory the allocated size is: - * sizeof(BlobHeader) + - * 3. Two 'virtual' members (items and capacity) are stored in the BlobHeader at beginning - * of the allocated block. - * 4. The pointer of the union pobsize_ts behind the header (to the first data byte). - * When memory block is allocated, the sizeof(BlobHeader) it added to it. - * 5. Benefits of this layout: - * - items are accessed in the simplest possible way - just dereferencing the pointer, - * which is good for performance (assuming that data are accessed most often). - * - sizeof(blob) is the same as the size of any other pointer - * 6. Drawbacks of this layout: - * - the fact that a pointer to the allocated block is adjusted by sizeof(BlobHeader) before - * it is stored can lead to several confusions: - * - it is not a common pattern so the implementation code is bit harder to read. - * - valgrind may generate a warning that the allocated block is lost (not accessible). - */ -class ByteBlob { -protected: - /** header of the allocated memory block */ - struct BlobHeader { - size_t items; ///< actual blob size in bytes - size_t capacity; ///< maximum (allocated) size in bytes - }; - - /** type used as class member */ - union { - byte *data; ///< ptr to the first byte of data - BlobHeader *header; ///< ptr just after the BlobHeader holding items and capacity - }; - -private: - /** - * Just to silence an unsilencable GCC 4.4+ warning - * Note: This cannot be 'const' as we do a lot of 'hdrEmpty[0]->items += 0;' and 'hdrEmpty[0]->capacity += 0;' - * after const_casting. - */ - static BlobHeader hdrEmpty[]; - -public: - static const size_t tail_reserve = 4; ///< four extra bytes will be always allocated and zeroed at the end - static const size_t header_size = sizeof(BlobHeader); - - /** default constructor - initializes empty blob */ - inline ByteBlob() - { - InitEmpty(); - } - - /** copy constructor */ - inline ByteBlob(const ByteBlob &src) - { - InitEmpty(); - AppendRaw(src); - } - - /** move constructor - take ownership of blob data */ - inline ByteBlob(BlobHeader * const & src) - { - assert(src != nullptr); - header = src; - *const_cast(&src) = nullptr; - } - - /** destructor */ - inline ~ByteBlob() - { - Free(); - } - -protected: - /** all allocation should happen here */ - static inline BlobHeader *RawAlloc(size_t num_bytes) - { - return (BlobHeader*)MallocT(num_bytes); - } - - /** - * Return header pointer to the static BlobHeader with - * both items and capacity containing zero - */ - static inline BlobHeader *Zero() - { - return const_cast(&ByteBlob::hdrEmpty[1]); - } - - /** simple allocation policy - can be optimized later */ - static inline size_t AllocPolicy(size_t min_alloc) - { - if (min_alloc < (1 << 9)) { - if (min_alloc < (1 << 5)) return (1 << 5); - return (min_alloc < (1 << 7)) ? (1 << 7) : (1 << 9); - } - if (min_alloc < (1 << 15)) { - if (min_alloc < (1 << 11)) return (1 << 11); - return (min_alloc < (1 << 13)) ? (1 << 13) : (1 << 15); - } - if (min_alloc < (1 << 20)) { - if (min_alloc < (1 << 17)) return (1 << 17); - return (min_alloc < (1 << 19)) ? (1 << 19) : (1 << 20); - } - min_alloc = (min_alloc | ((1 << 20) - 1)) + 1; - return min_alloc; - } - - /** all deallocations should happen here */ - static inline void RawFree(BlobHeader *p) - { - /* Just to silence an unsilencable GCC 4.4+ warning. */ - assert(p != ByteBlob::hdrEmpty); - - /* In case GCC warns about the following, see GCC's PR38509 why it is bogus. */ - free(p); - } - - /** initialize the empty blob */ - inline void InitEmpty() - { - header = Zero(); - } - - /** initialize blob by attaching it to the given header followed by data */ - inline void Init(BlobHeader *src) - { - header = &src[1]; - } - - /** blob header accessor - use it rather than using the pointer arithmetic directly - non-const version */ - inline BlobHeader& Hdr() - { - return *(header - 1); - } - - /** blob header accessor - use it rather than using the pointer arithmetic directly - const version */ - inline const BlobHeader& Hdr() const - { - return *(header - 1); - } - - /** return reference to the actual blob size - used when the size needs to be modified */ - inline size_t& LengthRef() - { - return Hdr().items; - } - -public: - /** return true if blob doesn't contain valid data */ - inline bool IsEmpty() const - { - return Length() == 0; - } - - /** return the number of valid data bytes in the blob */ - inline size_t Length() const - { - return Hdr().items; - } - - /** return the current blob capacity in bytes */ - inline size_t Capacity() const - { - return Hdr().capacity; - } - - /** return pointer to the first byte of data - non-const version */ - inline byte *Begin() - { - return data; - } - - /** return pointer to the first byte of data - const version */ - inline const byte *Begin() const - { - return data; - } - - /** invalidate blob's data - doesn't free buffer */ - inline void Clear() - { - LengthRef() = 0; - } - - /** free the blob's memory */ - inline void Free() - { - if (Capacity() > 0) { - RawFree(&Hdr()); - InitEmpty(); - } - } - - /** append new bytes at the end of existing data bytes - reallocates if necessary */ - inline void AppendRaw(const void *p, size_t num_bytes) - { - assert(p != nullptr); - if (num_bytes > 0) { - memcpy(Append(num_bytes), p, num_bytes); - } - } - - /** append bytes from given source blob to the end of existing data bytes - reallocates if necessary */ - inline void AppendRaw(const ByteBlob& src) - { - if (!src.IsEmpty()) { - memcpy(Append(src.Length()), src.Begin(), src.Length()); - } - } - - /** - * Reallocate if there is no free space for num_bytes bytes. - * @return pointer to the new data to be added - */ - inline byte *Prepare(size_t num_bytes) - { - size_t new_size = Length() + num_bytes; - if (new_size > Capacity()) SmartAlloc(new_size); - return data + Length(); - } - - /** - * Increase Length() by num_bytes. - * @return pointer to the new data added - */ - inline byte *Append(size_t num_bytes) - { - byte *pNewData = Prepare(num_bytes); - LengthRef() += num_bytes; - return pNewData; - } - - /** reallocate blob data if needed */ - void SmartAlloc(size_t new_size) - { - if (Capacity() >= new_size) return; - /* calculate minimum block size we need to allocate - * and ask allocation policy for some reasonable block size */ - assert(new_size < SIZE_MAX - header_size - tail_reserve); - new_size = AllocPolicy(header_size + new_size + tail_reserve); - - /* allocate new block and setup header */ - BlobHeader *tmp = RawAlloc(new_size); - tmp->items = Length(); - tmp->capacity = new_size - (header_size + tail_reserve); - - /* copy existing data */ - if (tmp->items != 0) { - memcpy(tmp + 1, data, tmp->items); - } - - /* replace our block with new one */ - if (Capacity() > 0) { - RawFree(&Hdr()); - } - Init(tmp); - } - - /** fixing the four bytes at the end of blob data - useful when blob is used to hold string */ - inline void FixTail() const - { - if (Capacity() > 0) { - byte *p = &data[Length()]; - for (uint i = 0; i < tail_reserve; i++) { - p[i] = 0; - } - } - } -}; - -/** - * Blob - simple dynamic T array. T (template argument) is a placeholder for any type. - * T can be any integral type, pointer, or structure. Using Blob instead of just plain C array - * simplifies the resource management in several ways: - * 1. When adding new item(s) it automatically grows capacity if needed. - * 2. When variable of type Blob comes out of scope it automatically frees the data buffer. - * 3. Takes care about the actual data size (number of used items). - * 4. Dynamically constructs only used items (as opposite of static array which constructs all items) - */ -template -class CBlobT : public ByteBlob { - /* make template arguments public: */ -public: - typedef ByteBlob base; - - static const size_t type_size = sizeof(T); - - struct OnTransfer { - typename base::BlobHeader *header; - - OnTransfer(const OnTransfer& src) : header(src.header) - { - assert(src.header != nullptr); - *const_cast(&src.header) = nullptr; - } - - OnTransfer(CBlobT& src) : header(src.header) - { - src.InitEmpty(); - } - - ~OnTransfer() - { - assert(header == nullptr); - } - }; - - /** Default constructor - makes new Blob ready to accept any data */ - inline CBlobT() - : base() - {} - - /** Take ownership constructor */ - inline CBlobT(const OnTransfer& ot) - : base(ot.header) - {} - - /** Destructor - ensures that allocated memory (if any) is freed */ - inline ~CBlobT() - { - Free(); - } - - /** Check the validity of item index (only in debug mode) */ - inline void CheckIdx(size_t index) const - { - assert(index < Size()); - } - - /** Return pointer to the first data item - non-const version */ - inline T *Data() - { - return (T*)base::Begin(); - } - - /** Return pointer to the first data item - const version */ - inline const T *Data() const - { - return (const T*)base::Begin(); - } - - /** Return pointer to the index-th data item - non-const version */ - inline T *Data(size_t index) - { - CheckIdx(index); - return (Data() + index); - } - - /** Return pointer to the index-th data item - const version */ - inline const T *Data(size_t index) const - { - CheckIdx(index); - return (Data() + index); - } - - /** Return number of items in the Blob */ - inline size_t Size() const - { - return (base::Length() / type_size); - } - - /** Return total number of items that can fit in the Blob without buffer reallocation */ - inline size_t MaxSize() const - { - return (base::Capacity() / type_size); - } - - /** Return number of additional items that can fit in the Blob without buffer reallocation */ - inline size_t GetReserve() const - { - return ((base::Capacity() - base::Length()) / type_size); - } - - /** Grow number of data items in Blob by given number - doesn't construct items */ - inline T *GrowSizeNC(size_t num_items) - { - return (T*)base::Append(num_items * type_size); - } - - /** - * Ensures that given number of items can be added to the end of Blob. Returns pointer to the - * first free (unused) item - */ - inline T *MakeFreeSpace(size_t num_items) - { - return (T*)base::Prepare(num_items * type_size); - } - - inline OnTransfer Transfer() - { - return OnTransfer(*this); - } -}; - - -#endif /* BLOB_HPP */ diff --git a/src/misc/dbg_helpers.cpp b/src/misc/dbg_helpers.cpp index 7d38c7e65a..b197e9a8af 100644 --- a/src/misc/dbg_helpers.cpp +++ b/src/misc/dbg_helpers.cpp @@ -11,6 +11,9 @@ #include "../rail_map.h" #include "dbg_helpers.h" +#include +#include + #include "../safeguards.h" /** Trackdir & TrackdirBits short names. */ @@ -20,19 +23,15 @@ static const char * const trackdir_names[] = { }; /** Return name of given Trackdir. */ -CStrA ValueStr(Trackdir td) +std::string ValueStr(Trackdir td) { - CStrA out; - out.Format("%d (%s)", td, ItemAtT(td, trackdir_names, "UNK", INVALID_TRACKDIR, "INV")); - return out.Transfer(); + return std::to_string(td) + " (" + ItemAtT(td, trackdir_names, "UNK", INVALID_TRACKDIR, "INV") + ")"; } /** Return composed name of given TrackdirBits. */ -CStrA ValueStr(TrackdirBits td_bits) +std::string ValueStr(TrackdirBits td_bits) { - CStrA out; - out.Format("%d (%s)", td_bits, ComposeNameT(td_bits, trackdir_names, "UNK", INVALID_TRACKDIR_BIT, "INV").Data()); - return out.Transfer(); + return std::to_string(td_bits) + " (" + ComposeNameT(td_bits, trackdir_names, "UNK", INVALID_TRACKDIR_BIT, "INV") + ")"; } @@ -42,11 +41,9 @@ static const char * const diagdir_names[] = { }; /** Return name of given DiagDirection. */ -CStrA ValueStr(DiagDirection dd) +std::string ValueStr(DiagDirection dd) { - CStrA out; - out.Format("%d (%s)", dd, ItemAtT(dd, diagdir_names, "UNK", INVALID_DIAGDIR, "INV")); - return out.Transfer(); + return std::to_string(dd) + " (" + ItemAtT(dd, diagdir_names, "UNK", INVALID_DIAGDIR, "INV") + ")"; } @@ -56,20 +53,19 @@ static const char * const signal_type_names[] = { }; /** Return name of given SignalType. */ -CStrA ValueStr(SignalType t) +std::string ValueStr(SignalType t) { - CStrA out; - out.Format("%d (%s)", t, ItemAtT(t, signal_type_names, "UNK")); - return out.Transfer(); + return std::to_string(t) + " (" + ItemAtT(t, signal_type_names, "UNK") + ")"; } /** Translate TileIndex into string. */ -CStrA TileStr(TileIndex tile) +std::string TileStr(TileIndex tile) { - CStrA out; - out.Format("0x%04X (%d, %d)", tile, TileX(tile), TileY(tile)); - return out.Transfer(); + std::stringstream ss; + ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << tile; // 0x%04X + ss << " (" << TileX(tile) << ", " << TileY(tile) << ")"; + return ss.str(); } /** @@ -81,21 +77,21 @@ CStrA TileStr(TileIndex tile) } /** Return structured name of the current class/structure. */ -CStrA DumpTarget::GetCurrentStructName() +std::string DumpTarget::GetCurrentStructName() { - CStrA out; + std::string out; if (!m_cur_struct.empty()) { /* we are inside some named struct, return its name */ out = m_cur_struct.top(); } - return out.Transfer(); + return out; } /** * Find the given instance in our anti-recursion repository. * Return true and set name when object was found. */ -bool DumpTarget::FindKnownName(size_t type_id, const void *ptr, CStrA &name) +bool DumpTarget::FindKnownName(size_t type_id, const void *ptr, std::string &name) { KNOWN_NAMES::const_iterator it = m_known_names.find(KnownStructKey(type_id, ptr)); if (it != m_known_names.end()) { @@ -111,33 +107,29 @@ void DumpTarget::WriteIndent() { int num_spaces = 2 * m_indent; if (num_spaces > 0) { - memset(m_out.GrowSizeNC(num_spaces), ' ', num_spaces); + m_out += std::string(num_spaces, ' '); } } -/** Write a line with indent at the beginning and \ at the end. */ -void DumpTarget::WriteLine(const char *format, ...) +/** Write 'name = value' with indent and new-line. */ +void DumpTarget::WriteValue(const char *name, int value) { WriteIndent(); - va_list args; - va_start(args, format); - m_out.AddFormatL(format, args); - va_end(args); - m_out.AppendStr("\n"); + m_out += std::string(name) + " = " + std::to_string(value) + "\n"; } /** Write 'name = value' with indent and new-line. */ void DumpTarget::WriteValue(const char *name, const char *value_str) { WriteIndent(); - m_out.AddFormat("%s = %s\n", name, value_str); + m_out += std::string(name) + " = " + value_str + "\n"; } /** Write name & TileIndex to the output. */ void DumpTarget::WriteTile(const char *name, TileIndex tile) { WriteIndent(); - m_out.AddFormat("%s = %s\n", name, TileStr(tile).Data()); + m_out += std::string(name) + " = " + TileStr(tile) + "\n"; } /** @@ -146,12 +138,12 @@ void DumpTarget::WriteTile(const char *name, TileIndex tile) void DumpTarget::BeginStruct(size_t type_id, const char *name, const void *ptr) { /* make composite name */ - CStrA cur_name = GetCurrentStructName().Transfer(); - if (cur_name.Size() > 0) { + std::string cur_name = GetCurrentStructName(); + if (cur_name.size() > 0) { /* add name delimiter (we use structured names) */ - cur_name.AppendStr("."); + cur_name += "."; } - cur_name.AppendStr(name); + cur_name += name; /* put the name onto stack (as current struct name) */ m_cur_struct.push(cur_name); @@ -160,7 +152,7 @@ void DumpTarget::BeginStruct(size_t type_id, const char *name, const void *ptr) m_known_names.insert(KNOWN_NAMES::value_type(KnownStructKey(type_id, ptr), cur_name)); WriteIndent(); - m_out.AddFormat("%s = {\n", name); + m_out += std::string(name) + " = {\n"; m_indent++; } @@ -171,11 +163,8 @@ void DumpTarget::EndStruct() { m_indent--; WriteIndent(); - m_out.AddFormat("}\n"); + m_out += "}\n"; /* remove current struct name from the stack */ m_cur_struct.pop(); } - -/** Just to silence an unsilencable GCC 4.4+ warning */ -/* static */ ByteBlob::BlobHeader ByteBlob::hdrEmpty[] = {{0, 0}, {0, 0}}; diff --git a/src/misc/dbg_helpers.h b/src/misc/dbg_helpers.h index 7c9b4c876f..f9d251b8a9 100644 --- a/src/misc/dbg_helpers.h +++ b/src/misc/dbg_helpers.h @@ -12,8 +12,7 @@ #include #include - -#include "str.hpp" +#include #include "../direction_type.h" #include "../signal_type.h" @@ -67,9 +66,9 @@ inline typename ArrayT::item_t ItemAtT(E idx, const T &t, typename ArrayT: * or t_unk when index is out of bounds. */ template -inline CStrA ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const char *name_inv) +inline std::string ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const char *name_inv) { - CStrA out; + std::string out; if (value == val_inv) { out = name_inv; } else if (value == 0) { @@ -77,18 +76,22 @@ inline CStrA ComposeNameT(E value, T &t, const char *t_unk, E val_inv, const cha } else { for (size_t i = 0; i < ArrayT::length; i++) { if ((value & (1 << i)) == 0) continue; - out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), (const char*)t[i]); + out += (!out.empty() ? "+" : ""); + out += t[i]; value &= ~(E)(1 << i); } - if (value != 0) out.AddFormat("%s%s", (out.Size() > 0 ? "+" : ""), t_unk); + if (value != 0) { + out += (!out.empty() ? "+" : ""); + out += t_unk; + } } - return out.Transfer(); + return out; } -CStrA ValueStr(Trackdir td); -CStrA ValueStr(TrackdirBits td_bits); -CStrA ValueStr(DiagDirection dd); -CStrA ValueStr(SignalType t); +std::string ValueStr(Trackdir td); +std::string ValueStr(TrackdirBits td_bits); +std::string ValueStr(DiagDirection dd); +std::string ValueStr(SignalType t); /** Class that represents the dump-into-string target. */ struct DumpTarget { @@ -118,31 +121,31 @@ struct DumpTarget { } }; - typedef std::map KNOWN_NAMES; + typedef std::map KNOWN_NAMES; - CStrA m_out; ///< the output string - int m_indent; ///< current indent/nesting level - std::stack m_cur_struct; ///< here we will track the current structure name - KNOWN_NAMES m_known_names; ///< map of known object instances and their structured names + std::string m_out; ///< the output string + int m_indent; ///< current indent/nesting level + std::stack m_cur_struct; ///< here we will track the current structure name + KNOWN_NAMES m_known_names; ///< map of known object instances and their structured names DumpTarget() : m_indent(0) {} static size_t& LastTypeId(); - CStrA GetCurrentStructName(); - bool FindKnownName(size_t type_id, const void *ptr, CStrA &name); + std::string GetCurrentStructName(); + bool FindKnownName(size_t type_id, const void *ptr, std::string &name); void WriteIndent(); - void CDECL WriteLine(const char *format, ...) WARN_FORMAT(2, 3); + void WriteValue(const char *name, int value); void WriteValue(const char *name, const char *value_str); void WriteTile(const char *name, TileIndex t); /** Dump given enum value (as a number and as named value) */ template void WriteEnumT(const char *name, E e) { - WriteValue(name, ValueStr(e).Data()); + WriteValue(name, ValueStr(e).c_str()); } void BeginStruct(size_t type_id, const char *name, const void *ptr); @@ -155,13 +158,14 @@ struct DumpTarget { if (s == nullptr) { /* No need to dump nullptr struct. */ - WriteLine("%s = ", name); + WriteValue(name, ""); return; } - CStrA known_as; + std::string known_as; if (FindKnownName(type_id, s, known_as)) { /* We already know this one, no need to dump it. */ - WriteLine("%s = known_as.%s", name, known_as.Data()); + std::string known_as_str = std::string("known_as.") + name; + WriteValue(name, known_as_str.c_str()); } else { /* Still unknown, dump it */ BeginStruct(type_id, name, s); diff --git a/src/misc/str.hpp b/src/misc/str.hpp deleted file mode 100644 index 05a79786b8..0000000000 --- a/src/misc/str.hpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file str.hpp String formatting? */ - -#ifndef STR_HPP -#define STR_HPP - -#include -#include -#include "blob.hpp" -#include "../core/math_func.hpp" -#include "../string_func.h" - -/** Blob based case sensitive ANSI/UTF-8 string */ -struct CStrA : public CBlobT -{ - typedef CBlobT base; ///< base class - - /** Create an empty CStrT */ - inline CStrA() - { - } - - /** Copy constructor */ - inline CStrA(const CStrA &src) : base(src) - { - base::FixTail(); - } - - /** Take over ownership constructor */ - inline CStrA(const OnTransfer &ot) - : base(ot) - { - } - - /** Grow the actual buffer and fix the trailing zero at the end. */ - inline char *GrowSizeNC(uint count) - { - char *ret = base::GrowSizeNC(count); - base::FixTail(); - return ret; - } - - /** Append zero-ended C string. */ - inline void AppendStr(const char *str) - { - if (!StrEmpty(str)) { - base::AppendRaw(str, strlen(str)); - base::FixTail(); - } - } - - /** Append another CStrA. */ - inline void Append(const CStrA &src) - { - if (src.Length() > 0) { - base::AppendRaw(src); - base::FixTail(); - } - } - - /** Assignment from C string. */ - inline CStrA &operator=(const char *src) - { - base::Clear(); - AppendStr(src); - return *this; - } - - /** Assignment from another CStrA. */ - inline CStrA &operator=(const CStrA &src) - { - if (&src != this) { - base::Clear(); - base::AppendRaw(src.Data(), src.Size()); - base::FixTail(); - } - return *this; - } - - /** Lower-than operator (to support stl collections) */ - inline bool operator<(const CStrA &other) const - { - return strcmp(base::Data(), other.Data()) < 0; - } - - /** Add formatted string (like vsprintf) at the end of existing contents. */ - int AddFormatL(const char *format, va_list args) WARN_FORMAT(2, 0) - { - size_t addSize = std::max(strlen(format), 16); - addSize += addSize / 2; - int ret; - int err = 0; - for (;;) { - char *buf = MakeFreeSpace(addSize); - ret = vseprintf(buf, buf + base::GetReserve() - 1, format, args); - if (ret >= (int)base::GetReserve()) { - /* Greater return than given count means needed buffer size. */ - addSize = ret + 1; - continue; - } - if (ret >= 0) { - /* success */ - break; - } - err = errno; - if (err != ERANGE && err != ENOENT && err != 0) { - /* some strange failure */ - break; - } - /* small buffer (M$ implementation) */ - addSize *= 2; - } - if (ret > 0) { - GrowSizeNC(ret); - } else { - base::FixTail(); - } - return ret; - } - - /** Add formatted string (like sprintf) at the end of existing contents. */ - int CDECL WARN_FORMAT(2, 3) AddFormat(const char *format, ...) - { - va_list args; - va_start(args, format); - int ret = AddFormatL(format, args); - va_end(args); - return ret; - } - - /** Assign formatted string (like sprintf). */ - int CDECL WARN_FORMAT(2, 3) Format(const char *format, ...) - { - base::Free(); - va_list args; - va_start(args, format); - int ret = AddFormatL(format, args); - va_end(args); - return ret; - } -}; - -#endif /* STR_HPP */ diff --git a/src/misc_gui.cpp b/src/misc_gui.cpp index 09a5949862..e01ca0e456 100644 --- a/src/misc_gui.cpp +++ b/src/misc_gui.cpp @@ -452,7 +452,6 @@ static const char * const _credits[] = { u8" Ingo von Borstel (planetmaker) - General, Support (since 1.1)", u8" Remko Bijker (Rubidium) - Lead coder and way more (since 0.4.5)", u8" Jos\u00e9 Soler (Terkhen) - General coding (since 1.0)", - u8" Leif Linse (Zuu) - AI/Game Script (since 1.2)", u8"", u8"Inactive Developers:", u8" Jean-Fran\u00e7ois Claeys (Belugas) - GUI, NewGRF and more (0.4.5 - 1.0)", @@ -465,6 +464,7 @@ static const char * const _credits[] = { u8" Christoph Mallon (Tron) - Programmer, code correctness police (0.3 - 0.5)", u8" Patric Stout (TrueBrain) - NoAI, NoGo, Network (0.3 - 1.2), sys op (active)", u8" Thijs Marinussen (Yexo) - AI Framework, General (0.6 - 1.3)", + u8" Leif Linse (Zuu) - AI/Game Script (1.2 - 1.6)", u8"", u8"Retired Developers:", u8" Tam\u00e1s Farag\u00f3 (Darkvater) - Ex-Lead coder (0.3 - 0.5)", @@ -504,7 +504,7 @@ struct AboutWindow : public Window { int line_height; ///< The height of a single line static const int num_visible_lines = 19; ///< The number of lines visible simultaneously - static const uint TIMER_INTERVAL = 150; ///< Scrolling interval in ms + static const uint TIMER_INTERVAL = 2100; ///< Scrolling interval, scaled by line text line height. This value chosen to maintain parity: 2100 / FONT_HEIGHT_NORMAL = 150ms GUITimer timer; AboutWindow() : Window(&_about_desc) @@ -512,7 +512,6 @@ struct AboutWindow : public Window { this->InitNested(WN_GAME_OPTIONS_ABOUT); this->text_position = this->GetWidget(WID_A_SCROLLING_TEXT)->pos_y + this->GetWidget(WID_A_SCROLLING_TEXT)->current_y; - this->timer.SetInterval(TIMER_INTERVAL); } void SetStringParameters(int widget) const override @@ -535,6 +534,10 @@ struct AboutWindow : public Window { d.width = std::max(d.width, GetStringBoundingBox(_credits[i]).width); } *size = maxdim(*size, d); + + /* Set scroll interval based on required speed. To keep scrolling smooth, + * the interval is adjusted rather than the distance moved. */ + this->timer.SetInterval(TIMER_INTERVAL / FONT_HEIGHT_NORMAL); } void DrawWidget(const Rect &r, int widget) const override @@ -785,6 +788,12 @@ struct TooltipsWindow : public Window case TCC_RIGHT_CLICK: if (!_right_button_down) delete this; break; case TCC_HOVER: if (!_mouse_hovering) delete this; break; case TCC_NONE: break; + + case TCC_EXIT_VIEWPORT: { + Window *w = FindWindowFromPt(_cursor.pos.x, _cursor.pos.y); + if (w == nullptr || IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y) == nullptr) delete this; + break; + } } } }; @@ -801,7 +810,7 @@ void GuiShowTooltips(Window *parent, StringID str, uint paramcount, const uint64 { DeleteWindowById(WC_TOOLTIPS, 0); - if (str == STR_NULL) return; + if (str == STR_NULL || !_cursor.in_window) return; new TooltipsWindow(parent, str, paramcount, params, close_tooltip); } @@ -1189,12 +1198,9 @@ struct QueryWindow : public Window { this->caption = caption; this->message = message; this->proc = callback; + this->parent = parent; this->InitNested(WN_CONFIRM_POPUP_QUERY); - - this->parent = parent; - this->left = parent->left + (parent->width / 2) - (this->width / 2); - this->top = parent->top + (parent->height / 2) - (this->height / 2); } ~QueryWindow() @@ -1202,6 +1208,14 @@ struct QueryWindow : public Window { if (this->proc != nullptr) this->proc(this->parent, false); } + void FindWindowPlacementAndResize(int def_width, int def_height) override + { + /* Position query window over the calling window, ensuring it's within screen bounds. */ + this->left = Clamp(parent->left + (parent->width / 2) - (this->width / 2), 0, _screen.width - this->width); + this->top = Clamp(parent->top + (parent->height / 2) - (this->height / 2), 0, _screen.height - this->height); + this->SetDirty(); + } + void SetStringParameters(int widget) const override { switch (widget) { @@ -1312,8 +1326,7 @@ void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallback { if (parent == nullptr) parent = FindWindowById(WC_MAIN_WINDOW, 0); - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class != WC_CONFIRM_POPUP_QUERY) continue; const QueryWindow *qw = (const QueryWindow *)w; diff --git a/src/mixer.cpp b/src/mixer.cpp index 90e3951cb0..d892a573c6 100644 --- a/src/mixer.cpp +++ b/src/mixer.cpp @@ -11,6 +11,7 @@ #include #include "core/math_func.hpp" #include "framerate_type.h" +#include "settings_type.h" #include "safeguards.h" #include "mixer.h" @@ -45,7 +46,7 @@ static MxStreamCallback _music_stream = nullptr; * stops overflowing when too many sounds are played at the same time, which * causes an even worse sound quality. */ -static const int MAX_VOLUME = 128 * 128; +static const int MAX_VOLUME = 32767; /** * Perform the rate conversion between the input and output. @@ -60,7 +61,7 @@ static int RateConversion(T *b, int frac_pos) return ((b[0] * ((1 << 16) - frac_pos)) + (b[1] * frac_pos)) >> 16; } -static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples) +static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples, uint8 effect_vol) { if (samples > sc->samples_left) samples = sc->samples_left; sc->samples_left -= samples; @@ -69,8 +70,8 @@ static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples) const int16 *b = (const int16 *)sc->memory + sc->pos; uint32 frac_pos = sc->frac_pos; uint32 frac_speed = sc->frac_speed; - int volume_left = sc->volume_left; - int volume_right = sc->volume_right; + int volume_left = sc->volume_left * effect_vol / 255; + int volume_right = sc->volume_right * effect_vol / 255; if (frac_speed == 0x10000) { /* Special case when frac_speed is 0x10000 */ @@ -96,7 +97,7 @@ static void mix_int16(MixerChannel *sc, int16 *buffer, uint samples) sc->pos = b - (const int16 *)sc->memory; } -static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples) +static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples, uint8 effect_vol) { if (samples > sc->samples_left) samples = sc->samples_left; sc->samples_left -= samples; @@ -105,8 +106,8 @@ static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples) const int8 *b = sc->memory + sc->pos; uint32 frac_pos = sc->frac_pos; uint32 frac_speed = sc->frac_speed; - int volume_left = sc->volume_left; - int volume_right = sc->volume_right; + int volume_left = sc->volume_left * effect_vol / 255; + int volume_right = sc->volume_right * effect_vol / 255; if (frac_speed == 0x10000) { /* Special case when frac_speed is 0x10000 */ @@ -154,13 +155,21 @@ void MxMixSamples(void *buffer, uint samples) /* Fetch music if a sampled stream is available */ if (_music_stream) _music_stream((int16*)buffer, samples); + /* Apply simple x^3 scaling to master effect volume. This increases the + * perceived difference in loudness to better match expectations. effect_vol + * is expected to be in the range 0-127 hence the division by 127 * 127 to + * get back into range. */ + uint8 effect_vol = (_settings_client.music.effect_vol * + _settings_client.music.effect_vol * + _settings_client.music.effect_vol) / (127 * 127); + /* Mix each channel */ for (mc = _channels; mc != endof(_channels); mc++) { if (mc->active) { if (mc->is16bit) { - mix_int16(mc, (int16*)buffer, samples); + mix_int16(mc, (int16*)buffer, samples, effect_vol); } else { - mix_int8_to_int16(mc, (int16*)buffer, samples); + mix_int8_to_int16(mc, (int16*)buffer, samples, effect_vol); } if (mc->samples_left == 0) MxCloseChannel(mc); } diff --git a/src/music/cocoa_m.cpp b/src/music/cocoa_m.cpp index a989cfe769..279e0b38ae 100644 --- a/src/music/cocoa_m.cpp +++ b/src/music/cocoa_m.cpp @@ -134,8 +134,8 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) return; } - const char *os_file = OTTD2FS(filename.c_str()); - CFAutoRelease url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file, strlen(os_file), false)); + std::string os_file = OTTD2FS(filename); + CFAutoRelease url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file.c_str(), os_file.length(), false)); if (MusicSequenceFileLoad(_sequence, url.get(), kMusicSequenceFile_AnyType, 0) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file"); diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index b0e34070c8..619a20d8bf 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -430,7 +430,7 @@ bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length) bool DLSFile::LoadFile(const wchar_t *file) { - DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file)); + DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file).c_str()); FILE *f = _wfopen(file, L"rb"); if (f == nullptr) return false; @@ -881,7 +881,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) if (!dls_file.LoadFile(path)) return "Can't load GM DLS collection"; } } else { - if (!dls_file.LoadFile(OTTD2FS(user_dls))) return "Can't load GM DLS collection"; + if (!dls_file.LoadFile(OTTD2FS(user_dls).c_str())) return "Can't load GM DLS collection"; } /* Get download port and allocate download IDs. */ @@ -1071,7 +1071,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) const char *MusicDriver_DMusic::Start(const StringList &parm) { /* Initialize COM */ - if (FAILED(CoInitializeEx(nullptr, COINITBASE_MULTITHREADED))) return "COM initialization failed"; + if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) return "COM initialization failed"; /* Create the DirectMusic object */ if (FAILED(CoCreateInstance( diff --git a/src/music/fluidsynth.cpp b/src/music/fluidsynth.cpp index 61686a441e..b5cbf46aa1 100644 --- a/src/music/fluidsynth.cpp +++ b/src/music/fluidsynth.cpp @@ -29,7 +29,15 @@ static FMusicDriver_FluidSynth iFMusicDriver_FluidSynth; /** List of sound fonts to try by default. */ static const char *default_sf[] = { - /* Debian/Ubuntu/OpenSUSE preferred */ + /* FluidSynth preferred */ + /* See: https://www.fluidsynth.org/api/settings_synth.html#settings_synth_default-soundfont */ + "/usr/share/soundfonts/default.sf2", + + /* Debian/Ubuntu preferred */ + /* See: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=929185 */ + "/usr/share/sounds/sf3/default-GM.sf3", + + /* OpenSUSE preferred */ "/usr/share/sounds/sf2/FluidR3_GM.sf2", /* RedHat/Fedora/Arch preferred */ @@ -77,12 +85,22 @@ const char *MusicDriver_FluidSynth::Start(const StringList ¶m) /* Load a SoundFont and reset presets (so that new instruments * get used from the SoundFont) */ if (!sfont_name) { - int i; sfont_id = FLUID_FAILED; - for (i = 0; default_sf[i]; i++) { - if (!fluid_is_soundfont(default_sf[i])) continue; - sfont_id = fluid_synth_sfload(_midi.synth, default_sf[i], 1); - if (sfont_id != FLUID_FAILED) break; + + /* Try loading the default soundfont registered with FluidSynth. */ + char *default_soundfont; + fluid_settings_dupstr(_midi.settings, "synth.default-soundfont", &default_soundfont); + if (fluid_is_soundfont(default_soundfont)) { + sfont_id = fluid_synth_sfload(_midi.synth, default_soundfont, 1); + } + + /* If no default soundfont found, try our own list. */ + if (sfont_id == FLUID_FAILED) { + for (int i = 0; default_sf[i]; i++) { + if (!fluid_is_soundfont(default_sf[i])) continue; + sfont_id = fluid_synth_sfload(_midi.synth, default_sf[i], 1); + if (sfont_id != FLUID_FAILED) break; + } } if (sfont_id == FLUID_FAILED) return "Could not open any sound font"; } else { @@ -145,14 +163,21 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song) void MusicDriver_FluidSynth::StopSong() { - std::lock_guard lock{ _midi.synth_mutex }; + { + std::lock_guard lock{ _midi.synth_mutex }; - if (!_midi.player) return; + if (!_midi.player) return; - fluid_player_stop(_midi.player); + fluid_player_stop(_midi.player); + } + + /* The join must be run without lock as the Music rendering needs to be + * running so FluidSynth's internals can actually stop the playing. */ if (fluid_player_join(_midi.player) != FLUID_OK) { DEBUG(driver, 0, "Could not join player"); } + + std::lock_guard lock{ _midi.synth_mutex }; delete_fluid_player(_midi.player); fluid_synth_system_reset(_midi.synth); fluid_synth_all_sounds_off(_midi.synth, -1); diff --git a/src/music/midifile.cpp b/src/music/midifile.cpp index 4bdd3e4e39..dcd2cefd8d 100644 --- a/src/music/midifile.cpp +++ b/src/music/midifile.cpp @@ -1142,7 +1142,7 @@ static void RegisterConsoleMidiCommands() { static bool registered = false; if (!registered) { - IConsoleCmdRegister("dumpsmf", CmdDumpSMF); + IConsole::CmdRegister("dumpsmf", CmdDumpSMF); registered = true; } } diff --git a/src/music_gui.cpp b/src/music_gui.cpp index e82c81c86b..c050311a6a 100644 --- a/src/music_gui.cpp +++ b/src/music_gui.cpp @@ -26,6 +26,7 @@ #include "settings_gui.h" #include "widgets/dropdown_func.h" #include "widgets/dropdown_type.h" +#include "widgets/slider_func.h" #include "widgets/music_widget.h" @@ -683,8 +684,6 @@ static void ShowMusicTrackSelection() } struct MusicWindow : public Window { - static const int slider_width = 3; - MusicWindow(WindowDesc *desc, WindowNumber number) : Window(desc) { this->InitNested(number); @@ -780,27 +779,13 @@ struct MusicWindow : public Window { break; } - case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { - /* Draw a wedge indicating low to high volume level. */ - const int ha = (r.bottom - r.top) / 5; - int wx1 = r.left, wx2 = r.right; - if (_current_text_dir == TD_RTL) std::swap(wx1, wx2); - const uint shadow = _colour_gradient[COLOUR_GREY][3]; - const uint fill = _colour_gradient[COLOUR_GREY][6]; - const uint light = _colour_gradient[COLOUR_GREY][7]; - const std::vector wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} }; - GfxFillPolygon(wedge, fill); - GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light); - GfxDrawLine(wedge[1].x, wedge[1].y, wedge[2].x, wedge[2].y, _current_text_dir == TD_RTL ? shadow : light); - GfxDrawLine(wedge[0].x, wedge[0].y, wedge[1].x, wedge[1].y, shadow); - /* Draw a slider handle indicating current volume level. */ - const int sw = ScaleGUITrad(slider_width); - byte volume = (widget == WID_M_MUSIC_VOL) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; - if (_current_text_dir == TD_RTL) volume = 127 - volume; - const int x = r.left + (volume * (r.right - r.left - sw) / 127); - DrawFrameRect(x, r.top, x + sw, r.bottom, COLOUR_GREY, FR_NONE); + case WID_M_MUSIC_VOL: + DrawVolumeSliderWidget(r, _settings_client.music.music_vol); + break; + + case WID_M_EFFECT_VOL: + DrawVolumeSliderWidget(r, _settings_client.music.effect_vol); break; - } } } @@ -841,19 +826,11 @@ struct MusicWindow : public Window { break; case WID_M_MUSIC_VOL: case WID_M_EFFECT_VOL: { // volume sliders - int x = pt.x - this->GetWidget(widget)->pos_x; - - byte *vol = (widget == WID_M_MUSIC_VOL) ? &_settings_client.music.music_vol : &_settings_client.music.effect_vol; - - byte new_vol = Clamp(x * 127 / (int)this->GetWidget(widget)->current_x, 0, 127); - if (_current_text_dir == TD_RTL) new_vol = 127 - new_vol; - /* Clamp to make sure min and max are properly settable */ - if (new_vol > 124) new_vol = 127; - if (new_vol < 3) new_vol = 0; - if (new_vol != *vol) { - *vol = new_vol; - if (widget == WID_M_MUSIC_VOL) MusicDriver::GetInstance()->SetVolume(new_vol); + byte &vol = (widget == WID_M_MUSIC_VOL) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; + if (ClickVolumeSliderWidget(this->GetWidget(widget)->GetCurrentRect(), pt, vol)) { + if (widget == WID_M_MUSIC_VOL) MusicDriver::GetInstance()->SetVolume(vol); this->SetDirty(); + SetWindowClassesDirty(WC_GAME_OPTIONS); } if (click_count > 0) this->mouse_capture_widget = widget; diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt index 777d15d841..bf713be99c 100644 --- a/src/network/core/CMakeLists.txt +++ b/src/network/core/CMakeLists.txt @@ -4,9 +4,11 @@ add_files( config.h core.cpp core.h - game.h + game_info.cpp + game_info.h host.cpp host.h + os_abstraction.cpp os_abstraction.h packet.cpp packet.h @@ -17,6 +19,7 @@ add_files( tcp_connect.cpp tcp_content.cpp tcp_content.h + tcp_content_type.h tcp_game.cpp tcp_game.h tcp_http.cpp diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 2e00b5b193..d3e373ef76 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -14,6 +14,8 @@ #include "../../safeguards.h" +static const int DEFAULT_CONNECT_TIMEOUT_SECONDS = 3; ///< Allow connect() three seconds to connect. + /** * Get the hostname; in case it wasn't given the * IPv4 dotted representation is given. @@ -99,8 +101,8 @@ void NetworkAddress::GetAddressAsString(char *buffer, const char *last, bool wit */ std::string NetworkAddress::GetAddressAsString(bool with_family) { - /* 6 = for the : and 5 for the decimal port number */ - char buf[NETWORK_HOSTNAME_LENGTH + 6 + 7]; + /* 7 extra are for with_family, which adds " (IPvX)". */ + char buf[NETWORK_HOSTNAME_PORT_LENGTH + 7]; this->GetAddressAsString(buf, lastof(buf), with_family); return buf; } @@ -239,14 +241,25 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * strecpy(this->hostname, fam == AF_INET ? "0.0.0.0" : "::", lastof(this->hostname)); } + static bool _resolve_timeout_error_message_shown = false; + auto start = std::chrono::steady_clock::now(); int e = getaddrinfo(StrEmpty(this->hostname) ? nullptr : this->hostname, port_name, &hints, &ai); + auto end = std::chrono::steady_clock::now(); + std::chrono::seconds duration = std::chrono::duration_cast(end - start); + if (!_resolve_timeout_error_message_shown && duration >= std::chrono::seconds(5)) { + DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s took %i seconds", + this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), (int)duration.count()); + DEBUG(net, 0, " this is likely an issue in the DNS name resolver's configuration causing it to time out"); + _resolve_timeout_error_message_shown = true; + } + if (reset_hostname) strecpy(this->hostname, "", lastof(this->hostname)); if (e != 0) { if (func != ResolveLoopProc) { DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s", - this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e))); + this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str()); } return INVALID_SOCKET; } @@ -300,35 +313,58 @@ static SOCKET ConnectLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); - char address[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address)); + std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, strerror(errno)); + DEBUG(net, 1, "[%s] could not create %s socket: %s", type, family, NetworkError::GetLast().AsString()); return INVALID_SOCKET; } if (!SetNoDelay(sock)) DEBUG(net, 1, "[%s] setting TCP_NODELAY failed", type); + if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); + int err = connect(sock, runp->ai_addr, (int)runp->ai_addrlen); -#ifdef __EMSCRIPTEN__ - /* Emscripten is asynchronous, and as such a connect() is still in - * progress by the time the call returns. */ - if (err != 0 && errno != EINPROGRESS) -#else - if (err != 0) -#endif - { - DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno)); + if (err != 0 && !NetworkError::GetLast().IsConnectInProgress()) { + DEBUG(net, 1, "[%s] could not connect to %s over %s: %s", type, address.c_str(), family, NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } - /* Connection succeeded */ - if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed", type); + fd_set write_fd; + struct timeval tv; - DEBUG(net, 1, "[%s] connected to %s", type, address); + FD_ZERO(&write_fd); + FD_SET(sock, &write_fd); + + /* Wait for connect() to either connect, timeout or fail. */ + tv.tv_usec = 0; + tv.tv_sec = DEFAULT_CONNECT_TIMEOUT_SECONDS; + int n = select(FD_SETSIZE, NULL, &write_fd, NULL, &tv); + if (n < 0) { + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), NetworkError::GetLast().AsString()); + closesocket(sock); + return INVALID_SOCKET; + } + + /* If no fd is selected, the timeout has been reached. */ + if (n == 0) { + DEBUG(net, 1, "[%s] timed out while connecting to %s", type, address.c_str()); + closesocket(sock); + return INVALID_SOCKET; + } + + /* Retrieve last error, if any, on the socket. */ + NetworkError socket_error = GetSocketError(sock); + if (socket_error.HasError()) { + DEBUG(net, 1, "[%s] could not connect to %s: %s", type, address.c_str(), socket_error.AsString()); + closesocket(sock); + return INVALID_SOCKET; + } + + /* Connection succeeded. */ + DEBUG(net, 1, "[%s] connected to %s", type, address.c_str()); return sock; } @@ -353,48 +389,47 @@ static SOCKET ListenLoopProc(addrinfo *runp) { const char *type = NetworkAddress::SocketTypeAsString(runp->ai_socktype); const char *family = NetworkAddress::AddressFamilyAsString(runp->ai_family); - char address[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(address, lastof(address)); + std::string address = NetworkAddress(runp->ai_addr, (int)runp->ai_addrlen).GetAddressAsString(); SOCKET sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock == INVALID_SOCKET) { - DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 0, "[%s] could not create %s socket on port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); return INVALID_SOCKET; } if (runp->ai_socktype == SOCK_STREAM && !SetNoDelay(sock)) { - DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address); + DEBUG(net, 3, "[%s] setting TCP_NODELAY failed for port %s", type, address.c_str()); } int on = 1; /* The (const char*) cast is needed for windows!! */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not set reusable %s sockets for port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); } #ifndef __OS2__ if (runp->ai_family == AF_INET6 && setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) == -1) { - DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address, strerror(errno)); + DEBUG(net, 3, "[%s] could not disable IPv4 over IPv6 on port %s: %s", type, address.c_str(), NetworkError::GetLast().AsString()); } #endif if (bind(sock, runp->ai_addr, (int)runp->ai_addrlen) != 0) { - DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not bind on %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } if (runp->ai_socktype != SOCK_DGRAM && listen(sock, 1) != 0) { - DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address, strerror(errno)); + DEBUG(net, 1, "[%s] could not listen at %s port %s: %s", type, family, address.c_str(), NetworkError::GetLast().AsString()); closesocket(sock); return INVALID_SOCKET; } /* Connection succeeded */ - if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address); + if (!SetNonBlocking(sock)) DEBUG(net, 0, "[%s] setting non-blocking mode failed for %s port %s", type, family, address.c_str()); - DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address); + DEBUG(net, 1, "[%s] listening on %s port %s", type, family, address.c_str()); return sock; } diff --git a/src/network/core/config.h b/src/network/core/config.h index 3488b1ff28..cacc907faf 100644 --- a/src/network/core/config.h +++ b/src/network/core/config.h @@ -30,7 +30,23 @@ static const uint16 NETWORK_DEFAULT_PORT = 3979; ///< The defau static const uint16 NETWORK_ADMIN_PORT = 3977; ///< The default port for admin network static const uint16 NETWORK_DEFAULT_DEBUGLOG_PORT = 3982; ///< The default port debug-log is sent to (TCP) -static const uint16 SEND_MTU = 1460; ///< Number of bytes we can pack in a single packet +static const uint16 UDP_MTU = 1460; ///< Number of bytes we can pack in a single UDP packet +/* + * Technically a TCP packet could become 64kiB, however the high bit is kept so it becomes possible in the future + * to go to (significantly) larger packets if needed. This would entail a strategy such as employed for UTF-8. + * + * Packets up to 32 KiB have the high bit not set: + * 00000000 00000000 0bbbbbbb aaaaaaaa -> aaaaaaaa 0bbbbbbb + * Send_uint16(GB(size, 0, 15) + * + * Packets up to 1 GiB, first uint16 has high bit set so it knows to read a + * next uint16 for the remaining bits of the size. + * 00dddddd cccccccc bbbbbbbb aaaaaaaa -> cccccccc 10dddddd aaaaaaaa bbbbbbbb + * Send_uint16(GB(size, 16, 14) | 0b10 << 14) + * Send_uint16(GB(size, 0, 16)) + */ +static const uint16 TCP_MTU = 32767; ///< Number of bytes we can pack in a single TCP packet +static const uint16 COMPAT_MTU = 1460; ///< Number of bytes we can pack in a single packet for backward compatibility static const byte NETWORK_GAME_ADMIN_VERSION = 1; ///< What version of the admin network do we use? static const byte NETWORK_GAME_INFO_VERSION = 4; ///< What version of game-info do we use? @@ -40,25 +56,24 @@ static const byte NETWORK_MASTER_SERVER_VERSION = 2; ///< What vers static const uint NETWORK_NAME_LENGTH = 80; ///< The maximum length of the server name and map name, in bytes including '\0' static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maximum length of the company name, in bytes including '\0' static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0' +static const uint NETWORK_HOSTNAME_PORT_LENGTH = 80 + 6; ///< The maximum length of the host name + port, in bytes including '\0'. The extra six is ":" + port number (with a max of 65536) static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0' static const uint NETWORK_REVISION_LENGTH = 33; ///< The maximum length of the revision, in bytes including '\0' static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH) static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0' static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0' static const uint NETWORK_RCONCOMMAND_LENGTH = 500; ///< The maximum length of a rconsole command, in bytes including '\0' -static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = SEND_MTU - 3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than SEND_MTU including header (3 bytes) +static const uint NETWORK_GAMESCRIPT_JSON_LENGTH = COMPAT_MTU-3; ///< The maximum length of a gamescript json string, in bytes including '\0'. Must not be longer than COMPAT_MTU including header (3 bytes) static const uint NETWORK_CHAT_LENGTH = 900; ///< The maximum length of a chat message, in bytes including '\0' static const uint NETWORK_GRF_NAME_LENGTH = 80; ///< Maximum length of the name of a GRF /** * Maximum number of GRFs that can be sent. - * This limit is reached when PACKET_UDP_SERVER_RESPONSE reaches the maximum size of SEND_MTU bytes. + * This limit is reached when PACKET_UDP_SERVER_RESPONSE reaches the maximum size of UDP_MTU bytes. */ static const uint NETWORK_MAX_GRF_COUNT = 62; -static const uint NETWORK_NUM_LANGUAGES = 36; ///< Number of known languages (to the network protocol) + 1 for 'any'. - /** * The number of landscapes in OpenTTD. * This number must be equal to NUM_LANDSCAPE, but as this number is used diff --git a/src/network/core/core.cpp b/src/network/core/core.cpp index 0aeb9c65ce..563deae963 100644 --- a/src/network/core/core.cpp +++ b/src/network/core/core.cpp @@ -47,32 +47,3 @@ void NetworkCoreShutdown() WSACleanup(); #endif } - - -/** - * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet - * @param p the packet to write the data to - * @param grf the GRFIdentifier to serialize - */ -void NetworkSocketHandler::SendGRFIdentifier(Packet *p, const GRFIdentifier *grf) -{ - uint j; - p->Send_uint32(grf->grfid); - for (j = 0; j < sizeof(grf->md5sum); j++) { - p->Send_uint8 (grf->md5sum[j]); - } -} - -/** - * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet - * @param p the packet to read the data from - * @param grf the GRFIdentifier to deserialize - */ -void NetworkSocketHandler::ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf) -{ - uint j; - grf->grfid = p->Recv_uint32(); - for (j = 0; j < sizeof(grf->md5sum); j++) { - grf->md5sum[j] = p->Recv_uint8(); - } -} diff --git a/src/network/core/core.h b/src/network/core/core.h index bf83adc72c..aac36080ff 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -71,8 +71,6 @@ public: */ void Reopen() { this->has_quit = false; } - void SendGRFIdentifier(Packet *p, const GRFIdentifier *grf); - void ReceiveGRFIdentifier(Packet *p, GRFIdentifier *grf); void SendCompanyInformation(Packet *p, const struct Company *c, const struct NetworkCompanyStats *stats, uint max_len = NETWORK_COMPANY_NAME_LENGTH); }; diff --git a/src/network/core/game.h b/src/network/core/game.h deleted file mode 100644 index 151ebef284..0000000000 --- a/src/network/core/game.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** - * @file game.h Information about a game that is sent between a - * game server, game client and masterserver. - */ - -#ifndef NETWORK_CORE_GAME_H -#define NETWORK_CORE_GAME_H - -#include "config.h" -#include "../../newgrf_config.h" -#include "../../date_type.h" - -/** - * The game information that is not generated on-the-fly and has to - * be sent to the clients. - */ -struct NetworkServerGameInfo { - char map_name[NETWORK_NAME_LENGTH]; ///< Map which is played ["random" for a randomized map] - byte clients_on; ///< Current count of clients on server -}; - -/** - * The game information that is sent from the server to the clients. - */ -struct NetworkGameInfo : NetworkServerGameInfo { - GRFConfig *grfconfig; ///< List of NewGRF files used - Date start_date; ///< When the game started - Date game_date; ///< Current date - uint16 map_width; ///< Map width - uint16 map_height; ///< Map height - char server_name[NETWORK_NAME_LENGTH]; ///< Server name - char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) - char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) - bool dedicated; ///< Is this a dedicated server? - bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) - bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match - bool use_password; ///< Is this server passworded? - byte game_info_version; ///< Version of the game info - byte server_lang; ///< Language of the server (we should make a nice table for this) - byte clients_max; ///< Max clients allowed on server - byte companies_on; ///< How many started companies do we have - byte companies_max; ///< Max companies allowed on server - byte spectators_on; ///< How many spectators do we have? - byte spectators_max; ///< Max spectators allowed on server - byte map_set; ///< Graphical set -}; - -const char * GetNetworkRevisionString(); - -#endif /* NETWORK_CORE_GAME_H */ diff --git a/src/network/core/game_info.cpp b/src/network/core/game_info.cpp new file mode 100644 index 0000000000..55b5d1749a --- /dev/null +++ b/src/network/core/game_info.cpp @@ -0,0 +1,338 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file game_info.cpp Functions to convert NetworkGameInfo to Packet and back. + */ + +#include "../../stdafx.h" +#include "game_info.h" +#include "../../core/bitmath_func.hpp" +#include "../../company_base.h" +#include "../../date_func.h" +#include "../../debug.h" +#include "../../map_func.h" +#include "../../settings_type.h" +#include "../../string_func.h" +#include "../../rev.h" +#include "../network_func.h" +#include "../network.h" +#include "packet.h" + +#include "../../safeguards.h" + + +/** + * How many hex digits of the git hash to include in network revision string. + * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix. + */ +static const uint GITHASH_SUFFIX_LEN = 12; + +NetworkServerGameInfo _network_game_info; ///< Information about our game. + +/** + * Get the network version string used by this build. + * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes. + */ +const char *GetNetworkRevisionString() +{ + /* This will be allocated on heap and never free'd, but only once so not a "real" leak. */ + static char *network_revision = nullptr; + + if (!network_revision) { + /* Start by taking a chance on the full revision string. */ + network_revision = stredup(_openttd_revision); + /* Ensure it's not longer than the packet buffer length. */ + if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0'; + + /* Tag names are not mangled further. */ + if (_openttd_revision_tagged) { + DEBUG(net, 1, "Network revision name is '%s'", network_revision); + return network_revision; + } + + /* Prepare a prefix of the git hash. + * Size is length + 1 for terminator, +2 for -g prefix. */ + assert(_openttd_revision_modified < 3); + char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-"; + githash_suffix[1] = "gum"[_openttd_revision_modified]; + for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) { + githash_suffix[i] = _openttd_revision_hash[i-2]; + } + + /* Where did the hash start in the original string? + * Overwrite from that position, unless that would go past end of packet buffer length. */ + ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision; + if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix); + /* Replace the git hash in revision string. */ + strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH); + assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than + DEBUG(net, 1, "Network revision name is '%s'", network_revision); + } + + return network_revision; +} + +/** + * Extract the git hash from the revision string. + * @param revstr The revision string (formatted as DATE-BRANCH-GITHASH). + * @return The git has part of the revision. + */ +static const char *ExtractNetworkRevisionHash(const char *revstr) +{ + return strrchr(revstr, '-'); +} + +/** + * Checks whether the given version string is compatible with our version. + * First tries to match the full string, if that fails, attempts to compare just git hashes. + * @param other the version string to compare to + */ +bool IsNetworkCompatibleVersion(const char *other) +{ + if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true; + + /* If this version is tagged, then the revision string must be a complete match, + * since there is no git hash suffix in it. + * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1". */ + if (_openttd_revision_tagged) return false; + + const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); + const char *hash2 = ExtractNetworkRevisionHash(other); + return hash1 != nullptr && hash2 != nullptr && strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0; +} + +/** + * Check if an game entry is compatible with our client. + */ +void CheckGameCompatibility(NetworkGameInfo &ngi) +{ + /* Check if we are allowed on this server based on the revision-check. */ + ngi.version_compatible = IsNetworkCompatibleVersion(ngi.server_revision); + ngi.compatible = ngi.version_compatible; + + /* Check if we have all the GRFs on the client-system too. */ + for (const GRFConfig *c = ngi.grfconfig; c != nullptr; c = c->next) { + if (c->status == GCS_NOT_FOUND) ngi.compatible = false; + } +} + +/** + * Fill a NetworkGameInfo structure with the latest information of the server. + * @param ngi the NetworkGameInfo struct to fill with data. + */ +void FillNetworkGameInfo(NetworkGameInfo &ngi) +{ + /* Update some game_info */ + ngi.clients_on = _network_game_info.clients_on; + ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); + + ngi.use_password = !StrEmpty(_settings_client.network.server_password); + ngi.clients_max = _settings_client.network.max_clients; + ngi.companies_on = (byte)Company::GetNumItems(); + ngi.companies_max = _settings_client.network.max_companies; + ngi.spectators_on = NetworkSpectatorCount(); + ngi.spectators_max = _settings_client.network.max_spectators; + ngi.game_date = _date; + ngi.map_width = MapSizeX(); + ngi.map_height = MapSizeY(); + ngi.map_set = _settings_game.game_creation.landscape; + ngi.dedicated = _network_dedicated; + ngi.grfconfig = _grfconfig; + + strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); + strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision)); +} + +/** + * Function that is called for every GRFConfig that is read when receiving + * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This + * function must set all appropriate fields. This GRF is later appended to + * the grfconfig list of the NetworkGameInfo. + * @param config the GRF to handle. + */ +static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) +{ + /* Find the matching GRF file */ + const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum); + if (f == nullptr) { + /* Don't know the GRF, so mark game incompatible and the (possibly) + * already resolved name for this GRF (another server has sent the + * name of the GRF already */ + config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); + config->status = GCS_NOT_FOUND; + } else { + config->filename = f->filename; + config->name = f->name; + config->info = f->info; + config->url = f->url; + } + SetBit(config->flags, GCF_COPY); +} + +/** + * Serializes the NetworkGameInfo struct to the packet. + * @param p the packet to write the data to. + * @param info the NetworkGameInfo struct to serialize from. + */ +void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info) +{ + p->Send_uint8 (NETWORK_GAME_INFO_VERSION); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + /* Update the documentation in game_info.h on changes + * to the NetworkGameInfo wire-protocol! */ + + /* NETWORK_GAME_INFO_VERSION = 4 */ + { + /* Only send the GRF Identification (GRF_ID and MD5 checksum) of + * the GRFs that are needed, i.e. the ones that the server has + * selected in the NewGRF GUI and not the ones that are used due + * to the fact that they are in [newgrf-static] in openttd.cfg */ + const GRFConfig *c; + uint count = 0; + + /* Count number of GRFs to send information about */ + for (c = info->grfconfig; c != nullptr; c = c->next) { + if (!HasBit(c->flags, GCF_STATIC)) count++; + } + p->Send_uint8 (count); // Send number of GRFs + + /* Send actual GRF Identifications */ + for (c = info->grfconfig; c != nullptr; c = c->next) { + if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident); + } + } + + /* NETWORK_GAME_INFO_VERSION = 3 */ + p->Send_uint32(info->game_date); + p->Send_uint32(info->start_date); + + /* NETWORK_GAME_INFO_VERSION = 2 */ + p->Send_uint8 (info->companies_max); + p->Send_uint8 (info->companies_on); + p->Send_uint8 (info->spectators_max); + + /* NETWORK_GAME_INFO_VERSION = 1 */ + p->Send_string(info->server_name); + p->Send_string(info->server_revision); + p->Send_uint8 (0); // Used to be server-lang. + p->Send_bool (info->use_password); + p->Send_uint8 (info->clients_max); + p->Send_uint8 (info->clients_on); + p->Send_uint8 (info->spectators_on); + p->Send_string(""); // Used to be map-name. + p->Send_uint16(info->map_width); + p->Send_uint16(info->map_height); + p->Send_uint8 (info->map_set); + p->Send_bool (info->dedicated); +} + +/** + * Deserializes the NetworkGameInfo struct from the packet. + * @param p the packet to read the data from. + * @param info the NetworkGameInfo to deserialize into. + */ +void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info) +{ + static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 + + info->game_info_version = p->Recv_uint8(); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + /* Update the documentation in game_info.h on changes + * to the NetworkGameInfo wire-protocol! */ + + switch (info->game_info_version) { + case 4: { + GRFConfig **dst = &info->grfconfig; + uint i; + uint num_grfs = p->Recv_uint8(); + + /* Broken/bad data. It cannot have that many NewGRFs. */ + if (num_grfs > NETWORK_MAX_GRF_COUNT) return; + + for (i = 0; i < num_grfs; i++) { + GRFConfig *c = new GRFConfig(); + DeserializeGRFIdentifier(p, &c->ident); + HandleIncomingNetworkGameInfoGRFConfig(c); + + /* Append GRFConfig to the list */ + *dst = c; + dst = &c->next; + } + FALLTHROUGH; + } + + case 3: + info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); + info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); + FALLTHROUGH; + + case 2: + info->companies_max = p->Recv_uint8 (); + info->companies_on = p->Recv_uint8 (); + info->spectators_max = p->Recv_uint8 (); + FALLTHROUGH; + + case 1: + p->Recv_string(info->server_name, sizeof(info->server_name)); + p->Recv_string(info->server_revision, sizeof(info->server_revision)); + p->Recv_uint8 (); // Used to contain server-lang. + info->use_password = p->Recv_bool (); + info->clients_max = p->Recv_uint8 (); + info->clients_on = p->Recv_uint8 (); + info->spectators_on = p->Recv_uint8 (); + if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier + info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; + info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; + } + while (p->Recv_uint8() != 0) {} // Used to contain the map-name. + info->map_width = p->Recv_uint16(); + info->map_height = p->Recv_uint16(); + info->map_set = p->Recv_uint8 (); + info->dedicated = p->Recv_bool (); + + if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0; + } +} + +/** + * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet + * @param p the packet to write the data to. + * @param grf the GRFIdentifier to serialize. + */ +void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf) +{ + uint j; + p->Send_uint32(grf->grfid); + for (j = 0; j < sizeof(grf->md5sum); j++) { + p->Send_uint8(grf->md5sum[j]); + } +} + +/** + * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet + * @param p the packet to read the data from. + * @param grf the GRFIdentifier to deserialize. + */ +void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf) +{ + uint j; + grf->grfid = p->Recv_uint32(); + for (j = 0; j < sizeof(grf->md5sum); j++) { + grf->md5sum[j] = p->Recv_uint8(); + } +} diff --git a/src/network/core/game_info.h b/src/network/core/game_info.h new file mode 100644 index 0000000000..324c6ea4aa --- /dev/null +++ b/src/network/core/game_info.h @@ -0,0 +1,105 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file game_info.h Convert NetworkGameInfo to Packet and back. + */ + +#ifndef NETWORK_CORE_GAME_INFO_H +#define NETWORK_CORE_GAME_INFO_H + +#include "config.h" +#include "core.h" +#include "../../newgrf_config.h" +#include "../../date_type.h" + +/* + * NetworkGameInfo has several revisions which we still need to support on the + * wire. The table below shows the version and size for each field of the + * serialized NetworkGameInfo. + * + * Version: Bytes: Description: + * all 1 the version of this packet's structure + * + * 4+ 1 number of GRFs attached (n) + * 4+ n * 20 unique identifier for GRF files. Consists of: + * - one 4 byte variable with the GRF ID + * - 16 bytes (sent sequentially) for the MD5 checksum + * of the GRF + * + * 3+ 4 current game date in days since 1-1-0 (DMY) + * 3+ 4 game introduction date in days since 1-1-0 (DMY) + * + * 2+ 1 maximum number of companies allowed on the server + * 2+ 1 number of companies on the server + * 2+ 1 maximum number of spectators allowed on the server + * + * 1+ var string with the name of the server + * 1+ var string with the revision of the server + * 1+ 1 the language run on the server + * (0 = any, 1 = English, 2 = German, 3 = French) + * 1+ 1 whether the server uses a password (0 = no, 1 = yes) + * 1+ 1 maximum number of clients allowed on the server + * 1+ 1 number of clients on the server + * 1+ 1 number of spectators on the server + * 1 & 2 2 current game date in days since 1-1-1920 (DMY) + * 1 & 2 2 game introduction date in days since 1-1-1920 (DMY) + * 1+ var string with the name of the map + * 1+ 2 width of the map in tiles + * 1+ 2 height of the map in tiles + * 1+ 1 type of map: + * (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland) + * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) + */ + +/** + * The game information that is not generated on-the-fly and has to + * be sent to the clients. + */ +struct NetworkServerGameInfo { + byte clients_on; ///< Current count of clients on server +}; + +/** + * The game information that is sent from the server to the clients. + */ +struct NetworkGameInfo : NetworkServerGameInfo { + GRFConfig *grfconfig; ///< List of NewGRF files used + Date start_date; ///< When the game started + Date game_date; ///< Current date + uint16 map_width; ///< Map width + uint16 map_height; ///< Map height + char server_name[NETWORK_NAME_LENGTH]; ///< Server name + char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) + bool dedicated; ///< Is this a dedicated server? + bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) + bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match + bool use_password; ///< Is this server passworded? + byte game_info_version; ///< Version of the game info + byte clients_max; ///< Max clients allowed on server + byte companies_on; ///< How many started companies do we have + byte companies_max; ///< Max companies allowed on server + byte spectators_on; ///< How many spectators do we have? + byte spectators_max; ///< Max spectators allowed on server + byte map_set; ///< Graphical set +}; + +extern NetworkServerGameInfo _network_game_info; + +const char *GetNetworkRevisionString(); +bool IsNetworkCompatibleVersion(const char *other); +void CheckGameCompatibility(NetworkGameInfo &ngi); + +void FillNetworkGameInfo(NetworkGameInfo &ngi); + +void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf); +void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf); + +void DeserializeNetworkGameInfo(Packet *p, NetworkGameInfo *info); +void SerializeNetworkGameInfo(Packet *p, const NetworkGameInfo *info); + +#endif /* NETWORK_CORE_GAME_INFO_H */ diff --git a/src/network/core/os_abstraction.cpp b/src/network/core/os_abstraction.cpp new file mode 100644 index 0000000000..b2d3475d01 --- /dev/null +++ b/src/network/core/os_abstraction.cpp @@ -0,0 +1,174 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file os_abstraction.cpp OS specific implementations of functions of the OS abstraction layer for network stuff. + * + * The general idea is to have simple abstracting functions for things that + * require different implementations for different environments. + * In here the functions, and their documentation, are defined only once + * and the implementation contains the #ifdefs to change the implementation. + * Since Windows is usually different that is usually the first case, after + * that the behaviour is usually Unix/BSD-like with occasional variation. + */ + +#include "stdafx.h" +#include "os_abstraction.h" +#include "../../string_func.h" +#include + +#include "../../safeguards.h" + +/** + * Construct the network error with the given error code. + * @param error The error code. + */ +NetworkError::NetworkError(int error) : error(error) +{ +} + +/** + * Check whether this error describes that the operation would block. + * @return True iff the operation would block. + */ +bool NetworkError::WouldBlock() const +{ +#if defined(_WIN32) + return this->error == WSAEWOULDBLOCK; +#else + /* Usually EWOULDBLOCK and EAGAIN are the same, but sometimes they are not + * and the POSIX.1 specification states that either should be checked. */ + return this->error == EWOULDBLOCK || this->error == EAGAIN; +#endif +} + +/** + * Check whether this error describes a connection reset. + * @return True iff the connection is reset. + */ +bool NetworkError::IsConnectionReset() const +{ +#if defined(_WIN32) + return this->error == WSAECONNRESET; +#else + return this->error == ECONNRESET; +#endif +} + +/** + * Check whether this error describes a connect is in progress. + * @return True iff the connect is already in progress. + */ +bool NetworkError::IsConnectInProgress() const +{ +#if defined(_WIN32) + return this->error == WSAEWOULDBLOCK; +#else + return this->error == EINPROGRESS; +#endif +} + +/** + * Get the string representation of the error message. + * @return The string representation that will get overwritten by next calls. + */ +const char *NetworkError::AsString() const +{ + if (this->message.empty()) { +#if defined(_WIN32) + char buffer[512]; + if (FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, this->error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, sizeof(buffer), NULL) == 0) { + seprintf(buffer, lastof(buffer), "Unknown error %d", this->error); + } + this->message.assign(buffer); +#else + /* Make strerror thread safe by locking access to it. There is a thread safe strerror_r, however + * the non-POSIX variant is available due to defining _GNU_SOURCE meaning it is not portable. + * The problem with the non-POSIX variant is that it does not necessarily fill the buffer with + * the error message but can also return a pointer to a static bit of memory, whereas the POSIX + * variant always fills the buffer. This makes the behaviour too erratic to work with. */ + static std::mutex mutex; + std::lock_guard guard(mutex); + this->message.assign(strerror(this->error)); +#endif + } + return this->message.c_str(); +} + +/** + * Check whether an error was actually set. + * @return True iff an error was set. + */ +bool NetworkError::HasError() const +{ + return this->error != 0; +} + +/** + * Get the last network error. + * @return The network error. + */ +/* static */ NetworkError NetworkError::GetLast() +{ +#if defined(_WIN32) + return NetworkError(WSAGetLastError()); +#elif defined(__OS2__) + return NetworkError(sock_errno()); +#else + return NetworkError(errno); +#endif +} + + +/** + * Try to set the socket into non-blocking mode. + * @param d The socket to set the non-blocking more for. + * @return True if setting the non-blocking mode succeeded, otherwise false. + */ +bool SetNonBlocking(SOCKET d) +{ +#if defined(_WIN32) + u_long nonblocking = 1; + return ioctlsocket(d, FIONBIO, &nonblocking) == 0; +#elif defined __EMSCRIPTEN__ + return true; +#else + int nonblocking = 1; + return ioctl(d, FIONBIO, &nonblocking) == 0; +#endif +} + +/** + * Try to set the socket to not delay sending. + * @param d The socket to disable the delaying for. + * @return True if disabling the delaying succeeded, otherwise false. + */ +bool SetNoDelay(SOCKET d) +{ +#ifdef __EMSCRIPTEN__ + return true; +#else + int flags = 1; + /* The (const char*) cast is needed for windows */ + return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char *)&flags, sizeof(flags)) == 0; +#endif +} + +/** + * Get the error from a socket, if any. + * @param d The socket to get the error from. + * @return The errno on the socket. + */ +NetworkError GetSocketError(SOCKET d) +{ + int err; + socklen_t len = sizeof(err); + getsockopt(d, SOL_SOCKET, SO_ERROR, (char *)&err, &len); + + return NetworkError(err); +} diff --git a/src/network/core/os_abstraction.h b/src/network/core/os_abstraction.h index b2b40639b4..8fab240297 100644 --- a/src/network/core/os_abstraction.h +++ b/src/network/core/os_abstraction.h @@ -14,6 +14,26 @@ #ifndef NETWORK_CORE_OS_ABSTRACTION_H #define NETWORK_CORE_OS_ABSTRACTION_H +/** + * Abstraction of a network error where all implementation details of the + * error codes are encapsulated in this class and the abstraction layer. + */ +class NetworkError { +private: + int error; ///< The underlying error number from errno or WSAGetLastError. + mutable std::string message; ///< The string representation of the error (set on first call to #AsString). +public: + NetworkError(int error); + + bool HasError() const; + bool WouldBlock() const; + bool IsConnectionReset() const; + bool IsConnectInProgress() const; + const char *AsString() const; + + static NetworkError GetLast(); +}; + /* Include standard stuff per OS */ /* Windows stuff */ @@ -23,9 +43,6 @@ #include #include -#define GET_LAST_ERROR() WSAGetLastError() -#undef EWOULDBLOCK -#define EWOULDBLOCK WSAEWOULDBLOCK /* Windows has some different names for some types */ typedef unsigned long in_addr_t; @@ -49,9 +66,7 @@ typedef unsigned long in_addr_t; # endif # define SOCKET int # define INVALID_SOCKET -1 -# define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (errno) /* Need this for FIONREAD on solaris */ # define BSD_COMP @@ -99,9 +114,7 @@ typedef unsigned long in_addr_t; #if defined(__OS2__) # define SOCKET int # define INVALID_SOCKET -1 -# define ioctlsocket ioctl # define closesocket close -# define GET_LAST_ERROR() (sock_errno()) /* Includes needed for OS/2 systems */ # include @@ -173,41 +186,10 @@ static inline socklen_t FixAddrLenForEmscripten(struct sockaddr_storage &address } #endif -/** - * Try to set the socket into non-blocking mode. - * @param d The socket to set the non-blocking more for. - * @return True if setting the non-blocking mode succeeded, otherwise false. - */ -static inline bool SetNonBlocking(SOCKET d) -{ -#ifdef __EMSCRIPTEN__ - return true; -#else -# ifdef _WIN32 - u_long nonblocking = 1; -# else - int nonblocking = 1; -# endif - return ioctlsocket(d, FIONBIO, &nonblocking) == 0; -#endif -} -/** - * Try to set the socket to not delay sending. - * @param d The socket to disable the delaying for. - * @return True if disabling the delaying succeeded, otherwise false. - */ -static inline bool SetNoDelay(SOCKET d) -{ -#ifdef __EMSCRIPTEN__ - return true; -#else - /* XXX should this be done at all? */ - int b = 1; - /* The (const char*) cast is needed for windows */ - return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; -#endif -} +bool SetNonBlocking(SOCKET d); +bool SetNoDelay(SOCKET d); +NetworkError GetSocketError(SOCKET d); /* Make sure these structures have the size we expect them to be */ static_assert(sizeof(in_addr) == 4); ///< IPv4 addresses should be 4 bytes. diff --git a/src/network/core/packet.cpp b/src/network/core/packet.cpp index 94ffcc5584..644490e0fb 100644 --- a/src/network/core/packet.cpp +++ b/src/network/core/packet.cpp @@ -17,44 +17,66 @@ #include "../../safeguards.h" /** - * Create a packet that is used to read from a network socket - * @param cs the socket handler associated with the socket we are reading from + * Create a packet that is used to read from a network socket. + * @param cs The socket handler associated with the socket we are reading from. + * @param limit The maximum size of packets to accept. + * @param initial_read_size The initial amount of data to transfer from the socket into the + * packet. This defaults to just the required bytes to determine the + * packet's size. That default is the wanted for streams such as TCP + * as you do not want to read data of the next packet yet. For UDP + * you need to read the whole packet at once otherwise you might + * loose some the data of the packet, so there you pass the maximum + * size for the packet you expect from the network. */ -Packet::Packet(NetworkSocketHandler *cs) +Packet::Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size) : next(nullptr), pos(0), limit(limit) { assert(cs != nullptr); - this->cs = cs; - this->next = nullptr; - this->pos = 0; // We start reading from here - this->size = 0; - this->buffer = MallocT(SEND_MTU); + this->cs = cs; + this->buffer.resize(initial_read_size); } /** * Creates a packet to send - * @param type of the packet to send + * @param type The type of the packet to send + * @param limit The maximum number of bytes the packet may have. Default is COMPAT_MTU. + * Be careful of compatibility with older clients/servers when changing + * the limit as it might break things if the other side is not expecting + * much larger packets than what they support. */ -Packet::Packet(PacketType type) +Packet::Packet(PacketType type, size_t limit) : next(nullptr), pos(0), limit(limit), cs(nullptr) { - this->cs = nullptr; - this->next = nullptr; - - /* Skip the size so we can write that in before sending the packet */ - this->pos = 0; - this->size = sizeof(PacketSize); - this->buffer = MallocT(SEND_MTU); - this->buffer[this->size++] = type; + /* Allocate space for the the size so we can write that in just before sending the packet. */ + this->Send_uint16(0); + this->Send_uint8(type); } /** - * Free the buffer of this packet. + * Add the given Packet to the end of the queue of packets. + * @param queue The pointer to the begin of the queue. + * @param packet The packet to append to the queue. */ -Packet::~Packet() +/* static */ void Packet::AddToQueue(Packet **queue, Packet *packet) { - free(this->buffer); + while (*queue != nullptr) queue = &(*queue)->next; + *queue = packet; } +/** + * Pop the packet from the begin of the queue and set the + * begin of the queue to the second element in the queue. + * @param queue The pointer to the begin of the queue. + * @return The Packet that used to be a the begin of the queue. + */ +/* static */ Packet *Packet::PopFromQueue(Packet **queue) +{ + Packet *p = *queue; + *queue = p->next; + p->next = nullptr; + return p; +} + + /** * Writes the packet size from the raw packet from packet->size */ @@ -62,10 +84,21 @@ void Packet::PrepareToSend() { assert(this->cs == nullptr && this->next == nullptr); - this->buffer[0] = GB(this->size, 0, 8); - this->buffer[1] = GB(this->size, 8, 8); + this->buffer[0] = GB(this->Size(), 0, 8); + this->buffer[1] = GB(this->Size(), 8, 8); this->pos = 0; // We start reading from here + this->buffer.shrink_to_fit(); +} + +/** + * Is it safe to write to the packet, i.e. didn't we run over the buffer? + * @param bytes_to_write The amount of bytes we want to try to write. + * @return True iff the given amount of bytes can be written to the packet. + */ +bool Packet::CanWriteToPacket(size_t bytes_to_write) +{ + return this->Size() + bytes_to_write < this->limit; } /* @@ -95,8 +128,8 @@ void Packet::Send_bool(bool data) */ void Packet::Send_uint8(uint8 data) { - assert(this->size < SEND_MTU - sizeof(data)); - this->buffer[this->size++] = data; + assert(this->CanWriteToPacket(sizeof(data))); + this->buffer.emplace_back(data); } /** @@ -105,9 +138,9 @@ void Packet::Send_uint8(uint8 data) */ void Packet::Send_uint16(uint16 data) { - assert(this->size < SEND_MTU - sizeof(data)); - this->buffer[this->size++] = GB(data, 0, 8); - this->buffer[this->size++] = GB(data, 8, 8); + assert(this->CanWriteToPacket(sizeof(data))); + this->buffer.emplace_back(GB(data, 0, 8)); + this->buffer.emplace_back(GB(data, 8, 8)); } /** @@ -116,11 +149,11 @@ void Packet::Send_uint16(uint16 data) */ void Packet::Send_uint32(uint32 data) { - assert(this->size < SEND_MTU - sizeof(data)); - this->buffer[this->size++] = GB(data, 0, 8); - this->buffer[this->size++] = GB(data, 8, 8); - this->buffer[this->size++] = GB(data, 16, 8); - this->buffer[this->size++] = GB(data, 24, 8); + assert(this->CanWriteToPacket(sizeof(data))); + this->buffer.emplace_back(GB(data, 0, 8)); + this->buffer.emplace_back(GB(data, 8, 8)); + this->buffer.emplace_back(GB(data, 16, 8)); + this->buffer.emplace_back(GB(data, 24, 8)); } /** @@ -129,15 +162,15 @@ void Packet::Send_uint32(uint32 data) */ void Packet::Send_uint64(uint64 data) { - assert(this->size < SEND_MTU - sizeof(data)); - this->buffer[this->size++] = GB(data, 0, 8); - this->buffer[this->size++] = GB(data, 8, 8); - this->buffer[this->size++] = GB(data, 16, 8); - this->buffer[this->size++] = GB(data, 24, 8); - this->buffer[this->size++] = GB(data, 32, 8); - this->buffer[this->size++] = GB(data, 40, 8); - this->buffer[this->size++] = GB(data, 48, 8); - this->buffer[this->size++] = GB(data, 56, 8); + assert(this->CanWriteToPacket(sizeof(data))); + this->buffer.emplace_back(GB(data, 0, 8)); + this->buffer.emplace_back(GB(data, 8, 8)); + this->buffer.emplace_back(GB(data, 16, 8)); + this->buffer.emplace_back(GB(data, 24, 8)); + this->buffer.emplace_back(GB(data, 32, 8)); + this->buffer.emplace_back(GB(data, 40, 8)); + this->buffer.emplace_back(GB(data, 48, 8)); + this->buffer.emplace_back(GB(data, 56, 8)); } /** @@ -148,11 +181,25 @@ void Packet::Send_uint64(uint64 data) void Packet::Send_string(const char *data) { assert(data != nullptr); - /* The <= *is* valid due to the fact that we are comparing sizes and not the index. */ - assert(this->size + strlen(data) + 1 <= SEND_MTU); - while ((this->buffer[this->size++] = *data++) != '\0') {} + /* Length of the string + 1 for the '\0' termination. */ + assert(this->CanWriteToPacket(strlen(data) + 1)); + while (this->buffer.emplace_back(*data++) != '\0') {} } +/** + * Send as many of the bytes as possible in the packet. This can mean + * that it is possible that not all bytes are sent. To cope with this + * the function returns the amount of bytes that were actually sent. + * @param begin The begin of the buffer to send. + * @param end The end of the buffer to send. + * @return The number of bytes that were added to this packet. + */ +size_t Packet::Send_bytes(const byte *begin, const byte *end) +{ + size_t amount = std::min(end - begin, this->limit - this->Size()); + this->buffer.insert(this->buffer.end(), begin, begin + amount); + return amount; +} /* * Receiving commands @@ -162,18 +209,21 @@ void Packet::Send_string(const char *data) /** - * Is it safe to read from the packet, i.e. didn't we run over the buffer ? - * @param bytes_to_read The amount of bytes we want to try to read. + * Is it safe to read from the packet, i.e. didn't we run over the buffer? + * In case \c close_connection is true, the connection will be closed when one would + * overrun the buffer. When it is false, the connection remains untouched. + * @param bytes_to_read The amount of bytes we want to try to read. + * @param close_connection Whether to close the connection if one cannot read that amount. * @return True if that is safe, otherwise false. */ -bool Packet::CanReadFromPacket(uint bytes_to_read) +bool Packet::CanReadFromPacket(size_t bytes_to_read, bool close_connection) { /* Don't allow reading from a quit client/client who send bad data */ if (this->cs->HasClientQuit()) return false; /* Check if variable is within packet-size */ - if (this->pos + bytes_to_read > this->size) { - this->cs->NetworkSocketHandler::CloseConnection(); + if (this->pos + bytes_to_read > this->Size()) { + if (close_connection) this->cs->NetworkSocketHandler::CloseConnection(); return false; } @@ -181,13 +231,45 @@ bool Packet::CanReadFromPacket(uint bytes_to_read) } /** - * Reads the packet size from the raw packet and stores it in the packet->size + * Check whether the packet, given the position of the "write" pointer, has read + * enough of the packet to contain its size. + * @return True iff there is enough data in the packet to contain the packet's size. */ -void Packet::ReadRawPacketSize() +bool Packet::HasPacketSizeData() const +{ + return this->pos >= sizeof(PacketSize); +} + +/** + * Get the number of bytes in the packet. + * When sending a packet this is the size of the data up to that moment. + * When receiving a packet (before PrepareToRead) this is the allocated size for the data to be read. + * When reading a packet (after PrepareToRead) this is the full size of the packet. + * @return The packet's size. + */ +size_t Packet::Size() const +{ + return this->buffer.size(); +} + +/** + * Reads the packet size from the raw packet and stores it in the packet->size + * @return True iff the packet size seems plausible. + */ +bool Packet::ParsePacketSize() { assert(this->cs != nullptr && this->next == nullptr); - this->size = (PacketSize)this->buffer[0]; - this->size += (PacketSize)this->buffer[1] << 8; + size_t size = (size_t)this->buffer[0]; + size += (size_t)this->buffer[1] << 8; + + /* If the size of the packet is less than the bytes required for the size and type of + * the packet, or more than the allowed limit, then something is wrong with the packet. + * In those cases the packet can generally be regarded as containing garbage data. */ + if (size < sizeof(PacketSize) + sizeof(PacketType) || size > this->limit) return false; + + this->buffer.resize(size); + this->pos = sizeof(PacketSize); + return true; } /** @@ -195,12 +277,20 @@ void Packet::ReadRawPacketSize() */ void Packet::PrepareToRead() { - this->ReadRawPacketSize(); - /* Put the position on the right place */ this->pos = sizeof(PacketSize); } +/** + * Get the \c PacketType from this packet. + * @return The packet type. + */ +PacketType Packet::GetPacketType() const +{ + assert(this->Size() >= sizeof(PacketSize) + sizeof(PacketType)); + return static_cast(buffer[sizeof(PacketSize)]); +} + /** * Read a boolean from the packet. * @return The read data. @@ -218,7 +308,7 @@ uint8 Packet::Recv_uint8() { uint8 n; - if (!this->CanReadFromPacket(sizeof(n))) return 0; + if (!this->CanReadFromPacket(sizeof(n), true)) return 0; n = this->buffer[this->pos++]; return n; @@ -232,7 +322,7 @@ uint16 Packet::Recv_uint16() { uint16 n; - if (!this->CanReadFromPacket(sizeof(n))) return 0; + if (!this->CanReadFromPacket(sizeof(n), true)) return 0; n = (uint16)this->buffer[this->pos++]; n += (uint16)this->buffer[this->pos++] << 8; @@ -247,7 +337,7 @@ uint32 Packet::Recv_uint32() { uint32 n; - if (!this->CanReadFromPacket(sizeof(n))) return 0; + if (!this->CanReadFromPacket(sizeof(n), true)) return 0; n = (uint32)this->buffer[this->pos++]; n += (uint32)this->buffer[this->pos++] << 8; @@ -264,7 +354,7 @@ uint64 Packet::Recv_uint64() { uint64 n; - if (!this->CanReadFromPacket(sizeof(n))) return 0; + if (!this->CanReadFromPacket(sizeof(n), true)) return 0; n = (uint64)this->buffer[this->pos++]; n += (uint64)this->buffer[this->pos++] << 8; @@ -293,16 +383,25 @@ void Packet::Recv_string(char *buffer, size_t size, StringValidationSettings set if (cs->HasClientQuit()) return; pos = this->pos; - while (--size > 0 && pos < this->size && (*buffer++ = this->buffer[pos++]) != '\0') {} + while (--size > 0 && pos < this->Size() && (*buffer++ = this->buffer[pos++]) != '\0') {} - if (size == 0 || pos == this->size) { + if (size == 0 || pos == this->Size()) { *buffer = '\0'; /* If size was sooner to zero then the string in the stream * skip till the \0, so than packet can be read out correctly for the rest */ - while (pos < this->size && this->buffer[pos] != '\0') pos++; + while (pos < this->Size() && this->buffer[pos] != '\0') pos++; pos++; } this->pos = pos; str_validate(bufp, last, settings); } + +/** + * Get the amount of bytes that are still available for the Transfer functions. + * @return The number of bytes that still have to be transfered. + */ +size_t Packet::RemainingBytesToTransfer() const +{ + return this->Size() - this->pos; +} diff --git a/src/network/core/packet.h b/src/network/core/packet.h index c9be4eeb53..bc7bab6c4f 100644 --- a/src/network/core/packet.h +++ b/src/network/core/packet.h @@ -12,9 +12,12 @@ #ifndef NETWORK_CORE_PACKET_H #define NETWORK_CORE_PACKET_H +#include "os_abstraction.h" #include "config.h" #include "core.h" #include "../../string_type.h" +#include +#include typedef uint16 PacketSize; ///< Size of the whole packet. typedef uint8 PacketType; ///< Identifier for the packet @@ -23,10 +26,11 @@ typedef uint8 PacketType; ///< Identifier for the packet * Internal entity of a packet. As everything is sent as a packet, * all network communication will need to call the functions that * populate the packet. - * Every packet can be at most SEND_MTU bytes. Overflowing this - * limit will give an assertion when sending (i.e. writing) the - * packet. Reading past the size of the packet when receiving - * will return all 0 values and "" in case of the string. + * Every packet can be at most a limited number bytes set in the + * constructor. Overflowing this limit will give an assertion when + * sending (i.e. writing) the packet. Reading past the size of the + * packet when receiving will return all 0 values and "" in case of + * the string. * * --- Points of attention --- * - all > 1 byte integral values are written in little endian, @@ -38,49 +42,150 @@ typedef uint8 PacketType; ///< Identifier for the packet * (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0)) */ struct Packet { +private: /** The next packet. Used for queueing packets before sending. */ Packet *next; - /** - * The size of the whole packet for received packets. For packets - * that will be sent, the value is filled in just before the - * actual transmission. - */ - PacketSize size; /** The current read/write position in the packet */ PacketSize pos; - /** The buffer of this packet, of basically variable length up to SEND_MTU. */ - byte *buffer; + /** The buffer of this packet. */ + std::vector buffer; + /** The limit for the packet size. */ + size_t limit; -private: /** Socket we're associated with. */ NetworkSocketHandler *cs; public: - Packet(NetworkSocketHandler *cs); - Packet(PacketType type); - ~Packet(); + Packet(NetworkSocketHandler *cs, size_t limit, size_t initial_read_size = sizeof(PacketSize)); + Packet(PacketType type, size_t limit = COMPAT_MTU); + + static void AddToQueue(Packet **queue, Packet *packet); + static Packet *PopFromQueue(Packet **queue); /* Sending/writing of packets */ void PrepareToSend(); - void Send_bool (bool data); - void Send_uint8 (uint8 data); - void Send_uint16(uint16 data); - void Send_uint32(uint32 data); - void Send_uint64(uint64 data); - void Send_string(const char *data); + bool CanWriteToPacket(size_t bytes_to_write); + void Send_bool (bool data); + void Send_uint8 (uint8 data); + void Send_uint16(uint16 data); + void Send_uint32(uint32 data); + void Send_uint64(uint64 data); + void Send_string(const char *data); + size_t Send_bytes (const byte *begin, const byte *end); /* Reading/receiving of packets */ - void ReadRawPacketSize(); + bool HasPacketSizeData() const; + bool ParsePacketSize(); + size_t Size() const; void PrepareToRead(); + PacketType GetPacketType() const; - bool CanReadFromPacket (uint bytes_to_read); + bool CanReadFromPacket(size_t bytes_to_read, bool close_connection = false); bool Recv_bool (); uint8 Recv_uint8 (); uint16 Recv_uint16(); uint32 Recv_uint32(); uint64 Recv_uint64(); void Recv_string(char *buffer, size_t size, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); + + size_t RemainingBytesToTransfer() const; + + /** + * Transfer data from the packet to the given function. It starts reading at the + * position the last transfer stopped. + * See Packet::TransferIn for more information about transferring data to functions. + * @param transfer_function The function to pass the buffer as second parameter and the + * amount to write as third parameter. It returns the amount that + * was written or -1 upon errors. + * @param limit The maximum amount of bytes to transfer. + * @param destination The first parameter of the transfer function. + * @param args The fourth and further parameters to the transfer function, if any. + * @return The return value of the transfer_function. + */ + template < + typename A = size_t, ///< The type for the amount to be passed, so it can be cast to the right type. + typename F, ///< The type of the function. + typename D, ///< The type of the destination. + typename ... Args> ///< The types of the remaining arguments to the function. + ssize_t TransferOutWithLimit(F transfer_function, size_t limit, D destination, Args&& ... args) + { + size_t amount = std::min(this->RemainingBytesToTransfer(), limit); + if (amount == 0) return 0; + + assert(this->pos < this->buffer.size()); + assert(this->pos + amount <= this->buffer.size()); + /* Making buffer a char means casting a lot in the Recv/Send functions. */ + const char *output_buffer = reinterpret_cast(this->buffer.data() + this->pos); + ssize_t bytes = transfer_function(destination, output_buffer, static_cast(amount), std::forward(args)...); + if (bytes > 0) this->pos += bytes; + return bytes; + } + + /** + * Transfer data from the packet to the given function. It starts reading at the + * position the last transfer stopped. + * See Packet::TransferIn for more information about transferring data to functions. + * @param transfer_function The function to pass the buffer as second parameter and the + * amount to write as third parameter. It returns the amount that + * was written or -1 upon errors. + * @param destination The first parameter of the transfer function. + * @param args The fourth and further parameters to the transfer function, if any. + * @tparam A The type for the amount to be passed, so it can be cast to the right type. + * @tparam F The type of the transfer_function. + * @tparam D The type of the destination. + * @tparam Args The types of the remaining arguments to the function. + * @return The return value of the transfer_function. + */ + template + ssize_t TransferOut(F transfer_function, D destination, Args&& ... args) + { + return TransferOutWithLimit(transfer_function, std::numeric_limits::max(), destination, std::forward(args)...); + } + + /** + * Transfer data from the given function into the packet. It starts writing at the + * position the last transfer stopped. + * + * Examples of functions that can be used to transfer data into a packet are TCP's + * recv and UDP's recvfrom functions. They will directly write their data into the + * packet without an intermediate buffer. + * Examples of functions that can be used to transfer data from a packet are TCP's + * send and UDP's sendto functions. They will directly read the data from the packet's + * buffer without an intermediate buffer. + * These are functions are special in a sense as even though the packet can send or + * receive an amount of data, those functions can say they only processed a smaller + * amount, so special handling is required to keep the position pointers correct. + * Most of these transfer functions are in the form function(source, buffer, amount, ...), + * so the template of this function will assume that as the base parameter order. + * + * This will attempt to write all the remaining bytes into the packet. It updates the + * position based on how many bytes were actually written by the called transfer_function. + * @param transfer_function The function to pass the buffer as second parameter and the + * amount to read as third parameter. It returns the amount that + * was read or -1 upon errors. + * @param source The first parameter of the transfer function. + * @param args The fourth and further parameters to the transfer function, if any. + * @tparam A The type for the amount to be passed, so it can be cast to the right type. + * @tparam F The type of the transfer_function. + * @tparam S The type of the source. + * @tparam Args The types of the remaining arguments to the function. + * @return The return value of the transfer_function. + */ + template + ssize_t TransferIn(F transfer_function, S source, Args&& ... args) + { + size_t amount = this->RemainingBytesToTransfer(); + if (amount == 0) return 0; + + assert(this->pos < this->buffer.size()); + assert(this->pos + amount <= this->buffer.size()); + /* Making buffer a char means casting a lot in the Recv/Send functions. */ + char *input_buffer = reinterpret_cast(this->buffer.data() + this->pos); + ssize_t bytes = transfer_function(source, input_buffer, static_cast(amount), std::forward(args)...); + if (bytes > 0) this->pos += bytes; + return bytes; + } }; #endif /* NETWORK_CORE_PACKET_H */ diff --git a/src/network/core/tcp.cpp b/src/network/core/tcp.cpp index a51913d843..842e1a89b9 100644 --- a/src/network/core/tcp.cpp +++ b/src/network/core/tcp.cpp @@ -42,9 +42,7 @@ NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error) /* Free all pending and partially received packets */ while (this->packet_queue != nullptr) { - Packet *p = this->packet_queue->next; - delete this->packet_queue; - this->packet_queue = p; + delete Packet::PopFromQueue(&this->packet_queue); } delete this->packet_recv; this->packet_recv = nullptr; @@ -60,26 +58,10 @@ NetworkRecvStatus NetworkTCPSocketHandler::CloseConnection(bool error) */ void NetworkTCPSocketHandler::SendPacket(Packet *packet) { - Packet *p; assert(packet != nullptr); packet->PrepareToSend(); - - /* Reallocate the packet as in 99+% of the times we send at most 25 bytes and - * keeping the other 1400+ bytes wastes memory, especially when someone tries - * to do a denial of service attack! */ - packet->buffer = ReallocT(packet->buffer, packet->size); - - /* Locate last packet buffered for the client */ - p = this->packet_queue; - if (p == nullptr) { - /* No packets yet */ - this->packet_queue = packet; - } else { - /* Skip to the last packet */ - while (p->next != nullptr) p = p->next; - p->next = packet; - } + Packet::AddToQueue(&this->packet_queue, packet); } /** @@ -101,15 +83,14 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) if (!this->writable) return SPS_NONE_SENT; if (!this->IsConnected()) return SPS_CLOSED; - p = this->packet_queue; - while (p != nullptr) { - res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 0); + while ((p = this->packet_queue) != nullptr) { + res = p->TransferOut(send, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { /* Something went wrong.. close client! */ if (!closing_down) { - DEBUG(net, 0, "send failed with error %d", err); + DEBUG(net, 0, "send failed with error %s", err.AsString()); this->CloseConnection(); } return SPS_CLOSED; @@ -122,14 +103,10 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down) return SPS_CLOSED; } - p->pos += res; - /* Is this packet sent? */ - if (p->pos == p->size) { + if (p->RemainingBytesToTransfer() == 0) { /* Go to the next packet */ - this->packet_queue = p->next; - delete p; - p = this->packet_queue; + delete Packet::PopFromQueue(&this->packet_queue); } else { return SPS_PARTLY_SENT; } @@ -149,21 +126,20 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() if (!this->IsConnected()) return nullptr; if (this->packet_recv == nullptr) { - this->packet_recv = new Packet(this); + this->packet_recv = new Packet(this, TCP_MTU); } Packet *p = this->packet_recv; /* Read packet size */ - if (p->pos < sizeof(PacketSize)) { - while (p->pos < sizeof(PacketSize)) { - /* Read the size of the packet */ - res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); + if (!p->HasPacketSizeData()) { + while (p->RemainingBytesToTransfer() != 0) { + res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); this->CloseConnection(); return nullptr; } @@ -175,26 +151,23 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() this->CloseConnection(); return nullptr; } - p->pos += res; } - /* Read the packet size from the received packet */ - p->ReadRawPacketSize(); - - if (p->size > SEND_MTU) { + /* Parse the size in the received packet and if not valid, close the connection. */ + if (!p->ParsePacketSize()) { this->CloseConnection(); return nullptr; } } /* Read rest of packet */ - while (p->pos < p->size) { - res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->pos, 0); + while (p->RemainingBytesToTransfer() != 0) { + res = p->TransferIn(recv, this->sock, 0); if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); this->CloseConnection(); return nullptr; } @@ -206,8 +179,6 @@ Packet *NetworkTCPSocketHandler::ReceivePacket() this->CloseConnection(); return nullptr; } - - p->pos += res; } /* Prepare for receiving a new packet */ diff --git a/src/network/core/tcp_admin.h b/src/network/core/tcp_admin.h index dc9753e89f..e5bcefa86f 100644 --- a/src/network/core/tcp_admin.h +++ b/src/network/core/tcp_admin.h @@ -222,7 +222,7 @@ protected: /** * Welcome a connected admin to the game: - * string Name of the Server (e.g. as advertised to master server). + * string Name of the Server. * string OpenTTD version string. * bool Server is dedicated. * string Name of the Map. diff --git a/src/network/core/tcp_content.cpp b/src/network/core/tcp_content.cpp index 6fb3b33794..488be50003 100644 --- a/src/network/core/tcp_content.cpp +++ b/src/network/core/tcp_content.cpp @@ -10,14 +10,12 @@ */ #include "../../stdafx.h" -#ifndef OPENTTD_MSU #include "../../textfile_gui.h" #include "../../newgrf_config.h" #include "../../base_media_base.h" #include "../../ai/ai.hpp" #include "../../game/game.hpp" #include "../../fios.h" -#endif /* OPENTTD_MSU */ #include "tcp_content.h" #include "../../safeguards.h" @@ -92,7 +90,6 @@ bool ContentInfo::IsValid() const return this->state < ContentInfo::INVALID && this->type >= CONTENT_TYPE_BEGIN && this->type < CONTENT_TYPE_END; } -#ifndef OPENTTD_MSU /** * Search a textfile file next to this file in the content list. * @param type The type of the textfile to search for. @@ -139,7 +136,6 @@ const char *ContentInfo::GetTextfile(TextfileType type) const if (tmp == nullptr) return nullptr; return ::GetTextfile(type, GetContentInfoSubDir(this->type), tmp); } -#endif /* OPENTTD_MSU */ void NetworkContentSocketHandler::Close() { @@ -171,9 +167,9 @@ bool NetworkContentSocketHandler::HandlePacket(Packet *p) default: if (this->HasClientQuit()) { - DEBUG(net, 0, "[tcp/content] received invalid packet type %d from %s", type, this->client_addr.GetAddressAsString().c_str()); + DEBUG(net, 0, "[tcp/content] received invalid packet type %d", type); } else { - DEBUG(net, 0, "[tcp/content] received illegal packet from %s", this->client_addr.GetAddressAsString().c_str()); + DEBUG(net, 0, "[tcp/content] received illegal packet"); } return false; } @@ -224,7 +220,7 @@ bool NetworkContentSocketHandler::ReceivePackets() */ bool NetworkContentSocketHandler::ReceiveInvalidPacket(PacketContentType type) { - DEBUG(net, 0, "[tcp/content] received illegal packet type %d from %s", type, this->client_addr.GetAddressAsString().c_str()); + DEBUG(net, 0, "[tcp/content] received illegal packet type %d", type); return false; } @@ -236,7 +232,6 @@ bool NetworkContentSocketHandler::Receive_SERVER_INFO(Packet *p) { return this-> bool NetworkContentSocketHandler::Receive_CLIENT_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_CLIENT_CONTENT); } bool NetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CONTENT_SERVER_CONTENT); } -#ifndef OPENTTD_MSU /** * Helper to get the subdirectory a #ContentInfo is located in. * @param type The type of content. @@ -261,4 +256,3 @@ Subdirectory GetContentInfoSubDir(ContentType type) case CONTENT_TYPE_HEIGHTMAP: return HEIGHTMAP_DIR; } } -#endif /* OPENTTD_MSU */ diff --git a/src/network/core/tcp_content.h b/src/network/core/tcp_content.h index be1cc6e77e..52cae1e0ed 100644 --- a/src/network/core/tcp_content.h +++ b/src/network/core/tcp_content.h @@ -16,86 +16,11 @@ #include "tcp.h" #include "packet.h" #include "../../debug.h" - -/** The values in the enum are important; they are used as database 'keys' */ -enum ContentType { - CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types - CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics - CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF - CONTENT_TYPE_AI = 3, ///< The content consists of an AI - CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library - CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario - CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap - CONTENT_TYPE_BASE_SOUNDS = 7, ///< The content consists of base sounds - CONTENT_TYPE_BASE_MUSIC = 8, ///< The content consists of base music - CONTENT_TYPE_GAME = 9, ///< The content consists of a game script - CONTENT_TYPE_GAME_LIBRARY = 10, ///< The content consists of a GS library - CONTENT_TYPE_END, ///< Helper to mark the end of the types -}; - -/** Enum with all types of TCP content packets. The order MUST not be changed **/ -enum PacketContentType { - PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type - PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs - PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs - PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5 - PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content - PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID - PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID - PACKET_CONTENT_END, ///< Must ALWAYS be on the end of this list!! (period) -}; - -/** Unique identifier for the content. */ -enum ContentID { - INVALID_CONTENT_ID = UINT32_MAX, ///< Sentinel for invalid content. -}; - -/** Container for all important information about a piece of content. */ -struct ContentInfo { - /** The state the content can be in. */ - enum State { - UNSELECTED, ///< The content has not been selected - SELECTED, ///< The content has been manually selected - AUTOSELECTED, ///< The content has been selected as dependency - ALREADY_HERE, ///< The content is already at the client side - DOES_NOT_EXIST, ///< The content does not exist in the content system - INVALID, ///< The content's invalid - }; - - ContentType type; ///< Type of content - ContentID id; ///< Unique (server side) ID for the content - uint32 filesize; ///< Size of the file - char filename[48]; ///< Filename (for the .tar.gz; only valid on download) - char name[32]; ///< Name of the content - char version[16]; ///< Version of the content - char url[96]; ///< URL related to the content - char description[512]; ///< Description of the content - uint32 unique_id; ///< Unique ID; either GRF ID or shortname - byte md5sum[16]; ///< The MD5 checksum - uint8 dependency_count; ///< Number of dependencies - ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids) - uint8 tag_count; ///< Number of tags - char (*tags)[32]; ///< Malloced array of tags (strings) - State state; ///< Whether the content info is selected (for download) - bool upgrade; ///< This item is an upgrade - - ContentInfo(); - ~ContentInfo(); - - void TransferFrom(ContentInfo *other); - - size_t Size() const; - bool IsSelected() const; - bool IsValid() const; -#ifndef OPENTTD_MSU - const char *GetTextfile(TextfileType type) const; -#endif /* OPENTTD_MSU */ -}; +#include "tcp_content_type.h" /** Base socket handler for all Content TCP sockets */ class NetworkContentSocketHandler : public NetworkTCPSocketHandler { protected: - NetworkAddress client_addr; ///< The address we're connected to. void Close() override; bool ReceiveInvalidPacket(PacketContentType type); @@ -193,9 +118,8 @@ public: * @param s the socket we are connected with * @param address IP etc. of the client */ - NetworkContentSocketHandler(SOCKET s = INVALID_SOCKET, const NetworkAddress &address = NetworkAddress()) : - NetworkTCPSocketHandler(s), - client_addr(address) + NetworkContentSocketHandler(SOCKET s = INVALID_SOCKET) : + NetworkTCPSocketHandler(s) { } @@ -205,8 +129,6 @@ public: bool ReceivePackets(); }; -#ifndef OPENTTD_MSU Subdirectory GetContentInfoSubDir(ContentType type); -#endif /* OPENTTD_MSU */ #endif /* NETWORK_CORE_TCP_CONTENT_H */ diff --git a/src/network/core/tcp_content_type.h b/src/network/core/tcp_content_type.h new file mode 100644 index 0000000000..4dc20f46bb --- /dev/null +++ b/src/network/core/tcp_content_type.h @@ -0,0 +1,88 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** + * @file tcp_content_type.h Basic types related to the content on the content server. + */ + +#ifndef NETWORK_CORE_TCP_CONTENT_TYPE_H +#define NETWORK_CORE_TCP_CONTENT_TYPE_H + +/** The values in the enum are important; they are used as database 'keys' */ +enum ContentType { + CONTENT_TYPE_BEGIN = 1, ///< Helper to mark the begin of the types + CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics + CONTENT_TYPE_NEWGRF = 2, ///< The content consists of a NewGRF + CONTENT_TYPE_AI = 3, ///< The content consists of an AI + CONTENT_TYPE_AI_LIBRARY = 4, ///< The content consists of an AI library + CONTENT_TYPE_SCENARIO = 5, ///< The content consists of a scenario + CONTENT_TYPE_HEIGHTMAP = 6, ///< The content consists of a heightmap + CONTENT_TYPE_BASE_SOUNDS = 7, ///< The content consists of base sounds + CONTENT_TYPE_BASE_MUSIC = 8, ///< The content consists of base music + CONTENT_TYPE_GAME = 9, ///< The content consists of a game script + CONTENT_TYPE_GAME_LIBRARY = 10, ///< The content consists of a GS library + CONTENT_TYPE_END, ///< Helper to mark the end of the types +}; + +/** Enum with all types of TCP content packets. The order MUST not be changed **/ +enum PacketContentType { + PACKET_CONTENT_CLIENT_INFO_LIST, ///< Queries the content server for a list of info of a given content type + PACKET_CONTENT_CLIENT_INFO_ID, ///< Queries the content server for information about a list of internal IDs + PACKET_CONTENT_CLIENT_INFO_EXTID, ///< Queries the content server for information about a list of external IDs + PACKET_CONTENT_CLIENT_INFO_EXTID_MD5, ///< Queries the content server for information about a list of external IDs and MD5 + PACKET_CONTENT_SERVER_INFO, ///< Reply of content server with information about content + PACKET_CONTENT_CLIENT_CONTENT, ///< Request a content file given an internal ID + PACKET_CONTENT_SERVER_CONTENT, ///< Reply with the content of the given ID + PACKET_CONTENT_END, ///< Must ALWAYS be on the end of this list!! (period) +}; + +/** Unique identifier for the content. */ +enum ContentID { + INVALID_CONTENT_ID = UINT32_MAX, ///< Sentinel for invalid content. +}; + +/** Container for all important information about a piece of content. */ +struct ContentInfo { + /** The state the content can be in. */ + enum State { + UNSELECTED, ///< The content has not been selected + SELECTED, ///< The content has been manually selected + AUTOSELECTED, ///< The content has been selected as dependency + ALREADY_HERE, ///< The content is already at the client side + DOES_NOT_EXIST, ///< The content does not exist in the content system + INVALID, ///< The content's invalid + }; + + ContentType type; ///< Type of content + ContentID id; ///< Unique (server side) ID for the content + uint32 filesize; ///< Size of the file + char filename[48]; ///< Filename (for the .tar.gz; only valid on download) + char name[32]; ///< Name of the content + char version[16]; ///< Version of the content + char url[96]; ///< URL related to the content + char description[512]; ///< Description of the content + uint32 unique_id; ///< Unique ID; either GRF ID or shortname + byte md5sum[16]; ///< The MD5 checksum + uint8 dependency_count; ///< Number of dependencies + ContentID *dependencies; ///< Malloced array of dependencies (unique server side ids) + uint8 tag_count; ///< Number of tags + char (*tags)[32]; ///< Malloced array of tags (strings) + State state; ///< Whether the content info is selected (for download) + bool upgrade; ///< This item is an upgrade + + ContentInfo(); + ~ContentInfo(); + + void TransferFrom(ContentInfo *other); + + size_t Size() const; + bool IsSelected() const; + bool IsValid() const; + const char *GetTextfile(TextfileType type) const; +}; + +#endif /* NETWORK_CORE_TCP_CONTENT_TYPE_H */ diff --git a/src/network/core/tcp_game.cpp b/src/network/core/tcp_game.cpp index 06e56e2291..eb53db5acd 100644 --- a/src/network/core/tcp_game.cpp +++ b/src/network/core/tcp_game.cpp @@ -71,6 +71,8 @@ NetworkRecvStatus NetworkGameSocketHandler::HandlePacket(Packet *p) case PACKET_SERVER_BANNED: return this->Receive_SERVER_BANNED(p); case PACKET_CLIENT_JOIN: return this->Receive_CLIENT_JOIN(p); case PACKET_SERVER_ERROR: return this->Receive_SERVER_ERROR(p); + case PACKET_CLIENT_GAME_INFO: return this->Receive_CLIENT_GAME_INFO(p); + case PACKET_SERVER_GAME_INFO: return this->Receive_SERVER_GAME_INFO(p); case PACKET_CLIENT_COMPANY_INFO: return this->Receive_CLIENT_COMPANY_INFO(p); case PACKET_SERVER_COMPANY_INFO: return this->Receive_SERVER_COMPANY_INFO(p); case PACKET_SERVER_CLIENT_INFO: return this->Receive_SERVER_CLIENT_INFO(p); @@ -157,6 +159,8 @@ NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_FULL(Packet *p) { ret NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_BANNED(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_BANNED); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_JOIN); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_ERROR); } +NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_GAME_INFO); } +NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_GAME_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_CLIENT_COMPANY_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_COMPANY_INFO); } NetworkRecvStatus NetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Packet *p) { return this->ReceiveInvalidPacket(PACKET_SERVER_CLIENT_INFO); } diff --git a/src/network/core/tcp_game.h b/src/network/core/tcp_game.h index 95b5f8c6c7..5fe9cd465d 100644 --- a/src/network/core/tcp_game.h +++ b/src/network/core/tcp_game.h @@ -24,7 +24,7 @@ */ enum PacketGameType { /* - * These first three pair of packets (thus six in + * These first four pair of packets (thus eight in * total) must remain in this order for backward * and forward compatibility between clients that * are trying to join directly. @@ -42,6 +42,10 @@ enum PacketGameType { PACKET_CLIENT_COMPANY_INFO, ///< Request information about all companies. PACKET_SERVER_COMPANY_INFO, ///< Information about a single company. + /* Packets used to get the game info. */ + PACKET_SERVER_GAME_INFO, ///< Information about the server. + PACKET_CLIENT_GAME_INFO, ///< Request information about the server. + /* * Packets after here assume that the client * and server are running the same version. As @@ -183,6 +187,19 @@ protected: */ virtual NetworkRecvStatus Receive_SERVER_ERROR(Packet *p); + /** + * Request game information. + * @param p The packet that was just received. + */ + virtual NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet *p); + + /** + * Sends information about the game. + * Serialized NetworkGameInfo. See game_info.h for details. + * @param p The packet that was just received. + */ + virtual NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet *p); + /** * Request company information (in detail). * @param p The packet that was just received. diff --git a/src/network/core/tcp_http.cpp b/src/network/core/tcp_http.cpp index be5a2c39a7..4f29df1912 100644 --- a/src/network/core/tcp_http.cpp +++ b/src/network/core/tcp_http.cpp @@ -12,7 +12,8 @@ #include "../../stdafx.h" #include "../../debug.h" #include "../../rev.h" -#include "../network_func.h" +#include "../network_internal.h" +#include "game_info.h" #include "tcp_http.h" @@ -202,13 +203,7 @@ int NetworkHTTPSocketHandler::HandleHeader() *url = '\0'; - /* Fetch the hostname, and possible port number. */ - const char *company = nullptr; - const char *port = nullptr; - ParseConnectionString(&company, &port, hname); - if (company != nullptr) return_error("[tcp/http] invalid hostname"); - - NetworkAddress address(hname, port == nullptr ? 80 : atoi(port)); + NetworkAddress address = ParseConnectionString(hname, 80); /* Restore the URL. */ *url = '/'; @@ -230,10 +225,10 @@ int NetworkHTTPSocketHandler::Receive() for (;;) { ssize_t res = recv(this->sock, (char *)this->recv_buffer + this->recv_pos, lengthof(this->recv_buffer) - this->recv_pos, 0); if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + NetworkError err = NetworkError::GetLast(); + if (!err.WouldBlock()) { + /* Something went wrong... */ + if (!err.IsConnectionReset()) DEBUG(net, 0, "recv failed with error %s", err.AsString()); return -1; } /* Connection would block, so stop for now */ diff --git a/src/network/core/tcp_listen.h b/src/network/core/tcp_listen.h index 1f073aa735..e23ecae707 100644 --- a/src/network/core/tcp_listen.h +++ b/src/network/core/tcp_listen.h @@ -63,8 +63,8 @@ public: DEBUG(net, 1, "[%s] Banned ip tried to join (%s), refused", Tsocket::GetName(), entry.c_str()); - if (send(s, (const char*)p.buffer, p.size, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + if (p.TransferOut(send, s, 0) < 0) { + DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString()); } closesocket(s); break; @@ -80,8 +80,8 @@ public: Packet p(Tfull_packet); p.PrepareToSend(); - if (send(s, (const char*)p.buffer, p.size, 0) < 0) { - DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR()); + if (p.TransferOut(send, s, 0) < 0) { + DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString()); } closesocket(s); @@ -151,7 +151,7 @@ public: if (sockets.size() == 0) { DEBUG(net, 0, "[server] could not start network: could not create listening socket"); - NetworkError(STR_NETWORK_ERROR_SERVER_START); + ShowNetworkError(STR_NETWORK_ERROR_SERVER_START); return false; } diff --git a/src/network/core/udp.cpp b/src/network/core/udp.cpp index aa6d39cbba..e7b99a53e8 100644 --- a/src/network/core/udp.cpp +++ b/src/network/core/udp.cpp @@ -12,6 +12,7 @@ #include "../../stdafx.h" #include "../../date_func.h" #include "../../debug.h" +#include "game_info.h" #include "udp.h" #include "../../safeguards.h" @@ -94,16 +95,16 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a /* Enable broadcast */ unsigned long val = 1; if (setsockopt(s.second, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof(val)) < 0) { - DEBUG(net, 1, "[udp] setting broadcast failed with: %i", GET_LAST_ERROR()); + DEBUG(net, 1, "[udp] setting broadcast failed with: %s", NetworkError::GetLast().AsString()); } } /* Send the buffer */ - int res = sendto(s.second, (const char*)p->buffer, p->size, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); + ssize_t res = p->TransferOut(sendto, s.second, 0, (const struct sockaddr *)send.GetAddress(), send.GetAddressLength()); DEBUG(net, 7, "[udp] sendto(%s)", send.GetAddressAsString().c_str()); /* Check for any errors, but ignore it otherwise */ - if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %i", send.GetAddressAsString().c_str(), GET_LAST_ERROR()); + if (res == -1) DEBUG(net, 1, "[udp] sendto(%s) failed with: %s", send.GetAddressAsString().c_str(), NetworkError::GetLast().AsString()); if (!all) break; } @@ -119,12 +120,13 @@ void NetworkUDPSocketHandler::ReceivePackets() struct sockaddr_storage client_addr; memset(&client_addr, 0, sizeof(client_addr)); - Packet p(this); + /* The limit is UDP_MTU, but also allocate that much as we need to read the whole packet in one go. */ + Packet p(this, UDP_MTU, UDP_MTU); socklen_t client_len = sizeof(client_addr); /* Try to receive anything */ SetNonBlocking(s.second); // Some OSes seem to lose the non-blocking status of the socket - int nbytes = recvfrom(s.second, (char*)p.buffer, SEND_MTU, 0, (struct sockaddr *)&client_addr, &client_len); + ssize_t nbytes = p.TransferIn(recvfrom, s.second, 0, (struct sockaddr *)&client_addr, &client_len); /* Did we get the bytes for the base header of the packet? */ if (nbytes <= 0) break; // No data, i.e. no packet @@ -134,14 +136,14 @@ void NetworkUDPSocketHandler::ReceivePackets() #endif NetworkAddress address(client_addr, client_len); - p.PrepareToRead(); /* If the size does not match the packet must be corrupted. * Otherwise it will be marked as corrupted later on. */ - if (nbytes != p.size) { + if (!p.ParsePacketSize() || (size_t)nbytes != p.Size()) { DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString().c_str()); continue; } + p.PrepareToRead(); /* Handle the packet */ this->HandleUDPPacket(&p, &address); @@ -149,143 +151,6 @@ void NetworkUDPSocketHandler::ReceivePackets() } } - -/** - * Serializes the NetworkGameInfo struct to the packet - * @param p the packet to write the data to - * @param info the NetworkGameInfo struct to serialize - */ -void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info) -{ - p->Send_uint8 (NETWORK_GAME_INFO_VERSION); - - /* - * Please observe the order. - * The parts must be read in the same order as they are sent! - */ - - /* Update the documentation in udp.h on changes - * to the NetworkGameInfo wire-protocol! */ - - /* NETWORK_GAME_INFO_VERSION = 4 */ - { - /* Only send the GRF Identification (GRF_ID and MD5 checksum) of - * the GRFs that are needed, i.e. the ones that the server has - * selected in the NewGRF GUI and not the ones that are used due - * to the fact that they are in [newgrf-static] in openttd.cfg */ - const GRFConfig *c; - uint count = 0; - - /* Count number of GRFs to send information about */ - for (c = info->grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) count++; - } - p->Send_uint8 (count); // Send number of GRFs - - /* Send actual GRF Identifications */ - for (c = info->grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); - } - } - - /* NETWORK_GAME_INFO_VERSION = 3 */ - p->Send_uint32(info->game_date); - p->Send_uint32(info->start_date); - - /* NETWORK_GAME_INFO_VERSION = 2 */ - p->Send_uint8 (info->companies_max); - p->Send_uint8 (info->companies_on); - p->Send_uint8 (info->spectators_max); - - /* NETWORK_GAME_INFO_VERSION = 1 */ - p->Send_string(info->server_name); - p->Send_string(info->server_revision); - p->Send_uint8 (info->server_lang); - p->Send_bool (info->use_password); - p->Send_uint8 (info->clients_max); - p->Send_uint8 (info->clients_on); - p->Send_uint8 (info->spectators_on); - p->Send_string(info->map_name); - p->Send_uint16(info->map_width); - p->Send_uint16(info->map_height); - p->Send_uint8 (info->map_set); - p->Send_bool (info->dedicated); -} - -/** - * Deserializes the NetworkGameInfo struct from the packet - * @param p the packet to read the data from - * @param info the NetworkGameInfo to deserialize into - */ -void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info) -{ - static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11 - - info->game_info_version = p->Recv_uint8(); - - /* - * Please observe the order. - * The parts must be read in the same order as they are sent! - */ - - /* Update the documentation in udp.h on changes - * to the NetworkGameInfo wire-protocol! */ - - switch (info->game_info_version) { - case 4: { - GRFConfig **dst = &info->grfconfig; - uint i; - uint num_grfs = p->Recv_uint8(); - - /* Broken/bad data. It cannot have that many NewGRFs. */ - if (num_grfs > NETWORK_MAX_GRF_COUNT) return; - - for (i = 0; i < num_grfs; i++) { - GRFConfig *c = new GRFConfig(); - this->ReceiveGRFIdentifier(p, &c->ident); - this->HandleIncomingNetworkGameInfoGRFConfig(c); - - /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; - } - FALLTHROUGH; - } - - case 3: - info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); - info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE); - FALLTHROUGH; - - case 2: - info->companies_max = p->Recv_uint8 (); - info->companies_on = p->Recv_uint8 (); - info->spectators_max = p->Recv_uint8 (); - FALLTHROUGH; - - case 1: - p->Recv_string(info->server_name, sizeof(info->server_name)); - p->Recv_string(info->server_revision, sizeof(info->server_revision)); - info->server_lang = p->Recv_uint8 (); - info->use_password = p->Recv_bool (); - info->clients_max = p->Recv_uint8 (); - info->clients_on = p->Recv_uint8 (); - info->spectators_on = p->Recv_uint8 (); - if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier - info->game_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; - info->start_date = p->Recv_uint16() + DAYS_TILL_ORIGINAL_BASE_YEAR; - } - p->Recv_string(info->map_name, sizeof(info->map_name)); - info->map_width = p->Recv_uint16(); - info->map_height = p->Recv_uint16(); - info->map_set = p->Recv_uint8 (); - info->dedicated = p->Recv_bool (); - - if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0; - if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0; - } -} - /** * Handle an incoming packets by sending it to the correct function. * @param p the received packet diff --git a/src/network/core/udp.h b/src/network/core/udp.h index ddbbd4515f..881fb0a612 100644 --- a/src/network/core/udp.h +++ b/src/network/core/udp.h @@ -13,7 +13,6 @@ #define NETWORK_CORE_UDP_H #include "address.h" -#include "game.h" #include "packet.h" /** Enum with all types of UDP packets. The order MUST not be changed **/ @@ -63,40 +62,7 @@ protected: /** * Return of server information to the client. - * This packet has several legacy versions, so we list the version and size of each "field": - * - * Version: Bytes: Description: - * all 1 the version of this packet's structure - * - * 4+ 1 number of GRFs attached (n) - * 4+ n * 20 unique identifier for GRF files. Consists of: - * - one 4 byte variable with the GRF ID - * - 16 bytes (sent sequentially) for the MD5 checksum - * of the GRF - * - * 3+ 4 current game date in days since 1-1-0 (DMY) - * 3+ 4 game introduction date in days since 1-1-0 (DMY) - * - * 2+ 1 maximum number of companies allowed on the server - * 2+ 1 number of companies on the server - * 2+ 1 maximum number of spectators allowed on the server - * - * 1+ var string with the name of the server - * 1+ var string with the revision of the server - * 1+ 1 the language run on the server - * (0 = any, 1 = English, 2 = German, 3 = French) - * 1+ 1 whether the server uses a password (0 = no, 1 = yes) - * 1+ 1 maximum number of clients allowed on the server - * 1+ 1 number of clients on the server - * 1+ 1 number of spectators on the server - * 1 & 2 2 current game date in days since 1-1-1920 (DMY) - * 1 & 2 2 game introduction date in days since 1-1-1920 (DMY) - * 1+ var string with the name of the map - * 1+ 2 width of the map in tiles - * 1+ 2 height of the map in tiles - * 1+ 1 type of map: - * (0 = temperate, 1 = arctic, 2 = desert, 3 = toyland) - * 1+ 1 whether the server is dedicated (0 = no, 1 = yes) + * Serialized NetworkGameInfo. See game_info.h for details. * @param p The received packet. * @param client_addr The origin of the packet. */ @@ -217,15 +183,6 @@ protected: virtual void Receive_MASTER_SESSION_KEY(Packet *p, NetworkAddress *client_addr); void HandleUDPPacket(Packet *p, NetworkAddress *client_addr); - - /** - * Function that is called for every GRFConfig that is read when receiving - * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This - * function must set all appropriate fields. This GRF is later appended to - * the grfconfig list of the NetworkGameInfo. - * @param config the GRF to handle - */ - virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); } public: NetworkUDPSocketHandler(NetworkAddressList *bind = nullptr); @@ -237,9 +194,6 @@ public: void SendPacket(Packet *p, NetworkAddress *recv, bool all = false, bool broadcast = false); void ReceivePackets(); - - void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info); - void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info); }; #endif /* NETWORK_CORE_UDP_H */ diff --git a/src/network/network.cpp b/src/network/network.cpp index 1d5563c3d9..c00a3650fb 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -54,7 +54,6 @@ bool _network_server; ///< network-server is active bool _network_available; ///< is network mode available? bool _network_dedicated; ///< are we a dedicated server? bool _is_network_server; ///< Does this client wants to be a network-server? -NetworkServerGameInfo _network_game_info; ///< Information about our game. NetworkCompanyState *_network_company_states = nullptr; ///< Statistics about some companies. ClientID _network_own_client_id; ///< Our client identifier. ClientID _redirect_console_to_client; ///< If not invalid, redirect the console output to a client. @@ -74,19 +73,12 @@ uint32 _sync_seed_2; ///< Second part of the seed. #endif uint32 _sync_frame; ///< The frame to perform the sync check. bool _network_first_time; ///< Whether we have finished joining or not. -bool _network_udp_server; ///< Is the UDP server started? -uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts. -uint8 _network_advertise_retries; ///< The number of advertisement retries we did. CompanyMask _network_company_passworded; ///< Bitmask of the password status of all companies. /* Check whether NETWORK_NUM_LANDSCAPES is still in sync with NUM_LANDSCAPE */ static_assert((int)NETWORK_NUM_LANDSCAPES == (int)NUM_LANDSCAPE); static_assert((int)NETWORK_COMPANY_NAME_LENGTH == MAX_LENGTH_COMPANY_NAME_CHARS * MAX_CHAR_LENGTH); -extern NetworkUDPSocketHandler *_udp_client_socket; ///< udp client socket -extern NetworkUDPSocketHandler *_udp_server_socket; ///< udp server socket -extern NetworkUDPSocketHandler *_udp_master_socket; ///< udp master socket - /** The amount of clients connected */ byte _network_clients_connected = 0; @@ -184,12 +176,15 @@ const char *GenerateCompanyPasswordHash(const char *password, const char *passwo if (StrEmpty(password)) return password; char salted_password[NETWORK_SERVER_ID_LENGTH]; + size_t password_length = strlen(password); + size_t password_server_id_length = strlen(password_server_id); - memset(salted_password, 0, sizeof(salted_password)); - seprintf(salted_password, lastof(salted_password), "%s", password); /* Add the game seed and the server's ID as the salt. */ for (uint i = 0; i < NETWORK_SERVER_ID_LENGTH - 1; i++) { - salted_password[i] ^= password_server_id[i] ^ (password_game_seed >> (i % 32)); + char password_char = (i < password_length ? password[i] : 0); + char server_id_char = (i < password_server_id_length ? password_server_id[i] : 0); + char seed_char = password_game_seed >> (i % 32); + salted_password[i] = password_char ^ server_id_char ^ seed_char; } Md5 checksum; @@ -285,7 +280,7 @@ uint NetworkCalculateLag(const NetworkClientSocket *cs) /* There was a non-recoverable error, drop back to the main menu with a nice * error */ -void NetworkError(StringID error_string) +void ShowNetworkError(StringID error_string) { _switch_mode = SM_MENU; ShowErrorMessage(error_string, INVALID_STRING_ID, WL_CRITICAL); @@ -321,6 +316,7 @@ StringID GetNetworkErrorMsg(NetworkErrorCode err) STR_NETWORK_ERROR_CLIENT_TIMEOUT_COMPUTER, STR_NETWORK_ERROR_CLIENT_TIMEOUT_MAP, STR_NETWORK_ERROR_CLIENT_TIMEOUT_JOIN, + STR_NETWORK_ERROR_CLIENT_INVALID_CLIENT_NAME, }; static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END); @@ -457,15 +453,14 @@ static void CheckPauseOnJoin() * Converts a string to ip/port/company * Format: IP:port#company * - * connection_string will be re-terminated to separate out the hostname, and company and port will - * be set to the company and port strings given by the user, inside the memory area originally - * occupied by connection_string. + * connection_string will be re-terminated to separate out the hostname, port will + * be set to the port strings given by the user, inside the memory area originally + * occupied by connection_string. Similar for company, if set. */ -void ParseConnectionString(const char **company, const char **port, char *connection_string) +void ParseFullConnectionString(const char **company, const char **port, char *connection_string) { bool ipv6 = (strchr(connection_string, ':') != strrchr(connection_string, ':')); - char *p; - for (p = connection_string; *p != '\0'; p++) { + for (char *p = connection_string; *p != '\0'; p++) { switch (*p) { case '[': ipv6 = true; @@ -476,6 +471,7 @@ void ParseConnectionString(const char **company, const char **port, char *connec break; case '#': + if (company == nullptr) continue; *company = p + 1; *p = '\0'; break; @@ -489,6 +485,51 @@ void ParseConnectionString(const char **company, const char **port, char *connec } } +/** + * Convert a string containing either "hostname" or "hostname:ip" to a + * NetworkAddress. + * + * @param connection_string The string to parse. + * @param default_port The default port to set port to if not in connection_string. + * @return A valid NetworkAddress of the parsed information. + */ +NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port) +{ + char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH]; + strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); + + const char *port = nullptr; + ParseFullConnectionString(nullptr, &port, internal_connection_string); + + int rport = port != nullptr ? atoi(port) : default_port; + return NetworkAddress(internal_connection_string, rport); +} + +/** + * Convert a string containing either "hostname" or "hostname:ip" to a + * NetworkAddress, where the string can be postfixed with "#company" to + * indicate the requested company. + * + * @param company Pointer to the company variable to set iff indicted. + * @param connection_string The string to parse. + * @param default_port The default port to set port to if not in connection_string. + * @return A valid NetworkAddress of the parsed information. + */ +NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port) +{ + char internal_connection_string[NETWORK_HOSTNAME_PORT_LENGTH + 4]; // 4 extra for the "#" and company + strecpy(internal_connection_string, connection_string.c_str(), lastof(internal_connection_string)); + + const char *port_s = nullptr; + const char *company_s = nullptr; + ParseFullConnectionString(&company_s, &port_s, internal_connection_string); + + if (company_s != nullptr) *company = (CompanyID)atoi(company_s); + + int port = port_s != nullptr ? atoi(port_s) : default_port; + return NetworkAddress(internal_connection_string, port); +} + /** * Handle the accepting of a connection to the server. * @param s The socket of the new connection. @@ -499,9 +540,10 @@ void ParseConnectionString(const char **company, const char **port, char *connec /* Register the login */ _network_clients_connected++; - SetWindowDirty(WC_CLIENT_LIST, 0); ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s); cs->client_address = address; // Save the IP of the client + + InvalidateWindowData(WC_CLIENT_LIST, 0); } /** @@ -563,8 +605,11 @@ static void NetworkInitialize(bool close_admins = true) /** Non blocking connection create to query servers */ class TCPQueryConnecter : TCPConnecter { +private: + bool request_company_info; + public: - TCPQueryConnecter(const NetworkAddress &address) : TCPConnecter(address) {} + TCPQueryConnecter(const NetworkAddress &address, bool request_company_info) : TCPConnecter(address), request_company_info(request_company_info) {} void OnFailure() override { @@ -574,45 +619,53 @@ public: void OnConnect(SOCKET s) override { _networking = true; - new ClientNetworkGameSocketHandler(s); - MyClient::SendCompanyInformationQuery(); + new ClientNetworkGameSocketHandler(s, address); + MyClient::SendInformationQuery(request_company_info); } }; -/* Query a server to fetch his game-info - * If game_info is true, only the gameinfo is fetched, - * else only the client_info is fetched */ -void NetworkTCPQueryServer(NetworkAddress address) +/** + * Query a server to fetch his game-info. + * @param address the address to query. + * @param request_company_info Whether to request company info too. + */ +void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info) { if (!_network_available) return; NetworkDisconnect(); NetworkInitialize(); - new TCPQueryConnecter(address); + new TCPQueryConnecter(address, request_company_info); } -/* Validates an address entered as a string and adds the server to +/** + * Validates an address entered as a string and adds the server to * the list. If you use this function, the games will be marked - * as manually added. */ -void NetworkAddServer(const char *b) + * as manually added. + * @param connection_string The IP:port of the server to add. + * @return The entry on the game list. + */ +NetworkGameList *NetworkAddServer(const std::string &connection_string) { - if (*b != '\0') { - const char *port = nullptr; - const char *company = nullptr; - char host[NETWORK_HOSTNAME_LENGTH]; - uint16 rport; + if (connection_string.empty()) return nullptr; - strecpy(host, b, lastof(host)); + NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_PORT); - strecpy(_settings_client.network.connect_to_ip, b, lastof(_settings_client.network.connect_to_ip)); - rport = NETWORK_DEFAULT_PORT; + /* Ensure the item already exists in the list */ + NetworkGameList *item = NetworkGameListAddItem(address); + if (StrEmpty(item->info.server_name)) { + ClearGRFConfigList(&item->info.grfconfig); + address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); + item->manually = true; - ParseConnectionString(&company, &port, host); - if (port != nullptr) rport = atoi(port); - - NetworkUDPQueryServer(NetworkAddress(host, rport), true); + NetworkRebuildHostList(); + UpdateNetworkGameWindow(); } + + NetworkTCPQueryServer(address); + + return item; } /** @@ -651,45 +704,105 @@ public: void OnFailure() override { - NetworkError(STR_NETWORK_ERROR_NOCONNECTION); + ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION); } void OnConnect(SOCKET s) override { _networking = true; - new ClientNetworkGameSocketHandler(s); + new ClientNetworkGameSocketHandler(s, this->address); IConsoleCmdExec("exec scripts/on_client.scr 0"); NetworkClient_Connected(); } }; - -/* Used by clients, to connect to a server */ -void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password, const char *join_company_password) +/** + * Join a client to the server at with the given connection string. + * The default for the passwords is \c nullptr. When the server or company needs a + * password and none is given, the user is asked to enter the password in the GUI. + * This function will return false whenever some information required to join is not + * correct such as the company number or the client's name, or when there is not + * networking avalabile at all. If the function returns false the connection with + * the existing server is not disconnected. + * It will return true when it starts the actual join process, i.e. when it + * actually shows the join status window. + * + * @param connection_string The IP address, port and company number to join as. + * @param default_company The company number to join as when none is given. + * @param join_server_password The password for the server. + * @param join_company_password The password for the company. + * @return Whether the join has started. + */ +bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password, const char *join_company_password) { - if (!_network_available) return; + CompanyID join_as = default_company; + NetworkAddress address = ParseGameConnectionString(&join_as, connection_string, NETWORK_DEFAULT_PORT); - if (address.GetPort() == 0) return; + if (join_as != COMPANY_NEW_COMPANY && join_as != COMPANY_SPECTATOR) { + join_as--; + if (join_as >= MAX_COMPANIES) { + return false; + } + } - strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host)); - _settings_client.network.last_port = address.GetPort(); - _network_join_as = join_as; - _network_join_server_password = join_server_password; - _network_join_company_password = join_company_password; + return NetworkClientConnectGame(address, join_as, join_server_password, join_company_password); +} +/** + * Join a client to the server at the given address. + * See the overloaded NetworkClientConnectGame for more details. + * + * @param address The network address of the server to join to. + * @param join_as The company number to join as. + * @param join_server_password The password for the server. + * @param join_company_password The password for the company. + * @return Whether the join has started. + */ +bool NetworkClientConnectGame(NetworkAddress &address, CompanyID join_as, const char *join_server_password, const char *join_company_password) +{ + if (!_network_available) return false; + if (!NetworkValidateClientName()) return false; + + _network_join.address = address; + _network_join.company = join_as; + _network_join.server_password = join_server_password; + _network_join.company_password = join_company_password; + + if (_game_mode == GM_MENU) { + /* From the menu we can immediately continue with the actual join. */ + NetworkClientJoinGame(); + } else { + /* When already playing a game, first go back to the main menu. This + * disconnects the user from the current game, meaning we can safely + * load in the new. After all, there is little point in continueing to + * play on a server if we are connecting to another one. + */ + _switch_mode = SM_JOIN_GAME; + } + return true; +} + +/** + * Actually perform the joining to the server. Use #NetworkClientConnectGame + * when you want to connect to a specific server/company. This function + * assumes _network_join is already fully set up. + */ +void NetworkClientJoinGame() +{ NetworkDisconnect(); NetworkInitialize(); + strecpy(_settings_client.network.last_joined, _network_join.address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined)); _network_join_status = NETWORK_JOIN_STATUS_CONNECTING; ShowJoinStatusWindow(); - new TCPClientConnecter(address); + new TCPClientConnecter(_network_join.address); } static void NetworkInitGameInfo() { if (StrEmpty(_settings_client.network.server_name)) { - seprintf(_settings_client.network.server_name, lastof(_settings_client.network.server_name), "Unnamed Server"); + strecpy(_settings_client.network.server_name, "Unnamed Server", lastof(_settings_client.network.server_name)); } /* The server is a client too */ @@ -724,7 +837,7 @@ bool NetworkServerStart() /* Try to start UDP-server */ DEBUG(net, 1, "starting listeners for incoming server queries"); - _network_udp_server = _udp_server_socket->Listen(); + NetworkUDPServerListen(); _network_company_states = CallocT(MAX_COMPANIES); _network_server = true; @@ -1034,11 +1147,13 @@ static void NetworkGenerateServerId() seprintf(_settings_client.network.network_id, lastof(_settings_client.network.network_id), "%s", hex_output); } -void NetworkStartDebugLog(NetworkAddress address) +void NetworkStartDebugLog(const std::string &connection_string) { extern SOCKET _debug_socket; // Comes from debug.c - DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort()); + NetworkAddress address = ParseConnectionString(connection_string, NETWORK_DEFAULT_DEBUGLOG_PORT); + + DEBUG(net, 0, "Redirecting DEBUG() to %s", address.GetAddressAsString().c_str()); SOCKET s = address.Connect(); if (s == INVALID_SOCKET) { @@ -1060,7 +1175,6 @@ void NetworkStartUp() _network_available = NetworkCoreInitialize(); _network_dedicated = false; _network_need_advertise = true; - _network_advertise_retries = 0; /* Generate an server id when there is none yet */ if (StrEmpty(_settings_client.network.network_id)) NetworkGenerateServerId(); @@ -1085,85 +1199,12 @@ void NetworkShutDown() NetworkCoreShutdown(); } -/** - * How many hex digits of the git hash to include in network revision string. - * Determined as 10 hex digits + 2 characters for -g/-u/-m prefix. - */ -static const uint GITHASH_SUFFIX_LEN = 12; - -/** - * Get the network version string used by this build. - * The returned string is guaranteed to be at most NETWORK_REVISON_LENGTH bytes. - */ -const char * GetNetworkRevisionString() -{ - /* This will be allocated on heap and never free'd, but only once so not a "real" leak. */ - static char *network_revision = nullptr; - - if (!network_revision) { - /* Start by taking a chance on the full revision string. */ - network_revision = stredup(_openttd_revision); - /* Ensure it's not longer than the packet buffer length. */ - if (strlen(network_revision) >= NETWORK_REVISION_LENGTH) network_revision[NETWORK_REVISION_LENGTH - 1] = '\0'; - - /* Tag names are not mangled further. */ - if (_openttd_revision_tagged) { - DEBUG(net, 1, "Network revision name is '%s'", network_revision); - return network_revision; - } - - /* Prepare a prefix of the git hash. - * Size is length + 1 for terminator, +2 for -g prefix. */ - assert(_openttd_revision_modified < 3); - char githash_suffix[GITHASH_SUFFIX_LEN + 1] = "-"; - githash_suffix[1] = "gum"[_openttd_revision_modified]; - for (uint i = 2; i < GITHASH_SUFFIX_LEN; i++) { - githash_suffix[i] = _openttd_revision_hash[i-2]; - } - - /* Where did the hash start in the original string? - * Overwrite from that position, unless that would go past end of packet buffer length. */ - ptrdiff_t hashofs = strrchr(_openttd_revision, '-') - _openttd_revision; - if (hashofs + strlen(githash_suffix) + 1 > NETWORK_REVISION_LENGTH) hashofs = strlen(network_revision) - strlen(githash_suffix); - /* Replace the git hash in revision string. */ - strecpy(network_revision + hashofs, githash_suffix, network_revision + NETWORK_REVISION_LENGTH); - assert(strlen(network_revision) < NETWORK_REVISION_LENGTH); // strlen does not include terminator, constant does, hence strictly less than - DEBUG(net, 1, "Network revision name is '%s'", network_revision); - } - - return network_revision; -} - -static const char *ExtractNetworkRevisionHash(const char *revstr) -{ - return strrchr(revstr, '-'); -} - -/** - * Checks whether the given version string is compatible with our version. - * First tries to match the full string, if that fails, attempts to compare just git hashes. - * @param other the version string to compare to - */ -bool IsNetworkCompatibleVersion(const char *other) -{ - if (strncmp(GetNetworkRevisionString(), other, NETWORK_REVISION_LENGTH - 1) == 0) return true; - - /* If this version is tagged, then the revision string must be a complete match, - * since there is no git hash suffix in it. - * This is needed to avoid situations like "1.9.0-beta1" comparing equal to "2.0.0-beta1". */ - if (_openttd_revision_tagged) return false; - - const char *hash1 = ExtractNetworkRevisionHash(GetNetworkRevisionString()); - const char *hash2 = ExtractNetworkRevisionHash(other); - return hash1 && hash2 && (strncmp(hash1, hash2, GITHASH_SUFFIX_LEN) == 0); -} - #ifdef __EMSCRIPTEN__ extern "C" { -void CDECL em_openttd_add_server(const char *host, int port) +void CDECL em_openttd_add_server(const char *connection_string) { - NetworkUDPQueryServer(NetworkAddress(host, port), true); + NetworkAddServer(connection_string); } } diff --git a/src/network/network_admin.cpp b/src/network/network_admin.cpp index aa2859ef88..7b49754515 100644 --- a/src/network/network_admin.cpp +++ b/src/network/network_admin.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" +#include "core/game_info.h" #include "network_admin.h" #include "network_base.h" #include "network_server.h" @@ -170,7 +171,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendWelcome() p->Send_string(GetNetworkRevisionString()); p->Send_bool (_network_dedicated); - p->Send_string(_network_game_info.map_name); + p->Send_string(""); // Used to be map-name. p->Send_uint32(_settings_game.game_creation.generation_seed); p->Send_uint8 (_settings_game.game_creation.landscape); p->Send_uint32(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1)); @@ -238,7 +239,7 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendClientInfo(const NetworkC p->Send_uint32(ci->client_id); p->Send_string(cs == nullptr ? "" : const_cast(cs->client_address).GetHostname()); p->Send_string(ci->client_name); - p->Send_uint8 (ci->client_lang); + p->Send_uint8 (0); // Used to be language p->Send_uint32(ci->join_date); p->Send_uint8 (ci->client_playas); @@ -560,8 +561,8 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendConsole(const char *origi /* If the length of both strings, plus the 2 '\0' terminations and 3 bytes of the packet * are bigger than the MTU, just ignore the message. Better safe than sorry. It should * never occur though as the longest strings are chat messages, which are still 30% - * smaller than SEND_MTU. */ - if (strlen(origin) + strlen(string) + 2 + 3 >= SEND_MTU) return NETWORK_RECV_STATUS_OKAY; + * smaller than COMPAT_MTU. */ + if (strlen(origin) + strlen(string) + 2 + 3 >= COMPAT_MTU) return NETWORK_RECV_STATUS_OKAY; Packet *p = new Packet(ADMIN_PACKET_SERVER_CONSOLE); @@ -610,10 +611,10 @@ NetworkRecvStatus ServerNetworkAdminSocketHandler::SendCmdNames() for (uint i = 0; i < CMD_END; i++) { const char *cmdname = GetCommandName(i); - /* Should SEND_MTU be exceeded, start a new packet + /* Should COMPAT_MTU be exceeded, start a new packet * (magic 5: 1 bool "more data" and one uint16 "command id", one * byte for string '\0' termination and 1 bool "no more data" */ - if (p->size + strlen(cmdname) + 5 >= SEND_MTU) { + if (p->CanWriteToPacket(strlen(cmdname) + 5)) { p->Send_bool(false); this->SendPacket(p); diff --git a/src/network/network_base.h b/src/network/network_base.h index cbb7e88f2c..9ad0300629 100644 --- a/src/network/network_base.h +++ b/src/network/network_base.h @@ -14,6 +14,7 @@ #include "core/address.h" #include "../core/pool_type.hpp" #include "../company_type.h" +#include "../date_type.h" /** Type for the pool with client information. */ typedef Pool NetworkClientInfoPool; @@ -23,7 +24,6 @@ extern NetworkClientInfoPool _networkclientinfo_pool; struct NetworkClientInfo : NetworkClientInfoPool::PoolItem<&_networkclientinfo_pool> { ClientID client_id; ///< Client identifier (same as ClientState->client_id) char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< Name of the client - byte client_lang; ///< The language of the client CompanyID client_playas; ///< As which company is this client playing (CompanyID) Date join_date; ///< Gamedate the client has joined diff --git a/src/network/network_chat_gui.cpp b/src/network/network_chat_gui.cpp index 6a6c34dbfe..8401d16d77 100644 --- a/src/network/network_chat_gui.cpp +++ b/src/network/network_chat_gui.cpp @@ -7,8 +7,6 @@ /** @file network_chat_gui.cpp GUI for handling chat messages. */ -#include /* va_list */ - #include "../stdafx.h" #include "../strings_func.h" #include "../blitter/factory.hpp" @@ -27,6 +25,9 @@ #include "table/strings.h" +#include /* va_list */ +#include + #include "../safeguards.h" /** The draw buffer must be able to contain the chat message, client name and the "[All]" message, @@ -44,12 +45,18 @@ struct ChatMessage { }; /* used for chat window */ -static ChatMessage *_chatmsg_list = nullptr; ///< The actual chat message list. +static std::deque _chatmsg_list; ///< The actual chat message list. static bool _chatmessage_dirty = false; ///< Does the chat message need repainting? static bool _chatmessage_visible = false; ///< Is a chat message visible. static bool _chat_tab_completion_active; ///< Whether tab completion is active. static uint MAX_CHAT_MESSAGES = 0; ///< The limit of chat messages to show. +/** + * Time the chat history was marked dirty. This is used to determine if expired + * messages have recently expired and should cause a redraw to hide them. + */ +static std::chrono::steady_clock::time_point _chatmessage_dirty_time; + /** * The chatbox grows from the bottom so the coordinates are pixels from * the left and pixels from the bottom. The height is the maximum height. @@ -58,17 +65,20 @@ static PointDimension _chatmsg_box; static uint8 *_chatmessage_backup = nullptr; ///< Backup in case text is moved. /** - * Count the chat messages. - * @return The number of chat messages. + * Test if there are any chat messages to display. + * @param show_all Set if all messages should be included, instead of unexpired only. + * @return True iff there are chat messages to display. */ -static inline uint GetChatMessageCount() +static inline bool HaveChatMessages(bool show_all) { - uint i = 0; - for (; i < MAX_CHAT_MESSAGES; i++) { - if (_chatmsg_list[i].message[0] == '\0') break; + if (show_all) return _chatmsg_list.size() != 0; + + auto now = std::chrono::steady_clock::now(); + for (auto &cmsg : _chatmsg_list) { + if (cmsg.remove_time >= now) return true; } - return i; + return false; } /** @@ -88,17 +98,16 @@ void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *m Utf8TrimString(buf, DRAW_STRING_BUFFER); - uint msg_count = GetChatMessageCount(); - if (MAX_CHAT_MESSAGES == msg_count) { - memmove(&_chatmsg_list[0], &_chatmsg_list[1], sizeof(_chatmsg_list[0]) * (msg_count - 1)); - msg_count = MAX_CHAT_MESSAGES - 1; + if (_chatmsg_list.size() == MAX_CHAT_MESSAGES) { + _chatmsg_list.pop_back(); } - ChatMessage *cmsg = &_chatmsg_list[msg_count++]; + ChatMessage *cmsg = &_chatmsg_list.emplace_front(); strecpy(cmsg->message, buf, lastof(cmsg->message)); cmsg->colour = (colour & TC_IS_PALETTE_COLOUR) ? colour : TC_WHITE; cmsg->remove_time = std::chrono::steady_clock::now() + std::chrono::seconds(duration); + _chatmessage_dirty_time = std::chrono::steady_clock::now(); _chatmessage_dirty = true; } @@ -115,15 +124,11 @@ void NetworkInitChatMessage() { MAX_CHAT_MESSAGES = _settings_client.gui.network_chat_box_height; - _chatmsg_list = ReallocT(_chatmsg_list, _settings_client.gui.network_chat_box_height); + _chatmsg_list.clear(); _chatmsg_box.x = GetMinSizing(NWST_STEP, 10) + 5; _chatmsg_box.width = _settings_client.gui.network_chat_box_width_pct * _screen.width / 100; NetworkReInitChatBoxSize(); _chatmessage_visible = false; - - for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { - _chatmsg_list[i].message[0] = '\0'; - } } /** Hide the chatbox */ @@ -168,6 +173,7 @@ void NetworkUndrawChatMessage() /* And make sure it is updated next time */ VideoDriver::GetInstance()->MakeDirty(x, y, width, height); + _chatmessage_dirty_time = std::chrono::steady_clock::now(); _chatmessage_dirty = true; } } @@ -175,21 +181,13 @@ void NetworkUndrawChatMessage() /** Check if a message is expired. */ void NetworkChatMessageLoop() { - for (uint i = 0; i < MAX_CHAT_MESSAGES; i++) { - ChatMessage *cmsg = &_chatmsg_list[i]; - if (cmsg->message[0] == '\0') continue; - + auto now = std::chrono::steady_clock::now(); + for (auto &cmsg : _chatmsg_list) { /* Message has expired, remove from the list */ - if (std::chrono::steady_clock::now() > cmsg->remove_time) { - /* Move the remaining messages over the current message */ - if (i != MAX_CHAT_MESSAGES - 1) memmove(cmsg, cmsg + 1, sizeof(*cmsg) * (MAX_CHAT_MESSAGES - i - 1)); - - /* Mark the last item as empty */ - _chatmsg_list[MAX_CHAT_MESSAGES - 1].message[0] = '\0'; + if (now > cmsg.remove_time && _chatmessage_dirty_time < cmsg.remove_time) { + _chatmessage_dirty_time = now; _chatmessage_dirty = true; - - /* Go one item back, because we moved the array 1 to the left */ - i--; + break; } } } @@ -200,14 +198,16 @@ void NetworkDrawChatMessage() Blitter *blitter = BlitterFactory::GetCurrentBlitter(); if (!_chatmessage_dirty) return; + const Window *w = FindWindowByClass(WC_SEND_NETWORK_MSG); + bool show_all = (w != nullptr); + /* First undraw if needed */ NetworkUndrawChatMessage(); if (_iconsole_mode == ICONSOLE_FULL) return; /* Check if we have anything to draw at all */ - uint count = GetChatMessageCount(); - if (count == 0) return; + if (!HaveChatMessages(show_all)) return; int x = _chatmsg_box.x; int y = _screen.height - _chatmsg_box.y - _chatmsg_box.height; @@ -229,9 +229,11 @@ void NetworkDrawChatMessage() _cur_dpi = &_screen; // switch to _screen painting + auto now = std::chrono::steady_clock::now(); int string_height = 0; - for (uint i = 0; i < count; i++) { - SetDParamStr(0, _chatmsg_list[i].message); + for (auto &cmsg : _chatmsg_list) { + if (!show_all && cmsg.remove_time < now) continue; + SetDParamStr(0, cmsg.message); string_height += GetStringLineCount(STR_JUST_RAW_STRING, width - 1) * FONT_HEIGHT_NORMAL + NETWORK_CHAT_LINE_SPACING; } @@ -247,8 +249,9 @@ void NetworkDrawChatMessage() /* Paint the chat messages starting with the lowest at the bottom */ int ypos = bottom - 2; - for (int i = count - 1; i >= 0; i--) { - ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, _chatmsg_list[i].message, _chatmsg_list[i].colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; + for (auto &cmsg : _chatmsg_list) { + if (!show_all && cmsg.remove_time < now) continue; + ypos = DrawStringMultiLine(_chatmsg_box.x + 3, _chatmsg_box.x + _chatmsg_box.width - 1, top, ypos, cmsg.message, cmsg.colour, SA_LEFT | SA_BOTTOM | SA_FORCE) - NETWORK_CHAT_LINE_SPACING; if (ypos < top) break; } @@ -278,7 +281,6 @@ static void SendChat(const char *buf, DestType type, int dest) /** Window to enter the chat message in. */ struct NetworkChatWindow : public Window { DestType dtype; ///< The type of destination. - StringID dest_string; ///< String representation of the destination. int dest; ///< The identifier of the destination. QueryString message_editbox; ///< Message editbox. @@ -302,9 +304,10 @@ struct NetworkChatWindow : public Window { STR_NETWORK_CHAT_CLIENT_CAPTION }; assert((uint)this->dtype < lengthof(chat_captions)); - this->dest_string = chat_captions[this->dtype]; - this->InitNested(type); + this->CreateNestedTree(); + this->GetWidget(WID_NC_DESTINATION)->widget_data = chat_captions[this->dtype]; + this->FinishInitNested(type); this->SetFocusedWidget(WID_NC_TEXTBOX); InvalidateWindowData(WC_NEWS_WINDOW, 0, this->height); @@ -459,27 +462,13 @@ struct NetworkChatWindow : public Window { return pt; } - void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override + void SetStringParameters(int widget) const override { if (widget != WID_NC_DESTINATION) return; if (this->dtype == DESTTYPE_CLIENT) { SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name); } - Dimension d = GetStringBoundingBox(this->dest_string); - d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = maxdim(*size, d); - } - - void DrawWidget(const Rect &r, int widget) const override - { - if (widget != WID_NC_DESTINATION) return; - - if (this->dtype == DESTTYPE_CLIENT) { - SetDParamStr(0, NetworkClientInfo::GetByClientID((ClientID)this->dest)->client_name); - } - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(r.top, r.bottom - r.top), this->dest_string, TC_BLACK, SA_RIGHT); } void OnClick(Point pt, int widget, int click_count) override @@ -527,7 +516,7 @@ static const NWidgetPart _nested_chat_window_widgets[] = { NWidget(WWT_CLOSEBOX, COLOUR_GREY, WID_NC_CLOSE), NWidget(WWT_PANEL, COLOUR_GREY, WID_NC_BACKGROUND), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXT, COLOUR_GREY, WID_NC_DESTINATION), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NULL, STR_NULL), + NWidget(WWT_TEXT, COLOUR_GREY, WID_NC_DESTINATION), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetTextColour(TC_BLACK), SetAlignment(SA_TOP | SA_RIGHT), SetDataTip(STR_NULL, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_NC_TEXTBOX), SetMinimalSize(100, 12), SetPadding(1, 0, 1, 0), SetResize(1, 0), SetDataTip(STR_NETWORK_CHAT_OSKTITLE, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_NC_SENDBUTTON), SetMinimalSize(62, 12), SetPadding(1, 0, 1, 0), SetDataTip(STR_NETWORK_CHAT_SEND, STR_NULL), diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index cd19042691..d288c71a6e 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -23,9 +23,11 @@ #include "../gfx_func.h" #include "../error.h" #include "../rev.h" +#include "core/game_info.h" #include "network.h" #include "network_base.h" #include "network_client.h" +#include "network_gamelist.h" #include "../core/backup_type.hpp" #include "../thread.h" @@ -35,7 +37,6 @@ /* This file handles all the client-commands */ - /** Read some packets, and when do use that data as initial load filter. */ struct PacketReader : LoadFilter { static const size_t CHUNK = 32 * 1024; ///< 32 KiB chunks of memory. @@ -59,35 +60,38 @@ struct PacketReader : LoadFilter { } } + /** + * Simple wrapper around fwrite to be able to pass it to Packet's TransferOut. + * @param destination The reader to add the data to. + * @param source The buffer to read data from. + * @param amount The number of bytes to copy. + * @return The number of bytes that were copied. + */ + static inline ssize_t TransferOutMemCopy(PacketReader *destination, const char *source, size_t amount) + { + memcpy(destination->buf, source, amount); + destination->buf += amount; + destination->written_bytes += amount; + return amount; + } + /** * Add a packet to this buffer. * @param p The packet to add. */ - void AddPacket(const Packet *p) + void AddPacket(Packet *p) { assert(this->read_bytes == 0); - - size_t in_packet = p->size - p->pos; - size_t to_write = std::min(this->bufe - this->buf, in_packet); - const byte *pbuf = p->buffer + p->pos; - - this->written_bytes += in_packet; - if (to_write != 0) { - memcpy(this->buf, pbuf, to_write); - this->buf += to_write; - } + p->TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this); /* Did everything fit in the current chunk, then we're done. */ - if (to_write == in_packet) return; + if (p->RemainingBytesToTransfer() == 0) return; /* Allocate a new chunk and add the remaining data. */ - pbuf += to_write; - to_write = in_packet - to_write; this->blocks.push_back(this->buf = CallocT(CHUNK)); this->bufe = this->buf + CHUNK; - memcpy(this->buf, pbuf, to_write); - this->buf += to_write; + p->TransferOutWithLimit(TransferOutMemCopy, this->bufe - this->buf, this); } size_t Read(byte *rbuf, size_t size) override @@ -141,7 +145,7 @@ void ClientNetworkEmergencySave() * Create a new socket for the client side of the game connection. * @param s The socket to connect with. */ -ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s) : NetworkGameSocketHandler(s), savegame(nullptr), status(STATUS_INACTIVE) +ClientNetworkGameSocketHandler::ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address) : NetworkGameSocketHandler(s), address(address), savegame(nullptr), status(STATUS_INACTIVE) { assert(ClientNetworkGameSocketHandler::my_client == nullptr); ClientNetworkGameSocketHandler::my_client = this; @@ -280,7 +284,7 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) #else if (_sync_seed_1 != _random.state[0]) { #endif - NetworkError(STR_NETWORK_ERROR_DESYNC); + ShowNetworkError(STR_NETWORK_ERROR_DESYNC); DEBUG(desync, 1, "sync_err: %08x; %02x", _date, _date_fract); DEBUG(net, 0, "Sync error detected!"); my_client->ClientError(NETWORK_RECV_STATUS_DESYNC); @@ -322,13 +326,8 @@ static uint8 _network_server_max_companies; /** Maximum number of spectators of the currently joined server. */ static uint8 _network_server_max_spectators; -/** Who would we like to join as. */ -CompanyID _network_join_as; - -/** Login password from -p argument */ -const char *_network_join_server_password = nullptr; -/** Company password from -P argument */ -const char *_network_join_company_password = nullptr; +/** Information about the game to join to. */ +NetworkJoinInfo _network_join; /** Make sure the server ID length is the same as a md5 hash. */ static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); @@ -338,15 +337,22 @@ static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1); * DEF_CLIENT_SEND_COMMAND has no parameters ************/ -/** Query the server for company information. */ -NetworkRecvStatus ClientNetworkGameSocketHandler::SendCompanyInformationQuery() +/** + * Query the server for server information. + */ +NetworkRecvStatus ClientNetworkGameSocketHandler::SendInformationQuery(bool request_company_info) { - my_client->status = STATUS_COMPANY_INFO; - _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; - SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); + my_client->status = STATUS_GAME_INFO; + my_client->SendPacket(new Packet(PACKET_CLIENT_GAME_INFO)); + + if (request_company_info) { + my_client->status = STATUS_COMPANY_INFO; + _network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO; + SetWindowDirty(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_JOIN); + + my_client->SendPacket(new Packet(PACKET_CLIENT_COMPANY_INFO)); + } - Packet *p = new Packet(PACKET_CLIENT_COMPANY_INFO); - my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -361,8 +367,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::SendJoin() p->Send_string(GetNetworkRevisionString()); p->Send_uint32(_openttd_newgrf_version); p->Send_string(_settings_client.network.client_name); // Client name - p->Send_uint8 (_network_join_as); // PlayAs - p->Send_uint8 (NETLANG_ANY); // Language + p->Send_uint8 (_network_join.company); // PlayAs + p->Send_uint8 (0); // Used to be language my_client->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } @@ -568,6 +574,34 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_BANNED(Packet * return NETWORK_RECV_STATUS_SERVER_BANNED; } +NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_GAME_INFO(Packet *p) +{ + if (this->status != STATUS_COMPANY_INFO && this->status != STATUS_GAME_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET; + + NetworkGameList *item = GetLobbyGameInfo(); + if (item == nullptr) { + /* This is not the lobby, so add it to the game list. */ + item = NetworkGameListAddItem(this->address); + } + + /* Clear any existing GRFConfig chain. */ + ClearGRFConfigList(&item->info.grfconfig); + /* Retrieve the NetworkGameInfo from the packet. */ + DeserializeNetworkGameInfo(p, &item->info); + /* Check for compatability with the client. */ + CheckGameCompatibility(item->info); + /* Ensure we consider the server online. */ + item->online = true; + + /* It could be either window, but only one is open, so redraw both. */ + SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); + SetWindowDirty(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); + + /* We will receive company info next, so keep connection open. */ + if (this->status == STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_OKAY; + return NETWORK_RECV_STATUS_CLOSE_QUERY; +} + NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_COMPANY_INFO(Packet *p) { if (this->status != STATUS_COMPANY_INFO) return NETWORK_RECV_STATUS_MALFORMED_PACKET; @@ -623,6 +657,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac if (this->status < STATUS_AUTHORIZED) return NETWORK_RECV_STATUS_MALFORMED_PACKET; if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; + /* The server validates the name when receiving it from clients, so when it is wrong + * here something went really wrong. In the best case the packet got malformed on its + * way too us, in the worst case the server is broken or compromised. */ + if (!NetworkIsValidClientName(name)) return NETWORK_RECV_STATUS_MALFORMED_PACKET; ci = NetworkClientInfo::GetByClientID(client_id); if (ci != nullptr) { @@ -641,7 +679,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac ci->client_playas = playas; strecpy(ci->client_name, name, lastof(ci->client_name)); - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } @@ -660,7 +698,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac strecpy(ci->client_name, name, lastof(ci->client_name)); - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } @@ -668,31 +706,41 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p) { static const StringID network_error_strings[] = { - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH - STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED - STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED - STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION - STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE - STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD - STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH - STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED - STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER - STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL - STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS - STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD - STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER - STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP - STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_GENERAL + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_DESYNC + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_SAVEGAME_FAILED + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_CONNECTION_LOST + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_ILLEGAL_PACKET + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NEWGRF_MISMATCH + STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_AUTHORIZED + STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_NOT_EXPECTED + STR_NETWORK_ERROR_WRONG_REVISION, // NETWORK_ERROR_WRONG_REVISION + STR_NETWORK_ERROR_LOSTCONNECTION, // NETWORK_ERROR_NAME_IN_USE + STR_NETWORK_ERROR_WRONG_PASSWORD, // NETWORK_ERROR_WRONG_PASSWORD + STR_NETWORK_ERROR_SERVER_ERROR, // NETWORK_ERROR_COMPANY_MISMATCH + STR_NETWORK_ERROR_KICKED, // NETWORK_ERROR_KICKED + STR_NETWORK_ERROR_CHEATER, // NETWORK_ERROR_CHEATER + STR_NETWORK_ERROR_SERVER_FULL, // NETWORK_ERROR_FULL + STR_NETWORK_ERROR_TOO_MANY_COMMANDS, // NETWORK_ERROR_TOO_MANY_COMMANDS + STR_NETWORK_ERROR_TIMEOUT_PASSWORD, // NETWORK_ERROR_TIMEOUT_PASSWORD + STR_NETWORK_ERROR_TIMEOUT_COMPUTER, // NETWORK_ERROR_TIMEOUT_COMPUTER + STR_NETWORK_ERROR_TIMEOUT_MAP, // NETWORK_ERROR_TIMEOUT_MAP + STR_NETWORK_ERROR_TIMEOUT_JOIN, // NETWORK_ERROR_TIMEOUT_JOIN + STR_NETWORK_ERROR_INVALID_CLIENT_NAME, // NETWORK_ERROR_INVALID_CLIENT_NAME }; static_assert(lengthof(network_error_strings) == NETWORK_ERROR_END); NetworkErrorCode error = (NetworkErrorCode)p->Recv_uint8(); + /* If we query a server that is 1.11.1 or older, we get an + * NETWORK_ERROR_NOT_EXPECTED on requesting the game info. Show a special + * error popup in that case. + */ + if (error == NETWORK_ERROR_NOT_EXPECTED && (this->status == STATUS_GAME_INFO || this->status == STATUS_COMPANY_INFO)) { + ShowErrorMessage(STR_NETWORK_ERROR_SERVER_TOO_OLD, INVALID_STRING_ID, WL_CRITICAL); + return NETWORK_RECV_STATUS_CLOSE_QUERY; + } + StringID err = STR_NETWORK_ERROR_LOSTCONNECTION; if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error]; /* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */ @@ -723,7 +771,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P /* Check all GRFs */ for (; grf_count > 0; grf_count--) { GRFIdentifier c; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); /* Check whether we know this GRF */ const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); @@ -751,7 +799,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_GAME_PASSW if (this->status < STATUS_JOIN || this->status >= STATUS_AUTH_GAME) return NETWORK_RECV_STATUS_MALFORMED_PACKET; this->status = STATUS_AUTH_GAME; - const char *password = _network_join_server_password; + const char *password = _network_join.server_password; if (!StrEmpty(password)) { return SendGamePassword(password); } @@ -770,7 +818,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_NEED_COMPANY_PA p->Recv_string(_password_server_id, sizeof(_password_server_id)); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_MALFORMED_PACKET; - const char *password = _network_join_company_password; + const char *password = _network_join.company_password; if (!StrEmpty(password)) { return SendCompanyPassword(password); } @@ -892,10 +940,10 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet /* New company/spectator (invalid company) or company we want to join is not active * Switch local company to spectator and await the server's judgement */ - if (_network_join_as == COMPANY_NEW_COMPANY || !Company::IsValidID(_network_join_as)) { + if (_network_join.company == COMPANY_NEW_COMPANY || !Company::IsValidID(_network_join.company)) { SetLocalCompany(COMPANY_SPECTATOR); - if (_network_join_as != COMPANY_SPECTATOR) { + if (_network_join.company != COMPANY_SPECTATOR) { /* We have arrived and ready to start playing; send a command to make a new company; * the server will give us a client-id and let us in */ _network_join_status = NETWORK_JOIN_STATUS_REGISTERING; @@ -904,7 +952,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_MAP_DONE(Packet } } else { /* take control over an existing company */ - SetLocalCompany(_network_join_as); + SetLocalCompany(_network_join.company); } return NETWORK_RECV_STATUS_OKAY; @@ -928,7 +976,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p } #endif /* Receive the token. */ - if (p->pos != p->size) this->token = p->Recv_uint8(); + if (p->CanReadFromPacket(sizeof(uint8))) this->token = p->Recv_uint8(); DEBUG(net, 5, "Received FRAME %d", _frame_counter_server); @@ -1036,7 +1084,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack delete ci; } - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } @@ -1055,7 +1103,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p) DEBUG(net, 0, "Unknown client (%d) is leaving the game", client_id); } - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); /* If we come here it means we could not locate the client.. strange :s */ return NETWORK_RECV_STATUS_OKAY; @@ -1072,7 +1120,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p) NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name); } - SetWindowDirty(WC_CLIENT_LIST, 0); + InvalidateWindowData(WC_CLIENT_LIST, 0); return NETWORK_RECV_STATUS_OKAY; } @@ -1250,6 +1298,56 @@ void NetworkClientsToSpectators(CompanyID cid) cur_company.Restore(); } +/** + * Check whether the given client name is deemed valid for use in network games. + * An empty name (null or '') is not valid as that is essentially no name at all. + * A name starting with white space is not valid for tab completion purposes. + * @param client_name The client name to check for validity. + * @return True iff the name is valid. + */ +bool NetworkIsValidClientName(const char *client_name) +{ + if (StrEmpty(client_name)) return false; + if (*client_name == ' ') return false; + return true; +} + +/** + * Trim the given client name in place, i.e. remove leading and trailing spaces. + * After the trim check whether the client name is valid. A client name is valid + * whenever the name is not empty and does not start with spaces. This check is + * done via \c NetworkIsValidClientName. + * When the client name is valid, this function returns true. + * When the client name is not valid a GUI error message is shown telling the + * user to set the client name and this function returns false. + * + * This function is not suitable for ensuring a valid client name at the server + * as the error message will then be shown to the host instead of the client. + * @param client_name The client name to validate. It will be trimmed of leading + * and trailing spaces. + * @return True iff the client name is valid. + */ +bool NetworkValidateClientName(char *client_name) +{ + StrTrimInPlace(client_name); + if (NetworkIsValidClientName(client_name)) return true; + + ShowErrorMessage(STR_NETWORK_ERROR_BAD_PLAYER_NAME, INVALID_STRING_ID, WL_ERROR); + return false; +} + +/** + * Convenience method for NetworkValidateClientName on _settings_client.network.client_name. + * It trims the client name and checks whether it is empty. When it is empty + * an error message is shown to the GUI user. + * See \c NetworkValidateClientName(char*) for details about the functionality. + * @return True iff the client name is valid. + */ +bool NetworkValidateClientName() +{ + return NetworkValidateClientName(_settings_client.network.client_name); +} + /** * Send the server our name. */ @@ -1258,6 +1356,11 @@ void NetworkUpdateClientName() NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(_network_own_client_id); if (ci == nullptr) return; + /* There is no validation on string settings, it is actually a post change callback. + * This method is called from that post change callback. So, when the client name is + * changed via the console there is no easy way to prevent an invalid name. Though, + * we can prevent it getting sent here. */ + if (!NetworkValidateClientName()) return; /* Don't change the name if it is the same as the old name */ if (strcmp(ci->client_name, _settings_client.network.client_name) != 0) { diff --git a/src/network/network_client.h b/src/network/network_client.h index d1ffe1c1d1..81d5b720cd 100644 --- a/src/network/network_client.h +++ b/src/network/network_client.h @@ -15,12 +15,14 @@ /** Class for handling the client side of the game connection. */ class ClientNetworkGameSocketHandler : public ZeroedMemoryAllocator, public NetworkGameSocketHandler { private: + NetworkAddress address; ///< Address we are connected to. struct PacketReader *savegame; ///< Packet reader for reading the savegame. byte token; ///< The token we need to send back to the server to prove we're the right client. /** Status of the connection with the server. */ enum ServerStatus { STATUS_INACTIVE, ///< The client is not connected nor active. + STATUS_GAME_INFO, ///< We are trying to get the game information. STATUS_COMPANY_INFO, ///< We are trying to get company information. STATUS_JOIN, ///< We are trying to join a server. STATUS_NEWGRFS_CHECK, ///< Last action was checking NewGRFs. @@ -43,6 +45,7 @@ protected: NetworkRecvStatus Receive_SERVER_FULL(Packet *p) override; NetworkRecvStatus Receive_SERVER_BANNED(Packet *p) override; NetworkRecvStatus Receive_SERVER_ERROR(Packet *p) override; + NetworkRecvStatus Receive_SERVER_GAME_INFO(Packet *p) override; NetworkRecvStatus Receive_SERVER_COMPANY_INFO(Packet *p) override; NetworkRecvStatus Receive_SERVER_CLIENT_INFO(Packet *p) override; NetworkRecvStatus Receive_SERVER_NEED_GAME_PASSWORD(Packet *p) override; @@ -73,13 +76,13 @@ protected: static NetworkRecvStatus SendMapOk(); void CheckConnection(); public: - ClientNetworkGameSocketHandler(SOCKET s); + ClientNetworkGameSocketHandler(SOCKET s, NetworkAddress address); ~ClientNetworkGameSocketHandler(); NetworkRecvStatus CloseConnection(NetworkRecvStatus status) override; void ClientError(NetworkRecvStatus res); - static NetworkRecvStatus SendCompanyInformationQuery(); + static NetworkRecvStatus SendInformationQuery(bool request_company_info); static NetworkRecvStatus SendJoin(); static NetworkRecvStatus SendCommand(const CommandPacket *cp); @@ -109,9 +112,15 @@ typedef ClientNetworkGameSocketHandler MyClient; void NetworkClient_Connected(); void NetworkClientSetCompanyPassword(const char *password); -extern CompanyID _network_join_as; +/** Information required to join a server. */ +struct NetworkJoinInfo { + NetworkJoinInfo() : company(COMPANY_SPECTATOR), server_password(nullptr), company_password(nullptr) {} + NetworkAddress address; ///< The address of the server to join. + CompanyID company; ///< The company to join. + const char *server_password; ///< The password of the server to join. + const char *company_password; ///< The password of the company to join. +}; -extern const char *_network_join_server_password; -extern const char *_network_join_company_password; +extern NetworkJoinInfo _network_join; #endif /* NETWORK_CLIENT_H */ diff --git a/src/network/network_content.cpp b/src/network/network_content.cpp index 0220f890b3..a208f3c6e2 100644 --- a/src/network/network_content.cpp +++ b/src/network/network_content.cpp @@ -221,9 +221,9 @@ void ClientNetworkContentSocketHandler::RequestContentList(uint count, const Con * A packet begins with the packet size and a byte for the type. * Then this packet adds a uint16 for the count in this packet. * The rest of the packet can be used for the IDs. */ - uint p_count = std::min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); + uint p_count = std::min(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); - Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID); + Packet *p = new Packet(PACKET_CONTENT_CLIENT_INFO_ID, TCP_MTU); p->Send_uint16(p_count); for (uint i = 0; i < p_count; i++) { @@ -248,10 +248,10 @@ void ClientNetworkContentSocketHandler::RequestContentList(ContentVector *cv, bo this->Connect(); assert(cv->size() < 255); - assert(cv->size() < (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / + assert(cv->size() < (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) / (sizeof(uint8) + sizeof(uint32) + (send_md5sum ? /*sizeof(ContentInfo::md5sum)*/16 : 0))); - Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID); + Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU); p->Send_uint8((uint8)cv->size()); for (const ContentInfo *ci : *cv) { @@ -363,9 +363,9 @@ void ClientNetworkContentSocketHandler::DownloadSelectedContentFallback(const Co * A packet begins with the packet size and a byte for the type. * Then this packet adds a uint16 for the count in this packet. * The rest of the packet can be used for the IDs. */ - uint p_count = std::min(count, (SEND_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); + uint p_count = std::min(count, (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint16)) / sizeof(uint32)); - Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT); + Packet *p = new Packet(PACKET_CONTENT_CLIENT_CONTENT, TCP_MTU); p->Send_uint16(p_count); for (uint i = 0; i < p_count; i++) { @@ -459,6 +459,18 @@ static bool GunzipFile(const ContentInfo *ci) #endif /* defined(WITH_ZLIB) */ } +/** + * Simple wrapper around fwrite to be able to pass it to Packet's TransferOut. + * @param file The file to write data to. + * @param buffer The buffer to write to the file. + * @param amount The number of bytes to write. + * @return The number of bytes that were written. + */ +static inline ssize_t TransferOutFWrite(FILE *file, const char *buffer, size_t amount) +{ + return fwrite(buffer, 1, amount, file); +} + bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) { if (this->curFile == nullptr) { @@ -476,8 +488,8 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet *p) } } else { /* We have a file opened, thus are downloading internal content */ - size_t toRead = (size_t)(p->size - p->pos); - if (fwrite(p->buffer + p->pos, 1, toRead, this->curFile) != toRead) { + size_t toRead = p->RemainingBytesToTransfer(); + if (toRead != 0 && (size_t)p->TransferOut(TransferOutFWrite, this->curFile) != toRead) { DeleteWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD); ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR); this->Close(); diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 40b4dbce0d..ace3e35f66 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -861,55 +861,31 @@ public: EventState OnKeyPress(WChar key, uint16 keycode) override { - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->list_pos > 0) this->list_pos--; - break; - case WKC_DOWN: - /* scroll down by one */ - if (this->list_pos < (int)this->content.size() - 1) this->list_pos++; - break; - case WKC_PAGEUP: - /* scroll up a page */ - this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); - break; - case WKC_PAGEDOWN: - /* scroll down a page */ - this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->content.size() - 1); - break; - case WKC_HOME: - /* jump to beginning */ - this->list_pos = 0; - break; - case WKC_END: - /* jump to end */ - this->list_pos = (int)this->content.size() - 1; - break; - - case WKC_SPACE: - case WKC_RETURN: - if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { - if (this->selected != nullptr) { - _network_content_client.ToggleSelectedState(this->selected); - this->content.ForceResort(); - this->InvalidateData(); + if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_NOT_HANDLED) { + switch (keycode) { + case WKC_SPACE: + case WKC_RETURN: + if (keycode == WKC_RETURN || !IsWidgetFocused(WID_NCL_FILTER)) { + if (this->selected != nullptr) { + _network_content_client.ToggleSelectedState(this->selected); + this->content.ForceResort(); + this->InvalidateData(); + } + if (this->filter_data.types.any()) { + this->content.ForceRebuild(); + this->InvalidateData(); + } + return ES_HANDLED; } - if (this->filter_data.types.any()) { - this->content.ForceRebuild(); - this->InvalidateData(); - } - return ES_HANDLED; - } - /* space is pressed and filter is focused. */ - FALLTHROUGH; + /* space is pressed and filter is focused. */ + FALLTHROUGH; - default: - return ES_NOT_HANDLED; + default: + return ES_NOT_HANDLED; + } } if (this->content.size() == 0) { - this->list_pos = 0; // above stuff may result in "-1". if (this->UpdateFilterState()) { this->content.ForceRebuild(); this->InvalidateData(); diff --git a/src/network/network_func.h b/src/network/network_func.h index cbb89820cf..5f3e27c12f 100644 --- a/src/network/network_func.h +++ b/src/network/network_func.h @@ -17,14 +17,13 @@ // #define DEBUG_DUMP_COMMANDS // #define DEBUG_FAILED_DUMP_COMMANDS -#include "core/address.h" #include "network_type.h" #include "../console_type.h" #include "../gfx_type.h" #include "../openttd.h" #include "../company_type.h" +#include "../string_type.h" -extern NetworkServerGameInfo _network_game_info; extern NetworkCompanyState *_network_company_states; extern ClientID _network_own_client_id; @@ -36,6 +35,9 @@ extern StringList _network_host_list; extern StringList _network_ban_list; byte NetworkSpectatorCount(); +bool NetworkIsValidClientName(const char *client_name); +bool NetworkValidateClientName(); +bool NetworkValidateClientName(char *client_name); void NetworkUpdateClientName(); bool NetworkCompanyHasClients(CompanyID company); const char *NetworkChangeCompanyPassword(CompanyID company_id, const char *password); @@ -43,13 +45,14 @@ void NetworkReboot(); void NetworkDisconnect(bool blocking = false, bool close_admins = true); void NetworkGameLoop(); void NetworkBackgroundLoop(); -void ParseConnectionString(const char **company, const char **port, char *connection_string); -void NetworkStartDebugLog(NetworkAddress address); +void ParseFullConnectionString(const char **company, const char **port, char *connection_string); +void NetworkStartDebugLog(const std::string &connection_string); void NetworkPopulateCompanyStats(NetworkCompanyStats *stats); void NetworkUpdateClientInfo(ClientID client_id); void NetworkClientsToSpectators(CompanyID cid); -void NetworkClientConnectGame(NetworkAddress address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +bool NetworkClientConnectGame(const std::string &connection_string, CompanyID default_company, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +void NetworkClientJoinGame(); void NetworkClientRequestMove(CompanyID company, const char *pass = ""); void NetworkClientSendRcon(const char *password, const char *command); void NetworkClientSendChat(NetworkAction action, DestType type, int dest, const char *msg, int64 data = 0); diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index dfe07bdbbb..12dbbce615 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -51,7 +51,6 @@ static void NetworkGameListHandleDelayedInsert() ClearGRFConfigList(&item->info.grfconfig); memset(&item->info, 0, sizeof(item->info)); strecpy(item->info.server_name, ins_item->info.server_name, lastof(item->info.server_name)); - strecpy(item->info.hostname, ins_item->info.hostname, lastof(item->info.hostname)); item->online = false; } item->manually |= ins_item->manually; @@ -70,15 +69,6 @@ static void NetworkGameListHandleDelayedInsert() */ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) { - const char *hostname = address.GetHostname(); - - /* Do not query the 'any' address. */ - if (StrEmpty(hostname) || - strcmp(hostname, "0.0.0.0") == 0 || - strcmp(hostname, "::") == 0) { - return nullptr; - } - NetworkGameList *item, *prev_item; prev_item = nullptr; @@ -96,7 +86,6 @@ NetworkGameList *NetworkGameListAddItem(NetworkAddress address) } else { prev_item->next = item; } - DEBUG(net, 4, "[gamelist] added server to list"); UpdateNetworkGameWindow(); @@ -152,7 +141,7 @@ void NetworkGameListRequery() /* item gets mostly zeroed by NetworkUDPQueryServer */ uint8 retries = item->retries; - NetworkUDPQueryServer(NetworkAddress(item->address)); + NetworkUDPQueryServer(item->address); item->retries = (retries >= REFRESH_GAMEINFO_X_REQUERIES) ? 0 : retries; } } diff --git a/src/network/network_gamelist.h b/src/network/network_gamelist.h index 8e61f3a93b..ce35c01d8b 100644 --- a/src/network/network_gamelist.h +++ b/src/network/network_gamelist.h @@ -11,6 +11,7 @@ #define NETWORK_GAMELIST_H #include "core/address.h" +#include "core/game_info.h" #include "network_type.h" /** Structure with information shown in the game list (GUI) */ diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index a2a934b42e..87f4681d0b 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -17,20 +17,25 @@ #include "network.h" #include "network_base.h" #include "network_content.h" +#include "network_server.h" #include "../gui.h" #include "network_udp.h" #include "../window_func.h" #include "../gfx_func.h" +#include "../widgets/dropdown_type.h" #include "../widgets/dropdown_func.h" #include "../querystring_gui.h" #include "../sortlist_type.h" #include "../company_func.h" +#include "../command_func.h" #include "../core/geometry_func.hpp" #include "../genworld.h" #include "../map_type.h" #include "../guitimer_func.h" #include "../settings_gui.h" #include "../zoom_func.h" +#include "../sprite.h" +#include "../settings_internal.h" #include "../widgets/network_widget.h" @@ -39,38 +44,30 @@ #include "../stringfilter_type.h" -#include "../safeguards.h" - #ifdef __EMSCRIPTEN__ # include #endif +#include + +#include "../safeguards.h" + static void ShowNetworkStartServerWindow(); static void ShowNetworkLobbyWindow(NetworkGameList *ngl); +static ClientID _admin_client_id = INVALID_CLIENT_ID; ///< For what client a confirmation window is open. +static CompanyID _admin_company_id = INVALID_COMPANY; ///< For what company a confirmation window is open. + /** - * Advertisement options in the start server window + * Visibility of the server. Public servers advertise, where private servers + * do not. */ -static const StringID _connection_types_dropdown[] = { - STR_NETWORK_START_SERVER_UNADVERTISED, - STR_NETWORK_START_SERVER_ADVERTISED, +static const StringID _server_visibility_dropdown[] = { + STR_NETWORK_SERVER_VISIBILITY_PRIVATE, + STR_NETWORK_SERVER_VISIBILITY_PUBLIC, INVALID_STRING_ID }; -static std::vector _language_dropdown; - -void SortNetworkLanguages() -{ - /* Init the strings */ - if (_language_dropdown.empty()) { - for (int i = 0; i < NETLANG_COUNT; i++) _language_dropdown.emplace_back(STR_NETWORK_LANG_ANY + i); - _language_dropdown.emplace_back(INVALID_STRING_ID); - } - - /* Sort the strings (we don't move 'any' and the 'invalid' one) */ - std::sort(_language_dropdown.begin() + 1, _language_dropdown.end() - 1, StringIDSorter); -} - /** * Update the network new window because a new server is * found on the network. @@ -81,8 +78,8 @@ void UpdateNetworkGameWindow() } typedef GUIList GUIGameServerList; -typedef uint16 ServerListPosition; -static const ServerListPosition SLP_INVALID = 0xFFFF; +typedef int ServerListPosition; +static const ServerListPosition SLP_INVALID = -1; /** Full blown container to make it behave exactly as we want :) */ class NWidgetServerListHeader : public NWidgetContainer { @@ -102,7 +99,9 @@ public: this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP)); leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP); - leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK).width + GetSpriteSize(SPR_BLOT).width + GetSpriteSize(SPR_FLAGS_BASE).width, 12); + leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK, nullptr, ZOOM_LVL_OUT_4X).width + + GetSpriteSize(SPR_BLOT, nullptr, ZOOM_LVL_OUT_4X).width + + GetSpriteSize(SPR_FLAGS_BASE, nullptr, ZOOM_LVL_OUT_4X).width, 12); leaf->SetFill(0, 1); this->Add(leaf); @@ -431,9 +430,6 @@ protected: /* draw red or green icon, depending on compatibility with server */ DrawSprite(SPR_BLOT, (cur_item->info.compatible ? PALETTE_TO_GREEN : (cur_item->info.version_compatible ? PALETTE_TO_YELLOW : PALETTE_TO_RED)), nwi_info->pos_x + this->blot_offset, y + icon_y_offset + 1); - - /* draw flag according to server language */ - DrawSprite(SPR_FLAGS_BASE + cur_item->info.server_lang, PAL_NONE, nwi_info->pos_x + this->flag_offset, y + (this->resize.step_height - GetSpriteSize(SPR_FLAGS_BASE + cur_item->info.server_lang).height) / 2); } } @@ -479,9 +475,8 @@ public: EM_ASM(if (window["openttd_server_list"]) openttd_server_list()); #endif - this->last_joined = NetworkGameListAddItem(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); + this->last_joined = NetworkAddServer(_settings_client.network.last_joined); this->server = this->last_joined; - if (this->last_joined != nullptr) NetworkUDPQueryServer(this->last_joined->address); this->requery_timer.SetInterval(MILLISECONDS_PER_TICK); @@ -500,7 +495,9 @@ public: { switch (widget) { case WID_NG_MATRIX: - resize->height = SETTING_BUTTON_HEIGHT; + resize->height = WD_MATRIX_TOP + std::max(GetSpriteSize(SPR_BLOT).height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_BOTTOM; + resize->height = GetMinSizing(NWST_STEP, resize->height); + fill->height = resize->height; size->height = 5 * resize->height; break; @@ -629,7 +626,6 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6, STR_NETWORK_SERVER_LIST_GAME_INFO, TC_FROMSTRING, SA_HOR_CENTER); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 4 + FONT_HEIGHT_NORMAL, sel->info.server_name, TC_ORANGE, SA_HOR_CENTER); // game name - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + 6 + 8 + 2 * FONT_HEIGHT_NORMAL, sel->info.map_name, TC_BLACK, SA_HOR_CENTER); // map name uint16 y = r.top + detail_height + 4; @@ -640,10 +636,6 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CLIENTS); y += FONT_HEIGHT_NORMAL; - SetDParam(0, STR_NETWORK_LANG_ANY + sel->info.server_lang); - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANGUAGE); // server language - y += FONT_HEIGHT_NORMAL; - SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + sel->info.map_set); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE); // landscape y += FONT_HEIGHT_NORMAL; @@ -657,9 +649,8 @@ public: DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_VERSION); // server version y += FONT_HEIGHT_NORMAL; - char network_addr_buffer[NETWORK_HOSTNAME_LENGTH + 6 + 7]; - sel->address.GetAddressAsString(network_addr_buffer, lastof(network_addr_buffer)); - SetDParamStr(0, network_addr_buffer); + std::string address = sel->address.GetAddressAsString(); + SetDParamStr(0, address.c_str()); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_SERVER_ADDRESS); // server address y += FONT_HEIGHT_NORMAL; @@ -748,7 +739,7 @@ public: ShowQueryString( STR_JUST_RAW_STRING, STR_NETWORK_SERVER_LIST_ENTER_IP, - NETWORK_HOSTNAME_LENGTH, // maximum number of characters including '\0' + NETWORK_HOSTNAME_PORT_LENGTH, // maximum number of characters including '\0' this, CS_ALPHANUMERAL, QSF_ACCEPT_UNCHANGED); break; @@ -758,14 +749,12 @@ public: case WID_NG_JOIN: // Join Game if (this->server != nullptr) { - seprintf(_settings_client.network.last_host, lastof(_settings_client.network.last_host), "%s", this->server->address.GetHostname()); - _settings_client.network.last_port = this->server->address.GetPort(); ShowNetworkLobbyWindow(this->server); } break; case WID_NG_REFRESH: // Refresh - if (this->server != nullptr) NetworkUDPQueryServer(this->server->address); + if (this->server != nullptr) NetworkTCPQueryServer(this->server->address); break; case WID_NG_NEWGRF: // NewGRF Settings @@ -794,39 +783,8 @@ public: EventState state = ES_NOT_HANDLED; /* handle up, down, pageup, pagedown, home and end */ - if (keycode == WKC_UP || keycode == WKC_DOWN || keycode == WKC_PAGEUP || keycode == WKC_PAGEDOWN || keycode == WKC_HOME || keycode == WKC_END) { - if (this->servers.size() == 0) return ES_HANDLED; - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - if (this->list_pos > 0) this->list_pos--; - break; - case WKC_DOWN: - /* scroll down by one */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - if (this->list_pos < this->servers.size() - 1) this->list_pos++; - break; - case WKC_PAGEUP: - /* scroll up a page */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - this->list_pos = (this->list_pos < this->vscroll->GetCapacity()) ? 0 : this->list_pos - this->vscroll->GetCapacity(); - break; - case WKC_PAGEDOWN: - /* scroll down a page */ - if (this->list_pos == SLP_INVALID) return ES_HANDLED; - this->list_pos = std::min(this->list_pos + this->vscroll->GetCapacity(), (int)this->servers.size() - 1); - break; - case WKC_HOME: - /* jump to beginning */ - this->list_pos = 0; - break; - case WKC_END: - /* jump to end */ - this->list_pos = (ServerListPosition)this->servers.size() - 1; - break; - default: NOT_REACHED(); - } + if (this->vscroll->UpdateListPositionOnKeyPress(this->list_pos, keycode) == ES_HANDLED) { + if (this->list_pos == SLP_INVALID) return ES_HANDLED; this->server = this->servers[this->list_pos]; @@ -862,19 +820,19 @@ public: } case WID_NG_CLIENT: - /* Make sure the name does not start with a space, so TAB completion works */ - if (!StrEmpty(this->name_editbox.text.buf) && this->name_editbox.text.buf[0] != ' ') { - strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name)); - } else { - strecpy(_settings_client.network.client_name, "Player", lastof(_settings_client.network.client_name)); - } + /* Validation of the name will happen once the user tries to join or start a game, as getting + * error messages while typing (e.g. when you clear the name) defeats the purpose of the check. */ + strecpy(_settings_client.network.client_name, this->name_editbox.text.buf, lastof(_settings_client.network.client_name)); break; } } void OnQueryTextFinished(char *str) override { - if (!StrEmpty(str)) NetworkAddServer(str); + if (!StrEmpty(str)) { + strecpy(_settings_client.network.connect_to_ip, str, lastof(_settings_client.network.connect_to_ip)); + NetworkAddServer(str); + } } void OnResize() override @@ -956,7 +914,7 @@ static const NWidgetPart _nested_network_game_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, WID_NG_DETAILS), NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPIP(5, 5, 5), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 155), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NG_DETAILS_SPACER), SetMinimalSize(140, 0), SetMinimalTextLines(15, 24 + WD_PAR_VSEP_NORMAL), SetResize(0, 1), SetFill(1, 1), // Make sure it's at least this wide NWidget(NWID_HORIZONTAL, NC_NONE), SetPIP(5, 5, 5), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NG_NEWGRF_MISSING_SEL), NWidget(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NEWGRF_MISSING), SetFill(1, 0), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), @@ -1017,7 +975,7 @@ void ShowNetworkGameWindow() first = false; /* Add all servers from the config file to our list. */ for (const auto &iter : _network_host_list) { - NetworkAddServer(iter.c_str()); + NetworkAddServer(iter); } } @@ -1042,7 +1000,7 @@ struct NetworkStartServerWindow : public Window { { switch (widget) { case WID_NSS_CONNTYPE_BTN: - SetDParam(0, _connection_types_dropdown[_settings_client.network.server_advertise]); + SetDParam(0, _server_visibility_dropdown[_settings_client.network.server_advertise]); break; case WID_NSS_CLIENTS_TXT: @@ -1056,10 +1014,6 @@ struct NetworkStartServerWindow : public Window { case WID_NSS_SPECTATORS_TXT: SetDParam(0, _settings_client.network.max_spectators); break; - - case WID_NSS_LANGUAGE_BTN: - SetDParam(0, STR_NETWORK_LANG_ANY + _settings_client.network.server_lang); - break; } } @@ -1067,9 +1021,11 @@ struct NetworkStartServerWindow : public Window { { switch (widget) { case WID_NSS_CONNTYPE_BTN: - *size = maxdim(GetStringBoundingBox(_connection_types_dropdown[0]), GetStringBoundingBox(_connection_types_dropdown[1])); - size->width = GetMinSizing(NWST_BUTTON, size->width + padding.width); - size->height = GetMinSizing(NWST_BUTTON, size->height + padding.height); + *size = maxdim(GetStringBoundingBox(_server_visibility_dropdown[0]), GetStringBoundingBox(_server_visibility_dropdown[1])); + size->width += padding.width; + size->width = GetMinSizing(NWST_BUTTON, size->width); + size->height += padding.height; + size->height = GetMinSizing(NWST_BUTTON, size->height); break; } } @@ -1097,7 +1053,7 @@ struct NetworkStartServerWindow : public Window { break; case WID_NSS_CONNTYPE_BTN: // Connection type - ShowDropDownMenu(this, _connection_types_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN + ShowDropDownMenu(this, _server_visibility_dropdown, _settings_client.network.server_advertise, WID_NSS_CONNTYPE_BTN, 0, 0); // do it for widget WID_NSS_CONNTYPE_BTN break; case WID_NSS_CLIENTS_BTND: case WID_NSS_CLIENTS_BTNU: // Click on up/down button for number of clients @@ -1141,18 +1097,6 @@ struct NetworkStartServerWindow : public Window { ShowQueryString(STR_JUST_INT, STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS, 4, this, CS_NUMERAL, QSF_NONE); break; - case WID_NSS_LANGUAGE_BTN: { // Language - uint sel = 0; - for (uint i = 0; i < _language_dropdown.size() - 1; i++) { - if (_language_dropdown[i] == STR_NETWORK_LANG_ANY + _settings_client.network.server_lang) { - sel = i; - break; - } - } - ShowDropDownMenu(this, _language_dropdown.data(), sel, WID_NSS_LANGUAGE_BTN, 0, 0); - break; - } - case WID_NSS_GENERATE_GAME: // Start game _is_network_server = true; if (_ctrl_pressed) { @@ -1185,9 +1129,6 @@ struct NetworkStartServerWindow : public Window { case WID_NSS_CONNTYPE_BTN: _settings_client.network.server_advertise = (index != 0); break; - case WID_NSS_LANGUAGE_BTN: - _settings_client.network.server_lang = _language_dropdown[index] - STR_NETWORK_LANG_ANY; - break; default: NOT_REACHED(); } @@ -1251,12 +1192,8 @@ static const NWidgetPart _nested_network_start_server_window_widgets[] = { NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(10, 6, 10), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), - NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_ADVERTISED_LABEL, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_ADVERTISED_TOOLTIP), - EndContainer(), - NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), - NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN, STR_NULL), - NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_LANGUAGE_BTN), SetSizingType(NWST_BUTTON), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP), + NWidget(WWT_TEXT, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_LABEL), SetFill(1, 0), SetDataTip(STR_NETWORK_START_SERVER_VISIBILITY_LABEL, STR_NULL), + NWidget(WWT_DROPDOWN, COLOUR_LIGHT_BLUE, WID_NSS_CONNTYPE_BTN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NETWORK_START_SERVER_VISIBILITY_TOOLTIP), EndContainer(), NWidget(NWID_VERTICAL), SetPIP(0, 1, 0), NWidget(NWID_SPACER), SetFill(1, 1), @@ -1323,6 +1260,8 @@ static WindowDesc _network_start_server_window_desc( static void ShowNetworkStartServerWindow() { + if (!NetworkValidateClientName()) return; + DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY); @@ -1538,22 +1477,22 @@ struct NetworkLobbyWindow : public Window { case WID_NL_JOIN: // Join company /* Button can be clicked only when it is enabled. */ - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), this->company); + NetworkClientConnectGame(this->server->address, this->company); break; case WID_NL_NEW: // New company - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_NEW_COMPANY); + NetworkClientConnectGame(this->server->address, COMPANY_NEW_COMPANY); break; case WID_NL_SPECTATE: // Spectate game - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); + NetworkClientConnectGame(this->server->address, COMPANY_SPECTATOR); break; case WID_NL_REFRESH: // Refresh - NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info - NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data /* Clear the information so removed companies don't remain */ for (auto &company : this->company_info) company = {}; + + NetworkTCPQueryServer(this->server->address, true); break; } } @@ -1616,11 +1555,14 @@ static WindowDesc _network_lobby_window_desc( */ static void ShowNetworkLobbyWindow(NetworkGameList *ngl) { + if (!NetworkValidateClientName()) return; + DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_START); DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_GAME); - NetworkTCPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // company info - NetworkUDPQueryServer(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port)); // general data + strecpy(_settings_client.network.last_joined, ngl->address.GetAddressAsString(false).c_str(), lastof(_settings_client.network.last_joined)); + + NetworkTCPQueryServer(ngl->address, true); new NetworkLobbyWindow(&_network_lobby_window_desc, ngl); } @@ -1636,366 +1578,822 @@ NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company) return (lobby != nullptr && company < MAX_COMPANIES) ? &lobby->company_info[company] : nullptr; } +/** + * Get the game information for the lobby. + * @return the game info struct to write the (downloaded) data to. + */ +NetworkGameList *GetLobbyGameInfo() +{ + NetworkLobbyWindow *lobby = dynamic_cast(FindWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_LOBBY)); + return lobby != nullptr ? lobby->server : nullptr; +} + /* The window below gives information about the connected clients * and also makes able to kick them (if server) and stuff like that. */ extern void DrawCompanyIcon(CompanyID cid, int x, int y); -/** - * Prototype for ClientList actions. - * @param ci The information about the current client. - */ -typedef void ClientList_Action_Proc(const NetworkClientInfo *ci); - -static const NWidgetPart _nested_client_list_popup_widgets[] = { - NWidget(WWT_PANEL, COLOUR_GREY, WID_CLP_PANEL), EndContainer(), -}; - -static WindowDesc _client_list_popup_desc( - WDP_AUTO, nullptr, 0, 0, - WC_CLIENT_LIST_POPUP, WC_CLIENT_LIST, - 0, - _nested_client_list_popup_widgets, lengthof(_nested_client_list_popup_widgets) -); - -/* Here we start to define the options out of the menu */ -static void ClientList_Kick(const NetworkClientInfo *ci) -{ - NetworkServerKickClient(ci->client_id, nullptr); -} - -static void ClientList_Ban(const NetworkClientInfo *ci) -{ - NetworkServerKickOrBanIP(ci->client_id, true, nullptr); -} - -static void ClientList_SpeakToClient(const NetworkClientInfo *ci) -{ - ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, ci->client_id); -} - -static void ClientList_SpeakToCompany(const NetworkClientInfo *ci) -{ - ShowNetworkChatQueryWindow(DESTTYPE_TEAM, ci->client_playas); -} - -static void ClientList_SpeakToAll(const NetworkClientInfo *ci) -{ - ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); -} - -/** Popup selection window to chose an action to perform */ -struct NetworkClientListPopupWindow : Window { - /** Container for actions that can be executed. */ - struct ClientListAction { - StringID name; ///< Name of the action to execute - ClientList_Action_Proc *proc; ///< Action to execute - }; - - int sel_index; - ClientID client_id; - Point desired_location; - std::vector actions; ///< Actions to execute - - /** - * Add an action to the list of actions to execute. - * @param name the name of the action - * @param proc the procedure to execute for the action - */ - inline void AddAction(StringID name, ClientList_Action_Proc *proc) - { - this->actions.push_back({name, proc}); - } - - NetworkClientListPopupWindow(WindowDesc *desc, int x, int y, ClientID client_id) : - Window(desc), - sel_index(-1), client_id(client_id) - { - this->desired_location.x = x - GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - this->desired_location.y = y + GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) / 2; - - const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(client_id); - - if (_network_own_client_id != ci->client_id) { - this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, &ClientList_SpeakToClient); - } - - if (Company::IsValidID(ci->client_playas) || ci->client_playas == COMPANY_SPECTATOR) { - this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, &ClientList_SpeakToCompany); - } - this->AddAction(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, &ClientList_SpeakToAll); - - /* A server can kick clients (but not himself). */ - if (_network_server && _network_own_client_id != ci->client_id) { - this->AddAction(STR_NETWORK_CLIENTLIST_KICK, &ClientList_Kick); - this->AddAction(STR_NETWORK_CLIENTLIST_BAN, &ClientList_Ban); - } - - this->InitNested(client_id); - CLRBITS(this->flags, WF_WHITE_BORDER); - } - - Point OnInitialPosition(int16 sm_width, int16 sm_height, int window_number) override - { - return this->desired_location; - } - - void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override - { - Dimension d = *size; - for (const ClientListAction &action : this->actions) { - d = maxdim(GetStringBoundingBox(action.name), d); - } - - d.height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - d.height *= (uint)this->actions.size(); - d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; - d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; - *size = d; - } - - void DrawWidget(const Rect &r, int widget) const override - { - /* Draw the actions */ - int sel = this->sel_index; - int y = r.top + WD_FRAMERECT_TOP; - for (const ClientListAction &action : this->actions) { - TextColour colour; - if (sel-- == 0) { // Selected item, highlight it - GfxFillRect(r.left + 1, y, r.right - 1, y + GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL) - 1, PC_BLACK); - colour = TC_WHITE; - } else { - colour = TC_BLACK; - } - - DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, Center(y, GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL)), action.name, colour); - y += GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - } - } - - void OnMouseLoop() override - { - /* We selected an action */ - int index = (_cursor.pos.y - this->top - WD_FRAMERECT_TOP) / FONT_HEIGHT_NORMAL; - - if (_left_button_down) { - if (index == this->sel_index || index >= (int)this->actions.size()) return; - - this->sel_index = index; - this->SetDirty(); - } else { - if (index < (int)this->actions.size() && _cursor.pos.y >= this->top) { - const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id); - if (ci != nullptr) this->actions[index].proc(ci); - } - } - } - - void OnClick(Point pt, int widget, int click_count) override - { - int index = (pt.y - WD_FRAMERECT_TOP) / GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - - if (index >= 0 && index < (int)this->actions.size()) { - const NetworkClientInfo *ci = NetworkClientInfo::GetByClientID(this->client_id); - if (ci != NULL) this->actions[index].proc(ci); - } - - DeleteWindowByClass(WC_CLIENT_LIST_POPUP); - } -}; - -/** - * Show the popup (action list) - */ -static void PopupClientList(ClientID client_id, int x, int y) -{ - DeleteWindowByClass(WC_CLIENT_LIST_POPUP); - - if (NetworkClientInfo::GetByClientID(client_id) == nullptr) return; - - new NetworkClientListPopupWindow(&_client_list_popup_desc, x, y, client_id); -} - static const NWidgetPart _nested_client_list_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_GREY), - NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_COMPANY_LIST_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY, WID_CL_PANEL), SetMinimalSize(100, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 1), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY), + NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CL_SERVER_SELECTOR), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER, STR_NULL), SetPadding(4, 4, 0, 4), SetPIP(0, 2, 0), + NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_NAME, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(20, 0), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_SERVER_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_SERVER_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_SERVER_NAME_EDIT_TOOLTIP), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(20, 0), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_CL_SERVER_VISIBILITY), SetDataTip(STR_BLACK_STRING, STR_NETWORK_CLIENT_LIST_SERVER_VISIBILITY_TOOLTIP), + EndContainer(), + EndContainer(), + EndContainer(), + NWidget(WWT_FRAME, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER, STR_NULL), SetPadding(4, 4, 4, 4), SetPIP(0, 2, 0), + NWidget(NWID_HORIZONTAL), SetPIP(0, 3, 0), + NWidget(WWT_TEXT, COLOUR_GREY), SetMinimalTextLines(1, 0), SetDataTip(STR_NETWORK_CLIENT_LIST_PLAYER_NAME, STR_NULL), + NWidget(NWID_SPACER), SetMinimalSize(20, 0), + NWidget(WWT_TEXT, COLOUR_GREY, WID_CL_CLIENT_NAME), SetFill(1, 0), SetMinimalTextLines(1, 0), SetResize(1, 0), SetDataTip(STR_BLACK_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_TOOLTIP), SetAlignment(SA_VERT_CENTER | SA_RIGHT), + NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_CL_CLIENT_NAME_EDIT), SetMinimalSize(12, 14), SetDataTip(SPR_RENAME, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_EDIT_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_MATRIX, COLOUR_GREY, WID_CL_MATRIX), SetMinimalSize(180, 0), SetResize(1, 1), SetFill(1, 1), SetMatrixDataTip(1, 0, STR_NULL), SetScrollbar(WID_CL_SCROLLBAR), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_CL_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), + EndContainer(), + EndContainer(), + EndContainer(), }; static WindowDesc _client_list_desc( - WDP_AUTO, "list_clients", 0, 0, + WDP_AUTO, "list_clients", 220, 300, WC_CLIENT_LIST, WC_NONE, 0, _nested_client_list_widgets, lengthof(_nested_client_list_widgets) ); +/** + * The possibly entries in a DropDown for an admin. + * Client and companies are mixed; they just have to be unique. + */ +enum DropDownAdmin { + DD_CLIENT_ADMIN_KICK, + DD_CLIENT_ADMIN_BAN, + DD_COMPANY_ADMIN_RESET, + DD_COMPANY_ADMIN_UNLOCK, +}; + +/** + * Callback function for admin command to kick client. + * @param w The window which initiated the confirmation dialog. + * @param confirmed Iff the user pressed Yes. + */ +static void AdminClientKickCallback(Window *w, bool confirmed) +{ + if (confirmed) NetworkServerKickClient(_admin_client_id, nullptr); +} + +/** + * Callback function for admin command to ban client. + * @param w The window which initiated the confirmation dialog. + * @param confirmed Iff the user pressed Yes. + */ +static void AdminClientBanCallback(Window *w, bool confirmed) +{ + if (confirmed) NetworkServerKickOrBanIP(_admin_client_id, true, nullptr); +} + +/** + * Callback function for admin command to reset company. + * @param w The window which initiated the confirmation dialog. + * @param confirmed Iff the user pressed Yes. + */ +static void AdminCompanyResetCallback(Window *w, bool confirmed) +{ + if (confirmed) { + if (NetworkCompanyHasClients(_admin_company_id)) return; + DoCommandP(0, CCA_DELETE | _admin_company_id << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL); + } +} + +/** + * Callback function for admin command to unlock company. + * @param w The window which initiated the confirmation dialog. + * @param confirmed Iff the user pressed Yes. + */ +static void AdminCompanyUnlockCallback(Window *w, bool confirmed) +{ + if (confirmed) NetworkServerSetCompanyPassword(_admin_company_id, "", false); +} + +/** + * Button shown for either a company or client in the client-list. + * + * These buttons are dynamic and strongly depends on which company/client + * what buttons are available. This class allows dynamically creating them + * as the current Widget system does not. + */ +class ButtonCommon { +public: + SpriteID sprite; ///< The sprite to use on the button. + StringID tooltip; ///< The tooltip of the button. + Colours colour; ///< The colour of the button. + bool disabled; ///< Is the button disabled? + uint height; ///< Calculated height of the button. + uint width; ///< Calculated width of the button. + + ButtonCommon(SpriteID sprite, StringID tooltip, Colours colour, bool disabled = false) : + sprite(sprite), + tooltip(tooltip), + colour(colour), + disabled(disabled) + { + Dimension d = GetSpriteSize(sprite); + this->height = d.height + ScaleGUITrad(WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM); + this->width = d.width + ScaleGUITrad(WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT); + } + virtual ~ButtonCommon() {} + + /** + * OnClick handler for when the button is pressed. + */ + virtual void OnClick(struct NetworkClientListWindow *w, Point pt) = 0; +}; + +/** + * Template version of Button, with callback support. + */ +template +class Button : public ButtonCommon { +private: + typedef void (*ButtonCallback)(struct NetworkClientListWindow *w, Point pt, T id); ///< Callback function to call on click. + T id; ///< ID this button belongs to. + ButtonCallback proc; ///< Callback proc to call when button is pressed. + +public: + Button(SpriteID sprite, StringID tooltip, Colours colour, T id, ButtonCallback proc, bool disabled = false) : + ButtonCommon(sprite, tooltip, colour, disabled), + id(id), + proc(proc) + { + assert(proc != nullptr); + } + + void OnClick(struct NetworkClientListWindow *w, Point pt) override + { + if (this->disabled) return; + + this->proc(w, pt, this->id); + } +}; + +using CompanyButton = Button; +using ClientButton = Button; + /** * Main handle for clientlist */ struct NetworkClientListWindow : Window { - int selected_item; +private: + ClientListWidgets query_widget; ///< During a query this tracks what widget caused the query. + CompanyID join_company; ///< During query for company password, this stores what company we wanted to join. - uint server_client_width; - uint line_height; - uint line_width; - enum { MAX_ROWS = 6 }; // Split the list in two if it does not fit the screen + ClientID dd_client_id; ///< During admin dropdown, track which client this was for. + CompanyID dd_company_id; ///< During admin dropdown, track which company this was for. - Dimension icon_size; + Scrollbar *vscroll; ///< Vertical scrollbar of this window. + uint line_height; ///< Current lineheight of each entry in the matrix. + uint line_count; ///< Amount of lines in the matrix. + int hover_index; ///< Index of the current line we are hovering over, or -1 if none. + int player_self_index; ///< The line the current player is on. + int player_host_index; ///< The line the host is on. - NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) : - Window(desc), - selected_item(-1) + std::map>> buttons; ///< Per line which buttons are available. + + static const int CLIENT_OFFSET_LEFT = 12; ///< Offset of client entries compared to company entries. + + /** + * Chat button on a Company is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param company_id The company this button was assigned to. + */ + static void OnClickCompanyChat(NetworkClientListWindow *w, Point pt, CompanyID company_id) { - this->InitNested(window_number); + ShowNetworkChatQueryWindow(DESTTYPE_TEAM, company_id); } /** - * Finds the amount of clients and set the height correct + * Join button on a Company is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param company_id The company this button was assigned to. */ - bool CheckClientListHeight() + static void OnClickCompanyJoin(NetworkClientListWindow *w, Point pt, CompanyID company_id) { - int num = 0; + if (_network_server) { + NetworkServerDoMove(CLIENT_ID_SERVER, company_id); + MarkWholeScreenDirty(); + } else if (NetworkCompanyIsPassworded(company_id)) { + w->query_widget = WID_CL_COMPANY_JOIN; + w->join_company = company_id; + ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, w, CS_ALPHANUMERAL, QSF_PASSWORD); + } else { + NetworkClientRequestMove(company_id); + } + } - /* Should be replaced with a loop through all clients */ + /** + * Crete new company button is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param company_id The company this button was assigned to. + */ + static void OnClickCompanyNew(NetworkClientListWindow *w, Point pt, CompanyID company_id) + { + if (_network_server) { + DoCommandP(0, CCA_NEW, _network_own_client_id, CMD_COMPANY_CTRL); + } else { + NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company); + } + } + + /** + * Admin button on a Client is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param client_id The client this button was assigned to. + */ + static void OnClickClientAdmin(NetworkClientListWindow *w, Point pt, ClientID client_id) + { + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_KICK, DD_CLIENT_ADMIN_KICK, false)); + list.emplace_back(new DropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_BAN, DD_CLIENT_ADMIN_BAN, false)); + + Rect wi_rect; + wi_rect.left = pt.x; + wi_rect.right = pt.x; + wi_rect.top = pt.y; + wi_rect.bottom = pt.y; + + w->dd_client_id = client_id; + ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true, true); + } + + /** + * Admin button on a Company is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param company_id The company this button was assigned to. + */ + static void OnClickCompanyAdmin(NetworkClientListWindow *w, Point pt, CompanyID company_id) + { + DropDownList list; + list.emplace_back(new DropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_RESET, DD_COMPANY_ADMIN_RESET, NetworkCompanyHasClients(company_id))); + list.emplace_back(new DropDownListStringItem(STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_UNLOCK, DD_COMPANY_ADMIN_UNLOCK, !NetworkCompanyIsPassworded(company_id))); + + Rect wi_rect; + wi_rect.left = pt.x; + wi_rect.right = pt.x; + wi_rect.top = pt.y; + wi_rect.bottom = pt.y; + + w->dd_company_id = company_id; + ShowDropDownListAt(w, std::move(list), -1, WID_CL_MATRIX, wi_rect, COLOUR_GREY, true, true); + } + /** + * Chat button on a Client is clicked. + * @param w The instance of this window. + * @param pt The point where this button was clicked. + * @param client_id The client this button was assigned to. + */ + static void OnClickClientChat(NetworkClientListWindow *w, Point pt, ClientID client_id) + { + ShowNetworkChatQueryWindow(DESTTYPE_CLIENT, client_id); + } + + /** + * Part of RebuildList() to create the information for a single company. + * @param company_id The company to build the list for. + * @param own_ci The NetworkClientInfo of the client itself. + */ + void RebuildListCompany(CompanyID company_id, const NetworkClientInfo *own_ci) + { + ButtonCommon *chat_button = new CompanyButton(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat); + + if (_network_server) this->buttons[line_count].emplace_back(new CompanyButton(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR)); + this->buttons[line_count].emplace_back(chat_button); + if (own_ci->client_playas != company_id) this->buttons[line_count].emplace_back(new CompanyButton(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin)); + + this->line_count += 1; + + bool has_players = false; for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) { - if (ci->client_playas != COMPANY_INACTIVE_CLIENT) num++; + if (ci->client_playas != company_id) continue; + has_players = true; + + if (_network_server) this->buttons[line_count].emplace_back(new ClientButton(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id)); + if (_network_own_client_id != ci->client_id) this->buttons[line_count].emplace_back(new ClientButton(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat)); + + if (ci->client_id == _network_own_client_id) { + this->player_self_index = this->line_count; + } else if (ci->client_id == CLIENT_ID_SERVER) { + this->player_host_index = this->line_count; + } + + this->line_count += 1; } - int cols = 1 + (num - 1) / MAX_ROWS; - cols *= this->line_width; - num = std::min(num, MAX_ROWS); - num *= this->line_height; + /* Disable the chat button when there are players in this company. */ + chat_button->disabled = !has_players; + } - int diffx = (cols + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT) - (this->GetWidget(WID_CL_PANEL)->current_x); - int diffy = (num + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM) - (this->GetWidget(WID_CL_PANEL)->current_y); - /* If height is changed */ - if (diffx > 0 || diffy != 0) { // Width can only grow, also title bar can be wider than content - ResizeWindow(this, diffx, diffy, false); - return false; + /** + * Rebuild the list, meaning: calculate the lines needed and what buttons go on which line. + */ + void RebuildList() + { + const NetworkClientInfo *own_ci = NetworkClientInfo::GetByClientID(_network_own_client_id); + + this->buttons.clear(); + this->line_count = 0; + this->player_host_index = -1; + this->player_self_index = -1; + + /* As spectator, show a line to create a new company. */ + if (own_ci->client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) { + this->buttons[line_count].emplace_back(new CompanyButton(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew)); + this->line_count += 1; } - return true; + + if (own_ci->client_playas != COMPANY_SPECTATOR) { + this->RebuildListCompany(own_ci->client_playas, own_ci); + } + + /* Companies */ + for (const Company *c : Company::Iterate()) { + if (c->index == own_ci->client_playas) continue; + + this->RebuildListCompany(c->index, own_ci); + } + + /* Spectators */ + this->RebuildListCompany(COMPANY_SPECTATOR, own_ci); + + this->vscroll->SetCount(this->line_count); + } + + /** + * Get the button at a specific point on the WID_CL_MATRIX. + * @param pt The point to look for a button. + * @return The button or a nullptr if there was none. + */ + ButtonCommon *GetButtonAtPoint(Point pt) + { + uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX); + NWidgetBase *widget_matrix = this->GetWidget(WID_CL_MATRIX); + + bool rtl = _current_text_dir == TD_RTL; + uint x = rtl ? (uint)widget_matrix->pos_x + WD_FRAMERECT_LEFT : widget_matrix->current_x - WD_FRAMERECT_RIGHT; + + /* Find the buttons for this row. */ + auto button_find = this->buttons.find(index); + if (button_find == this->buttons.end()) return nullptr; + + /* Check if we want to display a tooltip for any of the buttons. */ + for (auto &button : button_find->second) { + uint left = rtl ? x : x - button->width; + uint right = rtl ? x + button->width : x; + + if (IsInsideMM(pt.x, left, right)) { + return button.get(); + } + + int width = button->width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + x += rtl ? width : -width; + } + + return nullptr; + } + +public: + NetworkClientListWindow(WindowDesc *desc, WindowNumber window_number) : + Window(desc), + hover_index(-1), + player_self_index(-1), + player_host_index(-1) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR); + this->OnInvalidateData(); + this->FinishInitNested(window_number); + } + + void OnInvalidateData(int data = 0, bool gui_scope = true) override + { + this->RebuildList(); + + /* Currently server information is not sync'd to clients, so we cannot show it on clients. */ + this->GetWidget(WID_CL_SERVER_SELECTOR)->SetDisplayedPlane(_network_server ? 0 : SZSP_HORIZONTAL); } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { - if (widget != WID_CL_PANEL) return; + switch (widget) { + case WID_CL_SERVER_VISIBILITY: + *size = maxdim(GetStringBoundingBox(_server_visibility_dropdown[0]), GetStringBoundingBox(_server_visibility_dropdown[1])); + size->width += padding.width; + size->height += padding.height; + break; - this->server_client_width = std::max(GetStringBoundingBox(STR_NETWORK_SERVER).width, GetStringBoundingBox(STR_NETWORK_CLIENT).width) + WD_FRAMERECT_RIGHT; - this->icon_size = GetSpriteSize(SPR_COMPANY_ICON); - this->line_height = std::max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL); - this->line_height = GetMinSizing(NWST_STEP, this->line_height); + case WID_CL_MATRIX: { + uint height = std::max({GetSpriteSize(SPR_COMPANY_ICON).height, GetSpriteSize(SPR_JOIN).height, GetSpriteSize(SPR_ADMIN).height, GetSpriteSize(SPR_CHAT).height}); + height += ScaleGUITrad(WD_FRAMERECT_TOP) + ScaleGUITrad(WD_FRAMERECT_BOTTOM); + this->line_height = std::max(height, (uint)FONT_HEIGHT_NORMAL) + ScaleGUITrad(WD_MATRIX_TOP + WD_MATRIX_BOTTOM); - uint width = 100; // Default width - for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) { - width = std::max(width, GetStringBoundingBox(ci->client_name).width); + resize->width = 1; + resize->height = this->line_height; + fill->height = this->line_height; + size->height = std::max(size->height, 5 * this->line_height); + break; + } } - - this->line_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT + width + WD_FRAMERECT_RIGHT; } - void OnPaint() override + void OnResize() override { - /* Check if we need to reset the height */ - if (!this->CheckClientListHeight()) return; - - this->DrawWidgets(); + this->vscroll->SetCapacityFromWidget(this, WID_CL_MATRIX); } - void DrawWidget(const Rect &r, int widget) const override + void SetStringParameters(int widget) const override { - if (widget != WID_CL_PANEL) return; + switch (widget) { + case WID_CL_SERVER_NAME: + SetDParamStr(0, _settings_client.network.server_name); + break; - bool rtl = _current_text_dir == TD_RTL; - int icon_offset = (this->line_height - icon_size.height) / 2; - int text_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2; + case WID_CL_SERVER_VISIBILITY: + SetDParam(0, _server_visibility_dropdown[_settings_client.network.server_advertise]); + break; - uint y = r.top + WD_FRAMERECT_TOP; - uint left = r.left + WD_FRAMERECT_LEFT; - uint right = r.right - WD_FRAMERECT_RIGHT; - uint type_icon_width = this->server_client_width + this->icon_size.width + WD_FRAMERECT_LEFT; - - int i = 0; - for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) { - uint type_left = rtl ? right - this->server_client_width : left; - uint type_right = rtl ? right : left + this->server_client_width - 1; - uint icon_left = rtl ? right - type_icon_width + WD_FRAMERECT_LEFT : left + this->server_client_width; - uint name_left = rtl ? right - this->line_width : left + type_icon_width; - uint name_right = rtl ? right - type_icon_width : left + this->line_width; - TextColour colour; - if (this->selected_item == i++) { // Selected item, highlight it - if (rtl) { - GfxFillRect(right - this->line_width, y, right + WD_FRAMERECT_RIGHT - 1, y + this->line_height - 1, PC_BLACK); - } else { - GfxFillRect(left - WD_FRAMERECT_LEFT + 1, y, left + this->line_width, y + this->line_height - 1, PC_BLACK); - } - colour = TC_WHITE; - } else { - colour = TC_BLACK; - } - - if (ci->client_id == CLIENT_ID_SERVER) { - DrawString(type_left, type_right, y + text_offset, STR_NETWORK_SERVER, colour); - } else { - DrawString(type_left, type_right, y + text_offset, STR_NETWORK_CLIENT, colour); - } - - /* Filter out spectators */ - if (Company::IsValidID(ci->client_playas)) DrawCompanyIcon(ci->client_playas, icon_left, y + icon_offset); - - DrawString(name_left, name_right, y + text_offset, ci->client_name, colour); - - y += line_height; - if (i % MAX_ROWS == 0 && i > 1) { - y = r.top + WD_FRAMERECT_TOP; - if (rtl) { - right -= this->line_width; - } else { - left += this->line_width; - } - } + case WID_CL_CLIENT_NAME: + SetDParamStr(0, _settings_client.network.client_name); + break; } } void OnClick(Point pt, int widget, int click_count) override { - /* Show the popup with option */ - if (this->selected_item != -1) { - int client_no = this->selected_item; - for (NetworkClientInfo *ci : NetworkClientInfo::Iterate()) { - if (client_no == 0) { - PopupClientList(ci->client_id, pt.x + this->left, pt.y + this->top); - break; - } - client_no--; + switch (widget) { + case WID_CL_SERVER_NAME_EDIT: + if (!_network_server) break; + + this->query_widget = WID_CL_SERVER_NAME_EDIT; + SetDParamStr(0, _settings_client.network.server_name); + ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_SERVER_NAME_QUERY_CAPTION, NETWORK_NAME_LENGTH, this, CS_ALPHANUMERAL, QSF_LEN_IN_CHARS); + break; + + case WID_CL_CLIENT_NAME_EDIT: + this->query_widget = WID_CL_CLIENT_NAME_EDIT; + SetDParamStr(0, _settings_client.network.client_name); + ShowQueryString(STR_JUST_RAW_STRING, STR_NETWORK_CLIENT_LIST_PLAYER_NAME_QUERY_CAPTION, NETWORK_CLIENT_NAME_LENGTH, this, CS_ALPHANUMERAL, QSF_LEN_IN_CHARS); + break; + + case WID_CL_SERVER_VISIBILITY: + if (!_network_server) break; + + ShowDropDownMenu(this, _server_visibility_dropdown, _settings_client.network.server_advertise, WID_CL_SERVER_VISIBILITY, 0, 0); + break; + + case WID_CL_MATRIX: { + ButtonCommon *button = this->GetButtonAtPoint(pt); + if (button == nullptr) break; + + button->OnClick(this, pt); + break; } } } - void OnMouseOver(Point pt, int widget) override + bool OnTooltip(Point pt, int widget, TooltipCloseCondition close_cond) override { - /* -1 means we left the current window */ - if (pt.y == -1) { - this->selected_item = -1; + switch (widget) { + case WID_CL_MATRIX: { + int index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX); + + bool rtl = _current_text_dir == TD_RTL; + NWidgetBase *widget_matrix = this->GetWidget(WID_CL_MATRIX); + + Dimension d = GetSpriteSize(SPR_COMPANY_ICON); + uint text_left = widget_matrix->pos_x + (rtl ? (uint)WD_FRAMERECT_LEFT : d.width + 8); + uint text_right = widget_matrix->pos_x + widget_matrix->current_x - (rtl ? d.width + 8 : (uint)WD_FRAMERECT_RIGHT); + + Dimension d2 = GetSpriteSize(SPR_PLAYER_SELF); + uint offset_x = CLIENT_OFFSET_LEFT - d2.width - 3; + + uint player_icon_x = rtl ? text_right - offset_x - d2.width : text_left + offset_x; + + if (IsInsideMM(pt.x, player_icon_x, player_icon_x + d2.width)) { + if (index == this->player_self_index) { + GuiShowTooltips(this, STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP, 0, nullptr, close_cond); + return true; + } else if (index == this->player_host_index) { + GuiShowTooltips(this, STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP, 0, nullptr, close_cond); + return true; + } + } + + ButtonCommon *button = this->GetButtonAtPoint(pt); + if (button == nullptr) return false; + + GuiShowTooltips(this, button->tooltip, 0, nullptr, close_cond); + return true; + }; + } + + return false; + } + + void OnDropdownClose(Point pt, int widget, int index, bool instant_close) override + { + /* If you close the dropdown outside the list, don't take any action. */ + if (widget == WID_CL_MATRIX) return; + + Window::OnDropdownClose(pt, widget, index, instant_close); + } + + void OnDropdownSelect(int widget, int index) override + { + switch (widget) { + case WID_CL_SERVER_VISIBILITY: + if (!_network_server) break; + + _settings_client.network.server_advertise = (index != 0); + break; + + case WID_CL_MATRIX: { + StringID text = STR_NULL; + QueryCallbackProc *callback = nullptr; + + switch (index) { + case DD_CLIENT_ADMIN_KICK: + _admin_client_id = this->dd_client_id; + text = STR_NETWORK_CLIENT_LIST_ASK_CLIENT_KICK; + callback = AdminClientKickCallback; + SetDParamStr(0, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name); + break; + + case DD_CLIENT_ADMIN_BAN: + _admin_client_id = this->dd_client_id; + text = STR_NETWORK_CLIENT_LIST_ASK_CLIENT_BAN; + callback = AdminClientBanCallback; + SetDParamStr(0, NetworkClientInfo::GetByClientID(_admin_client_id)->client_name); + break; + + case DD_COMPANY_ADMIN_RESET: + _admin_company_id = this->dd_company_id; + text = STR_NETWORK_CLIENT_LIST_ASK_COMPANY_RESET; + callback = AdminCompanyResetCallback; + SetDParam(0, _admin_company_id); + break; + + case DD_COMPANY_ADMIN_UNLOCK: + _admin_company_id = this->dd_company_id; + text = STR_NETWORK_CLIENT_LIST_ASK_COMPANY_UNLOCK; + callback = AdminCompanyUnlockCallback; + SetDParam(0, _admin_company_id); + break; + + default: + NOT_REACHED(); + } + + assert(text != STR_NULL); + assert(callback != nullptr); + + /* Always ask confirmation for all admin actions. */ + ShowQuery(STR_NETWORK_CLIENT_LIST_ASK_CAPTION, text, this, callback); + + break; + } + + default: + NOT_REACHED(); + } + + this->SetDirty(); + } + + void OnQueryTextFinished(char *str) override + { + if (str == nullptr) return; + + switch (this->query_widget) { + default: NOT_REACHED(); + + case WID_CL_SERVER_NAME_EDIT: { + if (!_network_server) break; + + uint index; + GetSettingFromName("network.server_name", &index); + SetSettingValue(index, StrEmpty(str) ? "Unnamed Server" : str); + this->InvalidateData(); + break; + } + + case WID_CL_CLIENT_NAME_EDIT: { + if (!NetworkValidateClientName(str)) break; + + uint index; + GetSettingFromName("network.client_name", &index); + SetSettingValue(index, str); + this->InvalidateData(); + break; + } + + case WID_CL_COMPANY_JOIN: + NetworkClientRequestMove(this->join_company, str); + break; + } + } + + /** + * Draw the buttons for a single line in the matrix. + * + * The x-position in RTL is the most left or otherwise the most right pixel + * we can draw the buttons from. + * + * @param x The x-position to start with the buttons. Updated during this function. + * @param y The y-position to start with the buttons. + * @param buttons The buttons to draw. + */ + void DrawButtons(uint &x, uint y, const std::vector> &buttons) const + { + for (auto &button : buttons) { + bool rtl = _current_text_dir == TD_RTL; + + uint left = rtl ? x : x - button->width; + uint right = rtl ? x + button->width : x; + + int offset = std::max(0, ((int)(this->line_height + 1) - (int)button->height) / 2); + + DrawFrameRect(left, y + offset, right, y + offset + button->height, button->colour, FR_NONE); + DrawSprite(button->sprite, PAL_NONE, left + ScaleGUITrad(WD_FRAMERECT_LEFT), y + offset + ScaleGUITrad(WD_FRAMERECT_TOP)); + if (button->disabled) { + GfxFillRect(left + 1, y + offset + 1, right - 1, y + offset + button->height - 1, _colour_gradient[button->colour & 0xF][2], FILLRECT_CHECKER); + } + + int width = button->width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + x += rtl ? width : -width; + } + } + + /** + * Draw a company and its clients on the matrix. + * @param company_id The company to draw. + * @param left The most left pixel of the line. + * @param right The most right pixel of the line. + * @param top The top of the first line. + * @param line The Nth line we are drawing. Updated during this function. + */ + void DrawCompany(CompanyID company_id, uint left, uint right, uint top, uint &line) const + { + bool rtl = _current_text_dir == TD_RTL; + int text_y_offset = std::max(0, ((int)(this->line_height + 1) - (int)FONT_HEIGHT_NORMAL) / 2) + WD_MATRIX_BOTTOM; + + Dimension d = GetSpriteSize(SPR_COMPANY_ICON); + int offset = std::max(0, ((int)(this->line_height + 1) - (int)d.height) / 2); + + uint text_left = left + (rtl ? (uint)WD_FRAMERECT_LEFT : d.width + 8); + uint text_right = right - (rtl ? d.width + 8 : (uint)WD_FRAMERECT_RIGHT); + + uint line_start = this->vscroll->GetPosition(); + uint line_end = line_start + this->vscroll->GetCapacity(); + + uint y = top + (this->line_height * (line - line_start)); + + /* Draw the company line (if in range of scrollbar). */ + if (IsInsideMM(line, line_start, line_end)) { + uint x = rtl ? text_left : text_right; + + /* If there are buttons for this company, draw them. */ + auto button_find = this->buttons.find(line); + if (button_find != this->buttons.end()) { + this->DrawButtons(x, y, button_find->second); + } + + if (company_id == COMPANY_SPECTATOR) { + DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, rtl ? right - d.width - 4 : left + 4, y + offset); + DrawString(rtl ? x : text_left, rtl ? text_right : x, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER); + } else if (company_id == COMPANY_NEW_COMPANY) { + DrawSprite(SPR_COMPANY_ICON, PALETTE_TO_GREY, rtl ? right - d.width - 4 : left + 4, y + offset); + DrawString(rtl ? x : text_left, rtl ? text_right : x, y + text_y_offset, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE); + } else { + DrawCompanyIcon(company_id, rtl ? right - d.width - 4 : left + 4, y + offset); + + SetDParam(0, company_id); + SetDParam(1, company_id); + DrawString(rtl ? x : text_left, rtl ? text_right : x, y + text_y_offset, STR_COMPANY_NAME, TC_SILVER); + } + } + + y += this->line_height; + line++; + + for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) { + if (ci->client_playas != company_id) continue; + + /* Draw the player line (if in range of scrollbar). */ + if (IsInsideMM(line, line_start, line_end)) { + uint x = rtl ? text_left : text_right; + + /* If there are buttons for this client, draw them. */ + auto button_find = this->buttons.find(line); + if (button_find != this->buttons.end()) { + this->DrawButtons(x, y, button_find->second); + } + + SpriteID player_icon = 0; + if (ci->client_id == _network_own_client_id) { + player_icon = SPR_PLAYER_SELF; + } else if (ci->client_id == CLIENT_ID_SERVER) { + player_icon = SPR_PLAYER_HOST; + } + + if (player_icon != 0) { + Dimension d2 = GetSpriteSize(player_icon); + uint offset_x = CLIENT_OFFSET_LEFT - 3; + int offset_y = std::max(0, ((int)(this->line_height + 1) - (int)d2.height) / 2); + DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? text_right - offset_x : text_left + offset_x - d2.width, y + offset_y); + } + + SetDParamStr(0, ci->client_name); + DrawString(rtl ? x : text_left + CLIENT_OFFSET_LEFT, rtl ? text_right - CLIENT_OFFSET_LEFT : x, y + text_y_offset, STR_JUST_RAW_STRING, TC_BLACK); + } + + y += this->line_height; + line++; + } + } + + void DrawWidget(const Rect &r, int widget) const override + { + switch (widget) { + case WID_CL_MATRIX: { + uint line = 0; + + if (this->hover_index >= 0) { + uint offset = this->hover_index * this->line_height; + GfxFillRect(r.left + 2, r.top + offset, r.right - 1, r.top + offset + this->line_height - 1, GREY_SCALE(9)); + } + + NetworkClientInfo *own_ci = NetworkClientInfo::GetByClientID(_network_own_client_id); + if (own_ci->client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) { + this->DrawCompany(COMPANY_NEW_COMPANY, r.left, r.right, r.top, line); + } + + if (own_ci->client_playas != COMPANY_SPECTATOR) { + this->DrawCompany(own_ci->client_playas, r.left, r.right, r.top, line); + } + + for (const Company *c : Company::Iterate()) { + if (own_ci->client_playas == c->index) continue; + this->DrawCompany(c->index, r.left, r.right, r.top, line); + } + + /* Specators */ + this->DrawCompany(COMPANY_SPECTATOR, r.left, r.right, r.top, line); + + break; + } + } + } + + virtual void OnMouseLoop() override + { + if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) != WID_CL_MATRIX) { + this->hover_index = -1; this->SetDirty(); return; } - /* Find the new selected item (if any) */ - pt.y -= this->GetWidget(WID_CL_PANEL)->pos_y; - int item = -1; - if (IsInsideMM(pt.y, WD_FRAMERECT_TOP, this->GetWidget(WID_CL_PANEL)->current_y - WD_FRAMERECT_BOTTOM)) { - item = (pt.y - WD_FRAMERECT_TOP) / this->line_height + ((pt.x - WD_FRAMERECT_LEFT) / this->line_width) * MAX_ROWS; + NWidgetBase *nwi = this->GetWidget(WID_CL_MATRIX); + int y = _cursor.pos.y - this->top - nwi->pos_y - 2; + int index = y / this->line_height; + + if (index != this->hover_index) { + this->hover_index = index; + this->SetDirty(); } - - /* It did not change.. no update! */ - if (item == this->selected_item) return; - this->selected_item = item; - - /* Repaint */ - this->SetDirty(); } }; diff --git a/src/network/network_gui.h b/src/network/network_gui.h index 5124955626..e4ccf4e783 100644 --- a/src/network/network_gui.h +++ b/src/network/network_gui.h @@ -11,9 +11,11 @@ #define NETWORK_GUI_H #include "../company_type.h" +#include "../date_type.h" #include "../economy_type.h" #include "../window_type.h" #include "network_type.h" +#include "network_gamelist.h" void ShowNetworkNeedPassword(NetworkPasswordType npt); void ShowNetworkChatQueryWindow(DestType type, int dest); @@ -36,5 +38,6 @@ struct NetworkCompanyInfo : NetworkCompanyStats { }; NetworkCompanyInfo *GetLobbyCompanyInfo(CompanyID company); +NetworkGameList *GetLobbyGameInfo(); #endif /* NETWORK_GUI_H */ diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 8cae502e10..1fba1228a5 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -62,47 +62,6 @@ enum NetworkJoinStatus { NETWORK_JOIN_STATUS_END, }; -/** Language ids for server_lang and client_lang. Do NOT modify the order. */ -enum NetworkLanguage { - NETLANG_ANY = 0, - NETLANG_ENGLISH, - NETLANG_GERMAN, - NETLANG_FRENCH, - NETLANG_BRAZILIAN, - NETLANG_BULGARIAN, - NETLANG_CHINESE, - NETLANG_CZECH, - NETLANG_DANISH, - NETLANG_DUTCH, - NETLANG_ESPERANTO, - NETLANG_FINNISH, - NETLANG_HUNGARIAN, - NETLANG_ICELANDIC, - NETLANG_ITALIAN, - NETLANG_JAPANESE, - NETLANG_KOREAN, - NETLANG_LITHUANIAN, - NETLANG_NORWEGIAN, - NETLANG_POLISH, - NETLANG_PORTUGUESE, - NETLANG_ROMANIAN, - NETLANG_RUSSIAN, - NETLANG_SLOVAK, - NETLANG_SLOVENIAN, - NETLANG_SPANISH, - NETLANG_SWEDISH, - NETLANG_TURKISH, - NETLANG_UKRAINIAN, - NETLANG_AFRIKAANS, - NETLANG_CROATIAN, - NETLANG_CATALAN, - NETLANG_ESTONIAN, - NETLANG_GALICIAN, - NETLANG_GREEK, - NETLANG_LATVIAN, - NETLANG_COUNT -}; - extern uint32 _frame_counter_server; // The frame_counter of the server, if in network-mode extern uint32 _frame_counter_max; // To where we may go with our clients extern uint32 _frame_counter; @@ -126,22 +85,15 @@ extern uint32 _network_join_bytes_total; extern uint8 _network_reconnect; -extern bool _network_udp_server; -extern uint16 _network_udp_broadcast; - -extern uint8 _network_advertise_retries; - extern CompanyMask _network_company_passworded; -void NetworkTCPQueryServer(NetworkAddress address); +void NetworkTCPQueryServer(NetworkAddress address, bool request_company_info = false); void GetBindAddresses(NetworkAddressList *addresses, uint16 port); -void NetworkAddServer(const char *b); +struct NetworkGameList *NetworkAddServer(const std::string &connection_string); void NetworkRebuildHostList(); void UpdateNetworkGameWindow(); -bool IsNetworkCompatibleVersion(const char *version); - /* From network_command.cpp */ /** * Everything we need to know about a command to be able to execute it. @@ -160,11 +112,15 @@ void NetworkExecuteLocalCommandQueue(); void NetworkFreeLocalCommandQueue(); void NetworkSyncCommandQueue(NetworkClientSocket *cs); -void NetworkError(StringID error_string); +void ShowNetworkError(StringID error_string); void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send, const char *name, const char *str = "", int64 data = 0); uint NetworkCalculateLag(const NetworkClientSocket *cs); StringID GetNetworkErrorMsg(NetworkErrorCode err); bool NetworkFindName(char *new_name, const char *last); const char *GenerateCompanyPasswordHash(const char *password, const char *password_server_id, uint32 password_game_seed); +bool NetworkClientConnectGame(NetworkAddress &address, CompanyID join_as, const char *join_server_password = nullptr, const char *join_company_password = nullptr); +NetworkAddress ParseConnectionString(const std::string &connection_string, int default_port); +NetworkAddress ParseGameConnectionString(CompanyID *company, const std::string &connection_string, int default_port); + #endif /* NETWORK_INTERNAL_H */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 9e4d0d88f9..fd69a8d37a 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -10,6 +10,7 @@ #include "../stdafx.h" #include "../strings_func.h" #include "../date_func.h" +#include "core/game_info.h" #include "network_admin.h" #include "network_server.h" #include "network_udp.h" @@ -79,9 +80,7 @@ struct PacketWriter : SaveFilter { /* This must all wait until the Destroy function is called. */ while (this->packets != nullptr) { - Packet *p = this->packets->next; - delete this->packets; - this->packets = p; + delete Packet::PopFromQueue(&this->packets); } delete this->current; @@ -114,29 +113,27 @@ struct PacketWriter : SaveFilter { } /** - * Checks whether there are packets. - * It's not 100% threading safe, but this is only asked for when checking - * whether there still is something to send. Then another call will be made - * to actually get the Packet, which will be the only one popping packets - * and thus eventually setting this on false. + * Transfer all packets from here to the network's queue while holding + * the lock on our mutex. + * @param socket The network socket to write to. + * @return True iff the last packet of the map has been sent. */ - bool HasPackets() + bool TransferToNetworkQueue(ServerNetworkGameSocketHandler *socket) { - return this->packets != nullptr; - } + /* Unsafe check for the queue being empty or not. */ + if (this->packets == nullptr) return false; - /** - * Pop a single created packet from the queue with packets. - */ - Packet *PopPacket() - { std::lock_guard lock(this->mutex); - Packet *p = this->packets; - this->packets = p->next; - p->next = nullptr; + while (this->packets != nullptr) { + Packet *p = Packet::PopFromQueue(&this->packets); + bool last_packet = p->GetPacketType() == PACKET_SERVER_MAP_DONE; + socket->SendPacket(p); - return p; + if (last_packet) return true; + } + + return false; } /** Append the current packet to the queue. */ @@ -144,12 +141,7 @@ struct PacketWriter : SaveFilter { { if (this->current == nullptr) return; - Packet **p = &this->packets; - while (*p != nullptr) { - p = &(*p)->next; - } - *p = this->current; - + Packet::AddToQueue(&this->packets, this->current); this->current = nullptr; } @@ -158,7 +150,8 @@ struct PacketWriter : SaveFilter { { if (this->current == nullptr) return; - this->current->next = this->packets; + /* Reversed from AppendQueue so the queue gets added to the current one. */ + Packet::AddToQueue(&this->current, this->packets); this->packets = this->current; this->current = nullptr; } @@ -168,20 +161,18 @@ struct PacketWriter : SaveFilter { /* We want to abort the saving when the socket is closed. */ if (this->cs == nullptr) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); - if (this->current == nullptr) this->current = new Packet(PACKET_SERVER_MAP_DATA); + if (this->current == nullptr) this->current = new Packet(PACKET_SERVER_MAP_DATA, TCP_MTU); std::lock_guard lock(this->mutex); byte *bufe = buf + size; while (buf != bufe) { - size_t to_write = std::min(SEND_MTU - this->current->size, bufe - buf); - memcpy(this->current->buffer + this->current->size, buf, to_write); - this->current->size += (PacketSize)to_write; - buf += to_write; + size_t written = this->current->Send_bytes(buf, bufe); + buf += written; - if (this->current->size == SEND_MTU) { + if (!this->current->CanWriteToPacket(1)) { this->AppendQueue(); - if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA); + if (buf != bufe) this->current = new Packet(PACKET_SERVER_MAP_DATA, TCP_MTU); } } @@ -249,7 +240,7 @@ Packet *ServerNetworkGameSocketHandler::ReceivePacket() /* We can receive a packet, so try that and if needed account for * the amount of received data. */ Packet *p = this->NetworkTCPSocketHandler::ReceivePacket(); - if (p != nullptr) this->receive_limit -= p->size; + if (p != nullptr) this->receive_limit -= p->Size(); return p; } @@ -299,14 +290,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta extern byte _network_clients_connected; _network_clients_connected--; - DeleteWindowById(WC_CLIENT_LIST_POPUP, this->client_id); - SetWindowDirty(WC_CLIENT_LIST, 0); - this->SendPackets(true); delete this->GetInfo(); delete this; + InvalidateWindowData(WC_CLIENT_LIST, 0); + return status; } @@ -363,6 +353,20 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendClientInfo(NetworkClientIn return NETWORK_RECV_STATUS_OKAY; } +/** Send the client information about the server. */ +NetworkRecvStatus ServerNetworkGameSocketHandler::SendGameInfo() +{ + NetworkGameInfo ngi; + FillNetworkGameInfo(ngi); + + Packet *p = new Packet(PACKET_SERVER_GAME_INFO); + SerializeNetworkGameInfo(p, &ngi); + + this->SendPacket(p); + + return NETWORK_RECV_STATUS_OKAY; +} + /** Send the client information about the companies. */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo() { @@ -456,7 +460,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err } for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { - if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { + if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) { /* Some errors we filter to a more general error. Clients don't have to know the real * reason a joining failed. */ if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION) { @@ -488,7 +492,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck() p->Send_uint8 (grf_count); for (c = _grfconfig; c != nullptr; c = c->next) { - if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident); + if (!HasBit(c->flags, GCF_STATIC)) SerializeGRFIdentifier(p, &c->ident); } this->SendPacket(p); @@ -549,7 +553,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendWelcome() /* Transmit info about all the active clients */ for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { - if (new_cs != this && new_cs->status > STATUS_AUTHORIZED) { + if (new_cs != this && new_cs->status >= STATUS_AUTHORIZED) { this->SendClientInfo(new_cs->GetInfo()); } } @@ -605,8 +609,6 @@ void ServerNetworkGameSocketHandler::CheckNextClientToSendMap(NetworkClientSocke /** This sends the map to the client */ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() { - static uint sent_packets; // How many packets we did send successfully last time - if (this->status < STATUS_AUTHORIZED) { /* Illegal call, return error and ignore the packet */ return this->SendError(NETWORK_ERROR_NOT_AUTHORIZED); @@ -626,28 +628,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() this->last_frame = _frame_counter; this->last_frame_server = _frame_counter; - sent_packets = 4; // We start with trying 4 packets - /* Make a dump of the current game */ if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed"); } if (this->status == STATUS_MAP) { - bool last_packet = false; - bool has_packets = false; - - for (uint i = 0; (has_packets = this->savegame->HasPackets()) && i < sent_packets; i++) { - Packet *p = this->savegame->PopPacket(); - last_packet = p->buffer[2] == PACKET_SERVER_MAP_DONE; - - this->SendPacket(p); - - if (last_packet) { - /* There is no more data, so break the for */ - break; - } - } - + bool last_packet = this->savegame->TransferToNetworkQueue(this); if (last_packet) { /* Done reading, make sure saving is done as well */ this->savegame->Destroy(); @@ -659,25 +645,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap() this->CheckNextClientToSendMap(); } - - switch (this->SendPackets()) { - case SPS_CLOSED: - return NETWORK_RECV_STATUS_CONN_LOST; - - case SPS_ALL_SENT: - /* All are sent, increase the sent_packets */ - if (has_packets) sent_packets *= 2; - break; - - case SPS_PARTLY_SENT: - /* Only a part is sent; leave the transmission state. */ - break; - - case SPS_NONE_SENT: - /* Not everything is sent, decrease the sent_packets */ - if (sent_packets > 1) sent_packets /= 2; - break; - } } return NETWORK_RECV_STATUS_OKAY; } @@ -875,6 +842,11 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendConfigUpdate() * DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p ************/ +NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_GAME_INFO(Packet *p) +{ + return this->SendGameInfo(); +} + NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_COMPANY_INFO(Packet *p) { return this->SendCompanyInfo(); @@ -910,7 +882,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) char name[NETWORK_CLIENT_NAME_LENGTH]; CompanyID playas; - NetworkLanguage client_lang; char client_revision[NETWORK_REVISION_LENGTH]; p->Recv_string(client_revision, sizeof(client_revision)); @@ -924,7 +895,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) p->Recv_string(name, sizeof(name)); playas = (Owner)p->Recv_uint8(); - client_lang = (NetworkLanguage)p->Recv_uint8(); if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; @@ -947,8 +917,12 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) break; } - /* We need a valid name.. make it Player */ - if (StrEmpty(name)) strecpy(name, "Player", lastof(name)); + if (!NetworkIsValidClientName(name)) { + /* An invalid client name was given. However, the client ensures the name + * is valid before it is sent over the network, so something went horribly + * wrong. This is probably someone trying to troll us. */ + return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME); + } if (!NetworkFindName(name, lastof(name))) { // Change name if duplicate /* We could not create a name for this client */ @@ -961,7 +935,6 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_JOIN(Packet *p) ci->join_date = _date; strecpy(ci->client_name, name, lastof(ci->client_name)); ci->client_playas = playas; - ci->client_lang = client_lang; DEBUG(desync, 1, "client: %08x; %02x; %02x; %02x", _date, _date_fract, (int)ci->client_playas, (int)ci->index); /* Make sure companies to which people try to join are not autocleaned */ @@ -1054,6 +1027,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet * this->GetClientName(client_name, lastof(client_name)); NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, nullptr, this->client_id); + InvalidateWindowData(WC_CLIENT_LIST, 0); /* Mark the client as pre-active, and wait for an ACK * so we know he is done loading and in sync with us */ @@ -1068,7 +1042,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet * this->last_frame_server = _frame_counter; for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { - if (new_cs->status > STATUS_AUTHORIZED) { + if (new_cs->status >= STATUS_AUTHORIZED) { new_cs->SendClientInfo(this->GetInfo()); new_cs->SendJoin(this->client_id); } @@ -1178,7 +1152,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid); for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { - if (new_cs->status > STATUS_AUTHORIZED) { + if (new_cs->status >= STATUS_AUTHORIZED) { new_cs->SendErrorQuit(this->client_id, errorno); } } @@ -1204,7 +1178,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_QUIT(Packet *p) NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, STR_NETWORK_MESSAGE_CLIENT_LEAVING); for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { - if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { + if (new_cs->status >= STATUS_AUTHORIZED && new_cs != this) { new_cs->SendQuit(this->client_id); } } @@ -1444,6 +1418,13 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_SET_NAME(Packet if (this->HasClientQuit()) return NETWORK_RECV_STATUS_CONN_LOST; if (ci != nullptr) { + if (!NetworkIsValidClientName(client_name)) { + /* An invalid client name was given. However, the client ensures the name + * is valid before it is sent over the network, so something went horribly + * wrong. This is probably someone trying to troll us. */ + return this->SendError(NETWORK_ERROR_INVALID_CLIENT_NAME); + } + /* Display change */ if (NetworkFindName(client_name, lastof(client_name))) { NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, CC_DEFAULT, false, ci->client_name, client_name); @@ -1607,7 +1588,9 @@ void NetworkUpdateClientInfo(ClientID client_id) DEBUG(desync, 1, "client: %08x; %02x; %02x; %04x", _date, _date_fract, (int)ci->client_playas, client_id); for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { - cs->SendClientInfo(ci); + if (cs->status >= ServerNetworkGameSocketHandler::STATUS_AUTHORIZED) { + cs->SendClientInfo(ci); + } } NetworkAdminClientUpdate(ci); @@ -1824,7 +1807,7 @@ void NetworkServer_Tick(bool send_frame) for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { /* We allow a number of bytes per frame, but only to the burst amount * to be available for packet receiving at any particular time. */ - cs->receive_limit = std::min(cs->receive_limit + _settings_client.network.bytes_per_frame, + cs->receive_limit = std::min(cs->receive_limit + _settings_client.network.bytes_per_frame, _settings_client.network.bytes_per_frame_burst); /* Check if the speed of the client is what we can expect from a client */ @@ -2063,6 +2046,8 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id) NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN; NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1); + + InvalidateWindowData(WC_CLIENT_LIST, 0); } /** diff --git a/src/network/network_server.h b/src/network/network_server.h index 77612fdc8c..e72377e824 100644 --- a/src/network/network_server.h +++ b/src/network/network_server.h @@ -24,6 +24,7 @@ extern NetworkClientSocketPool _networkclientsocket_pool; class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler { protected: NetworkRecvStatus Receive_CLIENT_JOIN(Packet *p) override; + NetworkRecvStatus Receive_CLIENT_GAME_INFO(Packet *p) override; NetworkRecvStatus Receive_CLIENT_COMPANY_INFO(Packet *p) override; NetworkRecvStatus Receive_CLIENT_GAME_PASSWORD(Packet *p) override; NetworkRecvStatus Receive_CLIENT_COMPANY_PASSWORD(Packet *p) override; @@ -40,6 +41,7 @@ protected: NetworkRecvStatus Receive_CLIENT_NEWGRFS_CHECKED(Packet *p) override; NetworkRecvStatus Receive_CLIENT_MOVE(Packet *p) override; + NetworkRecvStatus SendGameInfo(); NetworkRecvStatus SendCompanyInfo(); NetworkRecvStatus SendNewGRFCheck(); NetworkRecvStatus SendWelcome(); @@ -67,7 +69,7 @@ public: uint32 last_token_frame; ///< The last frame we received the right token ClientStatus status; ///< Status of this client CommandQueue outgoing_queue; ///< The command-queue awaiting delivery - int receive_limit; ///< Amount of bytes that we can receive at this moment + size_t receive_limit; ///< Amount of bytes that we can receive at this moment struct PacketWriter *savegame; ///< Writer used to write the savegame. NetworkAddress client_address; ///< IP-address of the client (so he can be banned) diff --git a/src/network/network_type.h b/src/network/network_type.h index 5a77053469..4dcdd8c03d 100644 --- a/src/network/network_type.h +++ b/src/network/network_type.h @@ -10,7 +10,7 @@ #ifndef NETWORK_TYPE_H #define NETWORK_TYPE_H -#include "core/game.h" +#include "core/config.h" /** How many clients can we have */ static const uint MAX_CLIENTS = 255; @@ -132,6 +132,7 @@ enum NetworkErrorCode { NETWORK_ERROR_TIMEOUT_COMPUTER, NETWORK_ERROR_TIMEOUT_MAP, NETWORK_ERROR_TIMEOUT_JOIN, + NETWORK_ERROR_INVALID_CLIENT_NAME, NETWORK_ERROR_END, }; diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 99939fab44..bb71e5ceaa 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -16,6 +16,7 @@ #include "../date_func.h" #include "../map_func.h" #include "../debug.h" +#include "core/game_info.h" #include "network_gamelist.h" #include "network_internal.h" #include "network_udp.h" @@ -33,9 +34,6 @@ #include "../safeguards.h" -/** Mutex for all out threaded udp resolution and such. */ -static std::mutex _network_udp_mutex; - /** Session key to register ourselves to the master server */ static uint64 _session_key = 0; @@ -43,9 +41,45 @@ static const std::chrono::minutes ADVERTISE_NORMAL_INTERVAL(15); ///< interval b static const std::chrono::seconds ADVERTISE_RETRY_INTERVAL(10); ///< re-advertise when no response after this amount of time. static const uint32 ADVERTISE_RETRY_TIMES = 3; ///< give up re-advertising after this much failed retries -NetworkUDPSocketHandler *_udp_client_socket = nullptr; ///< udp client socket -NetworkUDPSocketHandler *_udp_server_socket = nullptr; ///< udp server socket -NetworkUDPSocketHandler *_udp_master_socket = nullptr; ///< udp master socket +static bool _network_udp_server; ///< Is the UDP server started? +static uint16 _network_udp_broadcast; ///< Timeout for the UDP broadcasts. +static uint8 _network_advertise_retries; ///< The number of advertisement retries we did. + +/** Some information about a socket, which exists before the actual socket has been created to provide locking and the likes. */ +struct UDPSocket { + const std::string name; ///< The name of the socket. + std::mutex mutex; ///< Mutex for everything that (indirectly) touches the sockets within the handler. + NetworkUDPSocketHandler *socket; ///< The actual socket, which may be nullptr when not initialized yet. + std::atomic receive_iterations_locked; ///< The number of receive iterations the mutex was locked. + + UDPSocket(const std::string &name_) : name(name_), socket(nullptr) {} + + void Close() + { + std::lock_guard lock(mutex); + socket->Close(); + delete socket; + socket = nullptr; + } + + void ReceivePackets() + { + std::unique_lock lock(mutex, std::defer_lock); + if (!lock.try_lock()) { + if (++receive_iterations_locked % 32 == 0) { + DEBUG(net, 0, "[udp] %s background UDP loop processing appears to be blocked. Your OS may be low on UDP send buffers.", name.c_str()); + } + return; + } + + receive_iterations_locked.store(0); + socket->ReceivePackets(); + } +}; + +static UDPSocket _udp_client("Client"); ///< udp client socket +static UDPSocket _udp_server("Server"); ///< udp server socket +static UDPSocket _udp_master("Master"); ///< udp master socket /** * Helper function doing the actual work for querying the server. @@ -58,16 +92,15 @@ static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, b /* Clear item in gamelist */ NetworkGameList *item = CallocT(1); address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name)); - strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname)); item->address = address; item->manually = manually; NetworkGameListAddItemDelayed(item); - std::unique_lock lock(_network_udp_mutex, std::defer_lock); + std::unique_lock lock(_udp_client.mutex, std::defer_lock); if (needs_mutex) lock.lock(); /* Init the packet */ Packet p(PACKET_UDP_CLIENT_FIND_SERVER); - if (_udp_client_socket != nullptr) _udp_client_socket->SendPacket(&p, &address); + if (_udp_client.socket != nullptr) _udp_client.socket->SendPacket(&p, &address); } /** @@ -138,31 +171,10 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ } NetworkGameInfo ngi; - - /* Update some game_info */ - ngi.clients_on = _network_game_info.clients_on; - ngi.start_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1); - - ngi.server_lang = _settings_client.network.server_lang; - ngi.use_password = !StrEmpty(_settings_client.network.server_password); - ngi.clients_max = _settings_client.network.max_clients; - ngi.companies_on = (byte)Company::GetNumItems(); - ngi.companies_max = _settings_client.network.max_companies; - ngi.spectators_on = NetworkSpectatorCount(); - ngi.spectators_max = _settings_client.network.max_spectators; - ngi.game_date = _date; - ngi.map_width = MapSizeX(); - ngi.map_height = MapSizeY(); - ngi.map_set = _settings_game.game_creation.landscape; - ngi.dedicated = _network_dedicated; - ngi.grfconfig = _grfconfig; - - strecpy(ngi.map_name, _network_game_info.map_name, lastof(ngi.map_name)); - strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name)); - strecpy(ngi.server_revision, GetNetworkRevisionString(), lastof(ngi.server_revision)); + FillNetworkGameInfo(ngi); Packet packet(PACKET_UDP_SERVER_RESPONSE); - this->SendNetworkGameInfo(&packet, &ngi); + SerializeNetworkGameInfo(&packet, &ngi); /* Let the client know that we are here */ this->SendPacket(&packet, client_addr); @@ -189,23 +201,23 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, Networ static const uint MIN_CI_SIZE = 54; uint max_cname_length = NETWORK_COMPANY_NAME_LENGTH; - if (Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH) >= (uint)SEND_MTU - packet.size) { + if (!packet.CanWriteToPacket(Company::GetNumItems() * (MIN_CI_SIZE + NETWORK_COMPANY_NAME_LENGTH))) { /* Assume we can at least put the company information in the packets. */ - assert(Company::GetNumItems() * MIN_CI_SIZE < (uint)SEND_MTU - packet.size); + assert(packet.CanWriteToPacket(Company::GetNumItems() * MIN_CI_SIZE)); /* At this moment the company names might not fit in the * packet. Check whether that is really the case. */ for (;;) { - int free = SEND_MTU - packet.size; + size_t required = 0; for (const Company *company : Company::Iterate()) { char company_name[NETWORK_COMPANY_NAME_LENGTH]; SetDParam(0, company->index); GetString(company_name, STR_COMPANY_NAME, company_name + max_cname_length - 1); - free -= MIN_CI_SIZE; - free -= (int)strlen(company_name); + required += MIN_CI_SIZE; + required += strlen(company_name); } - if (free >= 0) break; + if (packet.CanWriteToPacket(required)) break; /* Try again, with slightly shorter strings. */ assert(max_cname_length > 0); @@ -225,10 +237,10 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, Networ /** * A client has requested the names of some NewGRFs. * - * Replying this can be tricky as we have a limit of SEND_MTU bytes + * Replying this can be tricky as we have a limit of UDP_MTU bytes * in the reply packet and we can send up to 100 bytes per NewGRF * (GRF ID, MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name). - * As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it + * As UDP_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT, it * could be that a packet overflows. To stop this we only reply * with the first N NewGRFs so that if the first N + 1 NewGRFs * would be sent, the packet overflows. @@ -253,7 +265,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ GRFIdentifier c; const GRFConfig *f; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum); @@ -264,7 +276,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ * The name could be an empty string, if so take the filename. */ packet_len += sizeof(c.grfid) + sizeof(c.md5sum) + std::min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH); - if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply + if (packet_len > UDP_MTU - 4) { // 4 is 3 byte header + grf count in reply break; } in_reply[in_reply_count] = f; @@ -280,7 +292,7 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ /* The name could be an empty string, if so take the filename */ strecpy(name, in_reply[i]->GetName(), lastof(name)); - this->SendGRFIdentifier(&packet, &in_reply[i]->ident); + SerializeGRFIdentifier(&packet, &in_reply[i]->ident); packet.Send_string(name); } @@ -295,7 +307,6 @@ protected: void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) override; void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr) override; void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr) override; - void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) override; public: virtual ~ClientNetworkUDPSocketHandler() {} }; @@ -312,10 +323,15 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd /* Find next item */ item = NetworkGameListAddItem(*client_addr); + /* Clear any existing GRFConfig chain. */ ClearGRFConfigList(&item->info.grfconfig); - this->ReceiveNetworkGameInfo(p, &item->info); + /* Retrieve the NetworkGameInfo from the packet. */ + DeserializeNetworkGameInfo(p, &item->info); + /* Check for compatability with the client. */ + CheckGameCompatibility(item->info); + /* Ensure we consider the server online. */ + item->online = true; - item->info.compatible = true; { /* Checks whether there needs to be a request for names of GRFs and makes * the request if necessary. GRFs that need to be requested are the GRFs @@ -329,7 +345,6 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd uint in_request_count = 0; for (c = item->info.grfconfig; c != nullptr; c = c->next) { - if (c->status == GCS_NOT_FOUND) item->info.compatible = false; if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; in_request[in_request_count] = c; in_request_count++; @@ -342,27 +357,17 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd packet.Send_uint8(in_request_count); for (i = 0; i < in_request_count; i++) { - this->SendGRFIdentifier(&packet, &in_request[i]->ident); + SerializeGRFIdentifier(&packet, &in_request[i]->ident); } this->SendPacket(&packet, &item->address); } } - if (item->info.hostname[0] == '\0') { - seprintf(item->info.hostname, lastof(item->info.hostname), "%s", client_addr->GetHostname()); - } - if (client_addr->GetAddress()->ss_family == AF_INET6) { strecat(item->info.server_name, " (IPv6)", lastof(item->info.server_name)); } - /* Check if we are allowed on this server based on the revision-match */ - item->info.version_compatible = IsNetworkCompatibleVersion(item->info.server_revision); - item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs - - item->online = true; - UpdateNetworkGameWindow(); } @@ -416,7 +421,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd char name[NETWORK_GRF_NAME_LENGTH]; GRFIdentifier c; - this->ReceiveGRFIdentifier(p, &c); + DeserializeGRFIdentifier(p, &c); p->Recv_string(name, sizeof(name)); /* An empty name is not possible under normal circumstances @@ -433,25 +438,6 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_NEWGRFS(Packet *p, NetworkAdd } } -void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) -{ - /* Find the matching GRF file */ - const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum); - if (f == nullptr) { - /* Don't know the GRF, so mark game incompatible and the (possibly) - * already resolved name for this GRF (another server has sent the - * name of the GRF already */ - config->name = FindUnknownGRFName(config->ident.grfid, config->ident.md5sum, true); - config->status = GCS_NOT_FOUND; - } else { - config->filename = f->filename; - config->name = f->name; - config->info = f->info; - config->url = f->url; - } - SetBit(config->flags, GCF_COPY); -} - /** Broadcast to all ips */ static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket) { @@ -475,7 +461,8 @@ void NetworkUDPQueryMasterServer() p.Send_uint8(NETWORK_MASTER_SERVER_VERSION); p.Send_uint8(SLT_AUTODETECT); - _udp_client_socket->SendPacket(&p, &out_addr, true); + std::lock_guard lock(_udp_client.mutex); + _udp_client.socket->SendPacket(&p, &out_addr, true); DEBUG(net, 2, "[udp] master server queried at %s", out_addr.GetAddressAsString().c_str()); } @@ -488,7 +475,7 @@ void NetworkUDPSearchGame() DEBUG(net, 0, "[udp] searching server"); - NetworkUDPBroadCast(_udp_client_socket); + NetworkUDPBroadCast(_udp_client.socket); _network_udp_broadcast = 300; // Stay searching for 300 ticks } @@ -508,8 +495,8 @@ static void NetworkUDPRemoveAdvertiseThread() p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION); p.Send_uint16(_settings_client.network.server_port); - std::lock_guard lock(_network_udp_mutex); - if (_udp_master_socket != nullptr) _udp_master_socket->SendPacket(&p, &out_addr, true); + std::lock_guard lock(_udp_master.mutex); + if (_udp_master.socket != nullptr) _udp_master.socket->SendPacket(&p, &out_addr, true); } /** @@ -560,8 +547,8 @@ static void NetworkUDPAdvertiseThread() p.Send_uint16(_settings_client.network.server_port); p.Send_uint64(_session_key); - std::lock_guard lock(_network_udp_mutex); - if (_udp_master_socket != nullptr) _udp_master_socket->SendPacket(&p, &out_addr, true); + std::lock_guard lock(_udp_master.mutex); + if (_udp_master.socket != nullptr) _udp_master.socket->SendPacket(&p, &out_addr, true); } /** @@ -603,40 +590,41 @@ void NetworkUDPAdvertise() void NetworkUDPInitialize() { /* If not closed, then do it. */ - if (_udp_server_socket != nullptr) NetworkUDPClose(); + if (_udp_server.socket != nullptr) NetworkUDPClose(); DEBUG(net, 1, "[udp] initializing listeners"); - assert(_udp_client_socket == nullptr && _udp_server_socket == nullptr && _udp_master_socket == nullptr); + assert(_udp_client.socket == nullptr && _udp_server.socket == nullptr && _udp_master.socket == nullptr); - std::lock_guard lock(_network_udp_mutex); + std::scoped_lock lock(_udp_client.mutex, _udp_server.mutex, _udp_master.mutex); - _udp_client_socket = new ClientNetworkUDPSocketHandler(); + _udp_client.socket = new ClientNetworkUDPSocketHandler(); NetworkAddressList server; GetBindAddresses(&server, _settings_client.network.server_port); - _udp_server_socket = new ServerNetworkUDPSocketHandler(&server); + _udp_server.socket = new ServerNetworkUDPSocketHandler(&server); server.clear(); GetBindAddresses(&server, 0); - _udp_master_socket = new MasterNetworkUDPSocketHandler(&server); + _udp_master.socket = new MasterNetworkUDPSocketHandler(&server); _network_udp_server = false; _network_udp_broadcast = 0; + _network_advertise_retries = 0; +} + +/** Start the listening of the UDP server component. */ +void NetworkUDPServerListen() +{ + std::lock_guard lock(_udp_server.mutex); + _network_udp_server = _udp_server.socket->Listen(); } /** Close all UDP related stuff. */ void NetworkUDPClose() { - std::lock_guard lock(_network_udp_mutex); - _udp_server_socket->Close(); - _udp_master_socket->Close(); - _udp_client_socket->Close(); - delete _udp_client_socket; - delete _udp_server_socket; - delete _udp_master_socket; - _udp_client_socket = nullptr; - _udp_server_socket = nullptr; - _udp_master_socket = nullptr; + _udp_client.Close(); + _udp_server.Close(); + _udp_master.Close(); _network_udp_server = false; _network_udp_broadcast = 0; @@ -646,13 +634,11 @@ void NetworkUDPClose() /** Receive the UDP packets. */ void NetworkBackgroundUDPLoop() { - std::lock_guard lock(_network_udp_mutex); - if (_network_udp_server) { - _udp_server_socket->ReceivePackets(); - _udp_master_socket->ReceivePackets(); + _udp_server.ReceivePackets(); + _udp_master.ReceivePackets(); } else { - _udp_client_socket->ReceivePackets(); + _udp_client.ReceivePackets(); if (_network_udp_broadcast > 0) _network_udp_broadcast--; } } diff --git a/src/network/network_udp.h b/src/network/network_udp.h index c042bea404..189657bc87 100644 --- a/src/network/network_udp.h +++ b/src/network/network_udp.h @@ -19,6 +19,7 @@ void NetworkUDPQueryServer(NetworkAddress address, bool manually = false); void NetworkUDPAdvertise(); void NetworkUDPRemoveAdvertise(bool blocking); void NetworkUDPClose(); +void NetworkUDPServerListen(); void NetworkBackgroundUDPLoop(); #endif /* NETWORK_UDP_H */ diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 90b5ddd275..8bd92f3265 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -218,6 +218,19 @@ protected: public: ByteReader(byte *data, byte *end) : data(data), end(end) { } + inline byte *ReadBytes(size_t size) + { + if (data + size >= end) { + /* Put data at the end, as would happen if every byte had been individually read. */ + data = end; + throw OTTDByteReaderSignal(); + } + + byte *ret = data; + data += size; + return ret; + } + inline byte ReadByte() { if (data < end) return *(data)++; @@ -1883,7 +1896,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte StationSpec **spec = &_cur.grffile->stations[stid + i]; /* Property 0x08 is special; it is where the station is allocated */ - if (*spec == nullptr) *spec = CallocT(1); + if (*spec == nullptr) *spec = new StationSpec(); /* Swap classid because we read it in BE meaning WAYP or DFLT */ uint32 classid = buf->ReadDWord(); @@ -1891,13 +1904,13 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte break; } - case 0x09: // Define sprite layout - statspec->tiles = buf->ReadExtendedByte(); - delete[] statspec->renderdata; // delete earlier loaded stuff - statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; + case 0x09: { // Define sprite layout + uint16 tiles = buf->ReadExtendedByte(); + statspec->renderdata.clear(); // delete earlier loaded stuff + statspec->renderdata.reserve(tiles); - for (uint t = 0; t < statspec->tiles; t++) { - NewGRFSpriteLayout *dts = &statspec->renderdata[t]; + for (uint t = 0; t < tiles; t++) { + NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back(); dts->consistent_max_offset = UINT16_MAX; // Spritesets are unknown, so no limit. if (buf->HasData(4) && *(uint32*)buf->Data() == 0) { @@ -1933,6 +1946,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte dts->Clone(tmp_layout.data()); } break; + } case 0x0A: { // Copy sprite layout byte srcid = buf->ReadByte(); @@ -1943,12 +1957,12 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte continue; } - delete[] statspec->renderdata; // delete earlier loaded stuff + statspec->renderdata.clear(); // delete earlier loaded stuff + statspec->renderdata.reserve(srcstatspec->renderdata.size()); - statspec->tiles = srcstatspec->tiles; - statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; - for (uint t = 0; t < statspec->tiles; t++) { - statspec->renderdata[t].Clone(&srcstatspec->renderdata[t]); + for (const auto &it : srcstatspec->renderdata) { + NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back(); + dts->Clone(&it); } break; } @@ -1966,54 +1980,25 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte break; case 0x0E: // Define custom layout - statspec->copied_layouts = false; - while (buf->HasData()) { byte length = buf->ReadByte(); byte number = buf->ReadByte(); - StationLayout layout; - uint l, p; if (length == 0 || number == 0) break; - if (length > statspec->lengths) { - byte diff_length = length - statspec->lengths; - statspec->platforms = ReallocT(statspec->platforms, length); - memset(statspec->platforms + statspec->lengths, 0, diff_length); + if (statspec->layouts.size() < length) statspec->layouts.resize(length); + if (statspec->layouts[length - 1].size() < number) statspec->layouts[length - 1].resize(number); - statspec->layouts = ReallocT(statspec->layouts, length); - memset(statspec->layouts + statspec->lengths, 0, diff_length * sizeof(*statspec->layouts)); + const byte *layout = buf->ReadBytes(length * number); + statspec->layouts[length - 1][number - 1].assign(layout, layout + length * number); - statspec->lengths = length; - } - l = length - 1; // index is zero-based - - if (number > statspec->platforms[l]) { - statspec->layouts[l] = ReallocT(statspec->layouts[l], number); - /* We expect nullptr being 0 here, but C99 guarantees that. */ - memset(statspec->layouts[l] + statspec->platforms[l], 0, - (number - statspec->platforms[l]) * sizeof(**statspec->layouts)); - - statspec->platforms[l] = number; - } - - p = 0; - layout = MallocT(length * number); - try { - for (l = 0; l < length; l++) { - for (p = 0; p < number; p++) { - layout[l * number + p] = buf->ReadByte(); - } + /* Validate tile values are only the permitted 00, 02, 04 and 06. */ + for (auto &tile : statspec->layouts[length - 1][number - 1]) { + if ((tile & 6) != tile) { + grfmsg(1, "StationChangeInfo: Invalid tile %u in layout %ux%u", tile, length, number); + tile &= 6; } - } catch (...) { - free(layout); - throw; } - - l--; - p--; - free(statspec->layouts[l][p]); - statspec->layouts[l][p] = layout; } break; @@ -2026,10 +2011,7 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte continue; } - statspec->lengths = srcstatspec->lengths; - statspec->platforms = srcstatspec->platforms; - statspec->layouts = srcstatspec->layouts; - statspec->copied_layouts = true; + statspec->layouts = srcstatspec->layouts; break; } @@ -2074,18 +2056,19 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, Byte statspec->animation.triggers = buf->ReadWord(); break; - case 0x1A: // Advanced sprite layout - statspec->tiles = buf->ReadExtendedByte(); - delete[] statspec->renderdata; // delete earlier loaded stuff - statspec->renderdata = new NewGRFSpriteLayout[statspec->tiles]; + case 0x1A: { // Advanced sprite layout + uint16 tiles = buf->ReadExtendedByte(); + statspec->renderdata.clear(); // delete earlier loaded stuff + statspec->renderdata.reserve(tiles); - for (uint t = 0; t < statspec->tiles; t++) { - NewGRFSpriteLayout *dts = &statspec->renderdata[t]; + for (uint t = 0; t < tiles; t++) { + NewGRFSpriteLayout *dts = &statspec->renderdata.emplace_back(); uint num_building_sprites = buf->ReadByte(); /* On error, bail out immediately. Temporary GRF data was already freed */ if (ReadSpriteLayout(buf, num_building_sprites, false, GSF_STATIONS, true, false, dts)) return CIR_DISABLED; } break; + } default: ret = CIR_UNKNOWN; @@ -3862,6 +3845,7 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B } case 0x0A: { // Set airport layout + byte old_num_table = as->num_table; free(as->rotation); as->num_table = buf->ReadByte(); // Number of layaouts as->rotation = MallocT(as->num_table); @@ -3920,6 +3904,12 @@ static ChangeInfoResult AirportChangeInfo(uint airport, int numinfo, int prop, B tile_table[j] = CallocT(size); memcpy(tile_table[j], copy_from, sizeof(*copy_from) * size); } + /* Free old layouts in the airport spec */ + for (int j = 0; j < old_num_table; j++) { + /* remove the individual layouts */ + free(as->table[j]); + } + free(as->table); /* Install final layout construction in the airport spec */ as->table = tile_table; free(att); @@ -5017,16 +5007,13 @@ static void NewSpriteGroup(ByteReader *buf) case 2: group->size = DSG_SIZE_DWORD; varsize = 4; break; } - static std::vector adjusts; - adjusts.clear(); - /* Loop through the var adjusts. Unfortunately we don't know how many we have * from the outset, so we shall have to keep reallocing. */ do { - DeterministicSpriteGroupAdjust &adjust = adjusts.emplace_back(); + DeterministicSpriteGroupAdjust &adjust = group->adjusts.emplace_back(); /* The first var adjust doesn't have an operation specified, so we set it to add. */ - adjust.operation = adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte(); + adjust.operation = group->adjusts.size() == 1 ? DSGA_OP_ADD : (DeterministicSpriteGroupAdjustOperation)buf->ReadByte(); adjust.variable = buf->ReadByte(); if (adjust.variable == 0x7E) { /* Link subroutine group */ @@ -5051,10 +5038,6 @@ static void NewSpriteGroup(ByteReader *buf) /* Continue reading var adjusts while bit 5 is set. */ } while (HasBit(varadjust, 5)); - group->num_adjusts = (uint)adjusts.size(); - group->adjusts = MallocT(group->num_adjusts); - MemCpyT(group->adjusts, adjusts.data(), group->num_adjusts); - std::vector ranges; ranges.resize(buf->ReadByte()); for (uint i = 0; i < ranges.size(); i++) { @@ -5091,27 +5074,20 @@ static void NewSpriteGroup(ByteReader *buf) } assert(target.size() == bounds.size()); - std::vector optimised; for (uint j = 0; j < bounds.size(); ) { if (target[j] != group->default_group) { - DeterministicSpriteGroupRange r; + DeterministicSpriteGroupRange &r = group->ranges.emplace_back(); r.group = target[j]; r.low = bounds[j]; while (j < bounds.size() && target[j] == r.group) { j++; } r.high = j < bounds.size() ? bounds[j] - 1 : UINT32_MAX; - optimised.push_back(r); } else { j++; } } - group->num_ranges = (uint)optimised.size(); // cast is safe, there should never be 2**31 elements here - if (group->num_ranges > 0) { - group->ranges = MallocT(group->num_ranges); - MemCpyT(group->ranges, &optimised.front(), group->num_ranges); - } break; } @@ -5135,11 +5111,14 @@ static void NewSpriteGroup(ByteReader *buf) group->triggers = GB(triggers, 0, 7); group->cmp_mode = HasBit(triggers, 7) ? RSG_CMP_ALL : RSG_CMP_ANY; group->lowest_randbit = buf->ReadByte(); - group->num_groups = buf->ReadByte(); - group->groups = CallocT(group->num_groups); - for (uint i = 0; i < group->num_groups; i++) { - group->groups[i] = GetGroupFromGroupID(setid, type, buf->ReadWord()); + byte num_groups = buf->ReadByte(); + if (!HasExactlyOneBit(num_groups)) { + grfmsg(1, "NewSpriteGroup: Random Action 2 nrand should be power of 2"); + } + + for (uint i = 0; i < num_groups; i++) { + group->groups.push_back(GetGroupFromGroupID(setid, type, buf->ReadWord())); } break; @@ -5174,23 +5153,18 @@ static void NewSpriteGroup(ByteReader *buf) group->nfo_line = _cur.nfo_line; act_group = group; - group->num_loaded = num_loaded; - group->num_loading = num_loading; - if (num_loaded > 0) group->loaded = CallocT(num_loaded); - if (num_loading > 0) group->loading = CallocT(num_loading); - grfmsg(6, "NewSpriteGroup: New SpriteGroup 0x%02X, %u loaded, %u loading", setid, num_loaded, num_loading); for (uint i = 0; i < num_loaded; i++) { uint16 spriteid = buf->ReadWord(); - group->loaded[i] = CreateGroupFromGroupID(feature, setid, type, spriteid); + group->loaded.push_back(CreateGroupFromGroupID(feature, setid, type, spriteid)); grfmsg(8, "NewSpriteGroup: + rg->loaded[%i] = subset %u", i, spriteid); } for (uint i = 0; i < num_loading; i++) { uint16 spriteid = buf->ReadWord(); - group->loading[i] = CreateGroupFromGroupID(feature, setid, type, spriteid); + group->loading.push_back(CreateGroupFromGroupID(feature, setid, type, spriteid)); grfmsg(8, "NewSpriteGroup: + rg->loading[%i] = subset %u", i, spriteid); } @@ -5325,8 +5299,7 @@ static CargoID TranslateCargo(uint8 feature, uint8 ctype) return CT_INVALID; } - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (cs->bitnum == ctype) { grfmsg(6, "TranslateCargo: Cargo bitnum %d mapped to cargo type %d.", ctype, cs->Index()); return cs->Index(); @@ -8407,22 +8380,8 @@ static void ResetCustomStations() if (stations[i] == nullptr) continue; StationSpec *statspec = stations[i]; - delete[] statspec->renderdata; - - /* Release platforms and layouts */ - if (!statspec->copied_layouts) { - for (uint l = 0; l < statspec->lengths; l++) { - for (uint p = 0; p < statspec->platforms[l]; p++) { - free(statspec->layouts[l][p]); - } - free(statspec->layouts[l]); - } - free(statspec->layouts); - free(statspec->platforms); - } - /* Release this station */ - free(statspec); + delete statspec; } /* Free and reset the station data */ @@ -8804,8 +8763,7 @@ static void CalculateRefitMasks() if (_gted[engine].cargo_allowed != 0) { /* Build up the list of cargo types from the set cargo classes. */ - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (_gted[engine].cargo_allowed & cs->classes) SetBit(mask, cs->Index()); if (_gted[engine].cargo_disallowed & cs->classes) SetBit(not_mask, cs->Index()); } diff --git a/src/newgrf_airport.cpp b/src/newgrf_airport.cpp index 61ad46ac0e..86b65fd0e3 100644 --- a/src/newgrf_airport.cpp +++ b/src/newgrf_airport.cpp @@ -223,8 +223,8 @@ void AirportOverrideManager::SetEntitySpec(AirportSpec *as) { /* Airport action 2s should always have only 1 "loaded" state, but some * times things don't follow the spec... */ - if (group->num_loaded > 0) return group->loaded[0]; - if (group->num_loading > 0) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; return nullptr; } diff --git a/src/newgrf_canal.cpp b/src/newgrf_canal.cpp index 7295e5551b..6b3c9b3d42 100644 --- a/src/newgrf_canal.cpp +++ b/src/newgrf_canal.cpp @@ -111,7 +111,7 @@ struct CanalResolverObject : public ResolverObject { /* virtual */ const SpriteGroup *CanalResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loaded == 0) return nullptr; + if (group->loaded.empty()) return nullptr; return group->loaded[0]; } diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index c2859b71ef..105a2b2524 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -29,8 +29,8 @@ struct CargoResolverObject : public ResolverObject { { /* Cargo action 2s should always have only 1 "loaded" state, but some * times things don't follow the spec... */ - if (group->num_loaded > 0) return group->loaded[0]; - if (group->num_loading > 0) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; return nullptr; } diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index a0e60ef755..d7919e32ae 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -17,6 +17,7 @@ #include "window_func.h" #include "progress.h" #include "video/video_driver.hpp" +#include "string_func.h" #include "strings_func.h" #include "textfile_gui.h" #include "thread.h" diff --git a/src/newgrf_debug_gui.cpp b/src/newgrf_debug_gui.cpp index 9d769880cb..f3b8e14e5f 100644 --- a/src/newgrf_debug_gui.cpp +++ b/src/newgrf_debug_gui.cpp @@ -863,9 +863,10 @@ struct SpriteAlignerWindow : Window { size->height = ScaleGUITrad(200); break; case WID_SA_LIST: - resize->height = std::max(11, FONT_HEIGHT_NORMAL + 1); + resize->height = FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; resize->height = GetMinSizing(NWST_STEP, resize->height); resize->width = 1; + fill->height = resize->height; break; default: break; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index ee14098c28..e028b7a7d6 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -26,62 +26,29 @@ #include "safeguards.h" -struct WagonOverride { - EngineID *train_id; - uint trains; - CargoID cargo; - const SpriteGroup *group; -}; - void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const SpriteGroup *group, EngineID *train_id, uint trains) { Engine *e = Engine::Get(engine); - WagonOverride *wo; assert(cargo < NUM_CARGO + 2); // Include CT_DEFAULT and CT_PURCHASE pseudo cargoes. - e->overrides_count++; - e->overrides = ReallocT(e->overrides, e->overrides_count); - - wo = &e->overrides[e->overrides_count - 1]; + WagonOverride *wo = &e->overrides.emplace_back(); wo->group = group; wo->cargo = cargo; - wo->trains = trains; - wo->train_id = MallocT(trains); - memcpy(wo->train_id, train_id, trains * sizeof *train_id); + wo->engines.assign(train_id, train_id + trains); } const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine) { const Engine *e = Engine::Get(engine); - for (uint i = 0; i < e->overrides_count; i++) { - const WagonOverride *wo = &e->overrides[i]; - - if (wo->cargo != cargo && wo->cargo != CT_DEFAULT) continue; - - for (uint j = 0; j < wo->trains; j++) { - if (wo->train_id[j] == overriding_engine) return wo->group; - } + for (const WagonOverride &wo : e->overrides) { + if (wo.cargo != cargo && wo.cargo != CT_DEFAULT) continue; + if (std::find(wo.engines.begin(), wo.engines.end(), overriding_engine) != wo.engines.end()) return wo.group; } return nullptr; } -/** - * Unload all wagon override sprite groups. - */ -void UnloadWagonOverrides(Engine *e) -{ - for (uint i = 0; i < e->overrides_count; i++) { - WagonOverride *wo = &e->overrides[i]; - free(wo->train_id); - } - free(e->overrides); - e->overrides_count = 0; - e->overrides = nullptr; -} - - void SetCustomEngineSprites(EngineID engine, byte cargo, const SpriteGroup *group) { Engine *e = Engine::Get(engine); @@ -1025,14 +992,14 @@ static uint32 VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *object, const Vehicle *v = this->self_scope.v; if (v == nullptr) { - if (group->num_loading > 0) return group->loading[0]; - if (group->num_loaded > 0) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; return nullptr; } bool in_motion = !v->First()->current_order.IsType(OT_LOADING); - uint totalsets = in_motion ? group->num_loaded : group->num_loading; + uint totalsets = in_motion ? (uint)group->loaded.size() : (uint)group->loading.size(); if (totalsets == 0) return nullptr; diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index f830ff499d..90d755d3c4 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -116,8 +116,6 @@ enum VehicleTrigger { }; void TriggerVehicle(Vehicle *veh, VehicleTrigger trigger); -void UnloadWagonOverrides(Engine *e); - void AlterVehicleListOrder(EngineID engine, uint target); void CommitVehicleListOrderChanges(); diff --git a/src/newgrf_generic.cpp b/src/newgrf_generic.cpp index 6538b79b66..0a138f1d64 100644 --- a/src/newgrf_generic.cpp +++ b/src/newgrf_generic.cpp @@ -150,7 +150,7 @@ void AddGenericCallback(uint8 feature, const GRFFile *file, const SpriteGroup *g /* virtual */ const SpriteGroup *GenericResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loaded == 0) return nullptr; + if (group->loaded.empty()) return nullptr; return group->loaded[0]; } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index d3537c7d15..5c8d58d94a 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -47,8 +47,8 @@ void ShowNewGRFError() if (_game_mode == GM_MENU) return; for (const GRFConfig *c = _grfconfig; c != nullptr; c = c->next) { - /* We only want to show fatal errors */ - if (c->error == nullptr || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue; + /* Only show Fatal and Error level messages */ + if (c->error == nullptr || (c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL && c->error->severity != STR_NEWGRF_ERROR_MSG_ERROR)) continue; SetDParam (0, c->error->message != STR_NULL ? c->error->message : STR_JUST_RAW_STRING); SetDParamStr(1, c->error->custom_message.c_str()); @@ -57,7 +57,11 @@ void ShowNewGRFError() for (uint i = 0; i < lengthof(c->error->param_value); i++) { SetDParam(4 + i, c->error->param_value[i]); } - ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL); + if (c->error->severity == STR_NEWGRF_ERROR_MSG_FATAL) { + ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL); + } else { + ShowErrorMessage(STR_NEWGRF_ERROR_POPUP, INVALID_STRING_ID, WL_ERROR); + } break; } } @@ -612,6 +616,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { bool execute; ///< On pressing 'apply changes' are grf changes applied immediately, or only list is updated. int preset; ///< Selected preset or \c -1 if none selected. int active_over; ///< Active GRF item over which another one is dragged, \c -1 if none. + bool modified; ///< The list of active NewGRFs has been modified since the last time they got saved. Scrollbar *vscroll; Scrollbar *vscroll2; @@ -653,7 +658,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->avails.SetFilterFuncs(this->filter_funcs); this->avails.ForceRebuild(); - this->OnInvalidateData(GOID_NEWGRF_LIST_EDITED); + this->OnInvalidateData(GOID_NEWGRF_CURRENT_LOADED); } ~NewGRFWindow() @@ -662,7 +667,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { DeleteWindowByClass(WC_TEXTFILE); DeleteWindowByClass(WC_SAVE_PRESET); - if (this->editable && !this->execute && !_exit_game) { + if (this->editable && this->modified && !this->execute && !_exit_game) { CopyGRFConfigList(this->orig_list, this->actives, true); ResetGRFConfig(false); ReloadNewGRFData(); @@ -973,7 +978,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } this->vscroll->ScrollTowards(pos); this->preset = -1; - this->InvalidateData(); + this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; } @@ -992,7 +997,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { } this->vscroll->ScrollTowards(pos); this->preset = -1; - this->InvalidateData(); + this->InvalidateData(GOID_NEWGRF_LIST_EDITED); break; } @@ -1098,6 +1103,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { CopyGRFConfigList(this->orig_list, this->actives, true); ResetGRFConfig(false); ReloadNewGRFData(); + this->InvalidateData(GOID_NEWGRF_CHANGES_APPLIED); } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; @@ -1107,6 +1113,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (this->active_sel == nullptr || !this->show_params || this->active_sel->num_valid_params == 0) break; OpenGRFParameterWindow(this->active_sel, this->editable); + this->InvalidateData(GOID_NEWGRF_CHANGES_MADE); break; } @@ -1114,6 +1121,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { if (this->active_sel != nullptr && this->editable) { this->active_sel->palette ^= GRFP_USE_MASK; this->SetDirty(); + this->InvalidateData(GOID_NEWGRF_CHANGES_MADE); } break; @@ -1160,7 +1168,7 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { DeleteWindowByClass(WC_GRF_PARAMETERS); DeleteWindowByClass(WC_TEXTFILE); this->active_sel = nullptr; - this->InvalidateData(GOID_NEWGRF_PRESET_LOADED); + this->InvalidateData(GOID_NEWGRF_CHANGES_MADE); } void OnQueryTextFinished(char *str) override @@ -1181,6 +1189,20 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->InvalidateData(); } + /** + * Updates the scroll bars for the active and inactive NewGRF lists. + */ + void UpdateScrollBars() + { + /* Update scrollbars */ + int i = 0; + for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {} + + this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling. + + if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos); + } + /** * Some data on this window has become invalid. * @param data Information about the changed data. @see GameOptionsInvalidationData @@ -1215,27 +1237,34 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { this->avails.ForceRebuild(); FALLTHROUGH; + case GOID_NEWGRF_CURRENT_LOADED: + this->modified = false; + UpdateScrollBars(); + break; + case GOID_NEWGRF_LIST_EDITED: this->preset = -1; FALLTHROUGH; - case GOID_NEWGRF_PRESET_LOADED: { - /* Update scrollbars */ - int i = 0; - for (const GRFConfig *c = this->actives; c != nullptr; c = c->next, i++) {} + case GOID_NEWGRF_CHANGES_MADE: + UpdateScrollBars(); - this->vscroll->SetCount(i + 1); // Reserve empty space for drag and drop handling. + /* Changes have been made to the list of active NewGRFs */ + this->modified = true; - if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos); break; - } + + case GOID_NEWGRF_CHANGES_APPLIED: + /* No changes have been made to the list of active NewGRFs since the last time the changes got applied */ + this->modified = false; + break; } this->BuildAvailables(); + this->SetWidgetDisabledState(WID_NS_APPLY_CHANGES, !((this->editable && this->modified) || _settings_client.gui.newgrf_developer_tools)); this->SetWidgetsDisabledState(!this->editable, WID_NS_PRESET_LIST, - WID_NS_APPLY_CHANGES, WID_NS_TOGGLE_PALETTE, WIDGET_LIST_END ); @@ -1296,42 +1325,8 @@ struct NewGRFWindow : public Window, NewGRFScanCallback { { if (!this->editable) return ES_NOT_HANDLED; - switch (keycode) { - case WKC_UP: - /* scroll up by one */ - if (this->avail_pos > 0) this->avail_pos--; - break; + if (this->vscroll2->UpdateListPositionOnKeyPress(this->avail_pos, keycode) == ES_NOT_HANDLED) return ES_NOT_HANDLED; - case WKC_DOWN: - /* scroll down by one */ - if (this->avail_pos < (int)this->avails.size() - 1) this->avail_pos++; - break; - - case WKC_PAGEUP: - /* scroll up a page */ - this->avail_pos = (this->avail_pos < this->vscroll2->GetCapacity()) ? 0 : this->avail_pos - this->vscroll2->GetCapacity(); - break; - - case WKC_PAGEDOWN: - /* scroll down a page */ - this->avail_pos = std::min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.size() - 1); - break; - - case WKC_HOME: - /* jump to beginning */ - this->avail_pos = 0; - break; - - case WKC_END: - /* jump to end */ - this->avail_pos = (uint)this->avails.size() - 1; - break; - - default: - return ES_NOT_HANDLED; - } - - if (this->avails.size() == 0) this->avail_pos = -1; if (this->avail_pos >= 0) { this->active_sel = nullptr; DeleteWindowByClass(WC_GRF_PARAMETERS); @@ -1974,10 +1969,11 @@ static void NewGRFConfirmationCallback(Window *w, bool confirmed) for (c = nw->actives; c != nullptr && i > 0; c = c->next, i--) {} nw->active_sel = c; nw->avails.ForceRebuild(); + nw->modified = false; w->InvalidateData(); - ReInitAllWindows(); + ReInitAllWindows(false); DeleteWindowByClass(WC_BUILD_OBJECT); } } diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index 5e59634e84..abae446040 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -281,13 +281,17 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout if (this->tile == INVALID_TILE) break; return GetClosestIndustry(this->tile, MapNewGRFIndustryType(parameter, indspec->grf_prop.grffile->grfid), this->industry); /* Get town zone and Manhattan distance of closest town */ - case 0x65: + case 0x65: { if (this->tile == INVALID_TILE) break; - return GetTownRadiusGroup(this->industry->town, this->tile) << 16 | std::min(DistanceManhattan(this->tile, this->industry->town->xy), 0xFFFFu); - /* Get square of Euclidian distance of closes town */ - case 0x66: + TileIndex tile = GetNearbyTile(parameter, this->tile, true); + return GetTownRadiusGroup(this->industry->town, tile) << 16 | std::min(DistanceManhattan(tile, this->industry->town->xy), 0xFFFFu); + } + /* Get square of Euclidian distance of closest town */ + case 0x66: { if (this->tile == INVALID_TILE) break; - return GetTownRadiusGroup(this->industry->town, this->tile) << 16 | std::min(DistanceSquare(this->tile, this->industry->town->xy), 0xFFFFu); + TileIndex tile = GetNearbyTile(parameter, this->tile, true); + return DistanceSquare(tile, this->industry->town->xy); + } /* Count of industry, distance of closest instance * 68 is the same as 67, but with a filtering on selected layout */ diff --git a/src/newgrf_object.cpp b/src/newgrf_object.cpp index 649a4b58a1..3c069f4c95 100644 --- a/src/newgrf_object.cpp +++ b/src/newgrf_object.cpp @@ -303,8 +303,8 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte local_id, uint32 grfid, /* Get town zone and Manhattan distance of closest town */ case 0x45: return GetTownRadiusGroup(t, this->tile) << 16 | std::min(DistanceManhattan(this->tile, t->xy), 0xFFFFu); - /* Get square of Euclidian distance of closes town */ - case 0x46: return GetTownRadiusGroup(t, this->tile) << 16 | std::min(DistanceSquare(this->tile, t->xy), 0xFFFFu); + /* Get square of Euclidian distance of closest town */ + case 0x46: return DistanceSquare(this->tile, t->xy); /* Object colour */ case 0x47: return this->obj->colour; diff --git a/src/newgrf_railtype.cpp b/src/newgrf_railtype.cpp index 326ee80baf..407acc9844 100644 --- a/src/newgrf_railtype.cpp +++ b/src/newgrf_railtype.cpp @@ -60,8 +60,8 @@ /* virtual */ const SpriteGroup *RailTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loading > 0) return group->loading[0]; - if (group->num_loaded > 0) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; return nullptr; } diff --git a/src/newgrf_roadtype.cpp b/src/newgrf_roadtype.cpp index 025d03bb6a..9243bf77e3 100644 --- a/src/newgrf_roadtype.cpp +++ b/src/newgrf_roadtype.cpp @@ -60,8 +60,8 @@ /* virtual */ const SpriteGroup *RoadTypeResolverObject::ResolveReal(const RealSpriteGroup *group) const { - if (group->num_loading > 0) return group->loading[0]; - if (group->num_loaded > 0) return group->loaded[0]; + if (!group->loading.empty()) return group->loading[0]; + if (!group->loaded.empty()) return group->loaded[0]; return nullptr; } diff --git a/src/newgrf_spritegroup.cpp b/src/newgrf_spritegroup.cpp index 871108ec47..29080894ec 100644 --- a/src/newgrf_spritegroup.cpp +++ b/src/newgrf_spritegroup.cpp @@ -53,23 +53,6 @@ TemporaryStorageArray _temp_store; } } -RealSpriteGroup::~RealSpriteGroup() -{ - free(this->loaded); - free(this->loading); -} - -DeterministicSpriteGroup::~DeterministicSpriteGroup() -{ - free(this->adjusts); - free(this->ranges); -} - -RandomizedSpriteGroup::~RandomizedSpriteGroup() -{ - free(this->groups); -} - static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *scope, byte variable, uint32 parameter, bool *available) { uint32 value; @@ -158,18 +141,18 @@ static inline uint32 GetVariable(const ResolverObject &object, ScopeResolver *sc /* Evaluate an adjustment for a variable of the given size. * U is the unsigned type and S is the signed type to use. */ template -static U EvalAdjustT(const DeterministicSpriteGroupAdjust *adjust, ScopeResolver *scope, U last_value, uint32 value) +static U EvalAdjustT(const DeterministicSpriteGroupAdjust &adjust, ScopeResolver *scope, U last_value, uint32 value) { - value >>= adjust->shift_num; - value &= adjust->and_mask; + value >>= adjust.shift_num; + value &= adjust.and_mask; - switch (adjust->type) { - case DSGA_TYPE_DIV: value = ((S)value + (S)adjust->add_val) / (S)adjust->divmod_val; break; - case DSGA_TYPE_MOD: value = ((S)value + (S)adjust->add_val) % (S)adjust->divmod_val; break; + switch (adjust.type) { + case DSGA_TYPE_DIV: value = ((S)value + (S)adjust.add_val) / (S)adjust.divmod_val; break; + case DSGA_TYPE_MOD: value = ((S)value + (S)adjust.add_val) % (S)adjust.divmod_val; break; case DSGA_TYPE_NONE: break; } - switch (adjust->operation) { + switch (adjust.operation) { case DSGA_OP_ADD: return last_value + value; case DSGA_OP_SUB: return last_value - value; case DSGA_OP_SMIN: return std::min(last_value, value); @@ -207,17 +190,14 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con { uint32 last_value = 0; uint32 value = 0; - uint i; ScopeResolver *scope = object.GetScope(this->var_scope); - for (i = 0; i < this->num_adjusts; i++) { - DeterministicSpriteGroupAdjust *adjust = &this->adjusts[i]; - + for (const auto &adjust : this->adjusts) { /* Try to get the variable. We shall assume it is available, unless told otherwise. */ bool available = true; - if (adjust->variable == 0x7E) { - const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust->subroutine, object, false); + if (adjust.variable == 0x7E) { + const SpriteGroup *subgroup = SpriteGroup::Resolve(adjust.subroutine, object, false); if (subgroup == nullptr) { value = CALLBACK_FAILED; } else { @@ -225,10 +205,10 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con } /* Note: 'last_value' and 'reseed' are shared between the main chain and the procedure */ - } else if (adjust->variable == 0x7B) { - value = GetVariable(object, scope, adjust->parameter, last_value, &available); + } else if (adjust.variable == 0x7B) { + value = GetVariable(object, scope, adjust.parameter, last_value, &available); } else { - value = GetVariable(object, scope, adjust->variable, adjust->parameter, &available); + value = GetVariable(object, scope, adjust.variable, adjust.parameter, &available); } if (!available) { @@ -256,16 +236,16 @@ const SpriteGroup *DeterministicSpriteGroup::Resolve(ResolverObject &object) con return &nvarzero; } - if (this->num_ranges > 4) { - DeterministicSpriteGroupRange *lower = std::lower_bound(this->ranges + 0, this->ranges + this->num_ranges, value, RangeHighComparator); - if (lower != this->ranges + this->num_ranges && lower->low <= value) { + if (this->ranges.size() > 4) { + const auto &lower = std::lower_bound(this->ranges.begin(), this->ranges.end(), value, RangeHighComparator); + if (lower != this->ranges.end() && lower->low <= value) { assert(lower->low <= value && value <= lower->high); return SpriteGroup::Resolve(lower->group, object, false); } } else { - for (i = 0; i < this->num_ranges; i++) { - if (this->ranges[i].low <= value && value <= this->ranges[i].high) { - return SpriteGroup::Resolve(this->ranges[i].group, object, false); + for (const auto &range : this->ranges) { + if (range.low <= value && value <= range.high) { + return SpriteGroup::Resolve(range.group, object, false); } } } @@ -284,11 +264,11 @@ const SpriteGroup *RandomizedSpriteGroup::Resolve(ResolverObject &object) const if (res) { object.used_triggers |= match; - object.reseed[this->var_scope] |= (this->num_groups - 1) << this->lowest_randbit; + object.reseed[this->var_scope] |= (this->groups.size() - 1) << this->lowest_randbit; } } - uint32 mask = (this->num_groups - 1) << this->lowest_randbit; + uint32 mask = ((uint)this->groups.size() - 1) << this->lowest_randbit; byte index = (scope->GetRandomBits() & mask) >> this->lowest_randbit; return SpriteGroup::Resolve(this->groups[index], object, false); diff --git a/src/newgrf_spritegroup.h b/src/newgrf_spritegroup.h index 80f70df55d..b172667612 100644 --- a/src/newgrf_spritegroup.h +++ b/src/newgrf_spritegroup.h @@ -78,7 +78,6 @@ public: * groups. */ struct RealSpriteGroup : SpriteGroup { RealSpriteGroup() : SpriteGroup(SGT_REAL) {} - ~RealSpriteGroup(); /* Loaded = in motion, loading = not moving * Each group contains several spritesets, for various loading stages */ @@ -87,10 +86,8 @@ struct RealSpriteGroup : SpriteGroup { * with small amount of cargo whilst loading is for stations with a lot * of da stuff. */ - byte num_loaded; ///< Number of loaded groups - byte num_loading; ///< Number of loading groups - const SpriteGroup **loaded; ///< List of loaded groups (can be SpriteIDs or Callback results) - const SpriteGroup **loading; ///< List of loading groups (can be SpriteIDs or Callback results) + std::vector loaded; ///< List of loaded groups (can be SpriteIDs or Callback results) + std::vector loading; ///< List of loading groups (can be SpriteIDs or Callback results) protected: const SpriteGroup *Resolve(ResolverObject &object) const; @@ -169,15 +166,12 @@ struct DeterministicSpriteGroupRange { struct DeterministicSpriteGroup : SpriteGroup { DeterministicSpriteGroup() : SpriteGroup(SGT_DETERMINISTIC) {} - ~DeterministicSpriteGroup(); VarSpriteGroupScope var_scope; DeterministicSpriteGroupSize size; - uint num_adjusts; - uint num_ranges; bool calculated_result; - DeterministicSpriteGroupAdjust *adjusts; - DeterministicSpriteGroupRange *ranges; // Dynamically allocated + std::vector adjusts; + std::vector ranges; // Dynamically allocated /* Dynamically allocated, this is the sole owner */ const SpriteGroup *default_group; @@ -195,7 +189,6 @@ enum RandomizedSpriteGroupCompareMode { struct RandomizedSpriteGroup : SpriteGroup { RandomizedSpriteGroup() : SpriteGroup(SGT_RANDOMIZED) {} - ~RandomizedSpriteGroup(); VarSpriteGroupScope var_scope; ///< Take this object: @@ -204,9 +197,8 @@ struct RandomizedSpriteGroup : SpriteGroup { byte count; byte lowest_randbit; ///< Look for this in the per-object randomized bitmask: - byte num_groups; ///< must be power of 2 - const SpriteGroup **groups; ///< Take the group with appropriate index: + std::vector groups; ///< Take the group with appropriate index: protected: const SpriteGroup *Resolve(ResolverObject &object) const; diff --git a/src/newgrf_station.cpp b/src/newgrf_station.cpp index a127d54c9b..eff5ef2b2c 100644 --- a/src/newgrf_station.cpp +++ b/src/newgrf_station.cpp @@ -523,13 +523,13 @@ uint32 Waypoint::GetNewGRFVariable(const ResolverObject &object, byte variable, cargo = std::min(0xfffu, cargo); if (cargo > this->station_scope.statspec->cargo_threshold) { - if (group->num_loading > 0) { - uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * group->num_loading) / (4096 - this->station_scope.statspec->cargo_threshold); + if (!group->loading.empty()) { + uint set = ((cargo - this->station_scope.statspec->cargo_threshold) * (uint)group->loading.size()) / (4096 - this->station_scope.statspec->cargo_threshold); return group->loading[set]; } } else { - if (group->num_loaded > 0) { - uint set = (cargo * group->num_loaded) / (this->station_scope.statspec->cargo_threshold + 1); + if (!group->loaded.empty()) { + uint set = (cargo * (uint)group->loaded.size()) / (this->station_scope.statspec->cargo_threshold + 1); return group->loaded[set]; } } @@ -572,8 +572,7 @@ StationResolverObject::StationResolverObject(const StationSpec *statspec, BaseSt } else if (Station::IsExpected(this->station_scope.st)) { const Station *st = Station::From(this->station_scope.st); /* Pick the first cargo that we have waiting */ - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (this->station_scope.statspec->grf_prop.spritegroup[cs->Index()] != nullptr && st->goods[cs->Index()].cargo.TotalCount() > 0) { ctype = cs->Index(); @@ -799,10 +798,10 @@ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID const NewGRFSpriteLayout *layout = nullptr; DrawTileSprites tmp_rail_layout; - if (statspec->renderdata == nullptr) { + if (statspec->renderdata.empty()) { sprites = GetStationTileLayout(STATION_RAIL, tile + axis); } else { - layout = &statspec->renderdata[(tile < statspec->tiles) ? tile + axis : (uint)axis]; + layout = &statspec->renderdata[(tile < statspec->renderdata.size()) ? tile + axis : (uint)axis]; if (!layout->NeedsPreprocessing()) { sprites = layout; layout = nullptr; diff --git a/src/newgrf_station.h b/src/newgrf_station.h index fac5d64ddd..5273625ae6 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -109,12 +109,13 @@ enum StationRandomTrigger { SRT_PATH_RESERVATION, ///< Trigger platform when train reserves path. }; -/* Station layout for given dimensions - it is a two-dimensional array - * where index is computed as (x * platforms) + platform. */ -typedef byte *StationLayout; - /** Station specification. */ struct StationSpec { + StationSpec() : cls_id(STAT_CLASS_DFLT), name(0), + disallowed_platforms(0), disallowed_lengths(0), + cargo_threshold(0), cargo_triggers(0), + callback_mask(0), flags(0), pylons(0), wires(0), blocked(0), + animation({0, 0, 0, 0}) {} /** * Properties related the the grf file. * NUM_CARGO real cargo plus three pseudo cargo sprite groups. @@ -144,8 +145,7 @@ struct StationSpec { * 4-5 = platform with roof, left side * 6-7 = platform with roof, right side */ - uint tiles; - NewGRFSpriteLayout *renderdata; ///< Array of tile layouts. + std::vector renderdata; ///< Array of tile layouts. /** * Cargo threshold for choosing between little and lots of cargo @@ -165,10 +165,15 @@ struct StationSpec { AnimationInfo animation; - byte lengths; - byte *platforms; - StationLayout **layouts; - bool copied_layouts; + /** + * Custom platform layouts. + * This is a 2D array containing an array of tiles. + * 1st layer is platform lengths. + * 2nd layer is tracks (width). + * These can be sparsely populated, and the upper limit is not defined but + * limited to 255. + */ + std::vector>> layouts; }; /** Struct containing information relating to station classes. */ diff --git a/src/news_gui.cpp b/src/news_gui.cpp index 526d97e705..ea810d2250 100644 --- a/src/news_gui.cpp +++ b/src/news_gui.cpp @@ -424,7 +424,7 @@ struct NewsWindow : Window { { switch (widget) { case WID_N_CAPTION: - DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, STR_NEWS_MESSAGE_CAPTION, this->GetWidget(WID_N_CAPTION), this); + DrawCaption(r, COLOUR_LIGHT_BLUE, this->owner, TC_FROMSTRING, STR_NEWS_MESSAGE_CAPTION, SA_HOR_CENTER, this->GetWidget(WID_N_CAPTION), this); break; case WID_N_PANEL: @@ -1207,7 +1207,7 @@ struct MessageHistoryWindow : Window { NewsItem *ni = _latest_news; if (ni == nullptr) return; - for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP, this->line_height); n > 0; n--) { + for (int n = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_MH_BACKGROUND, WD_FRAMERECT_TOP); n > 0; n--) { ni = ni->prev; if (ni == nullptr) return; } diff --git a/src/object_gui.cpp b/src/object_gui.cpp index 4ee3b7265f..a22aa75bfc 100644 --- a/src/object_gui.cpp +++ b/src/object_gui.cpp @@ -660,24 +660,24 @@ static const NWidgetPart _nested_build_object_widgets[] = { NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 0), - NWidget(NWID_VERTICAL), - NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5), + NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 2), + NWidget(NWID_VERTICAL), SetPadding(0, 5, 2, 0), SetPIP(0, 2, 0), + NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXT, COLOUR_DARK_GREEN), SetFill(0, 1), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BO_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), - NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 5), + NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_BO_CLASS_LIST), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_OBJECT_BUILD_CLASS_TOOLTIP), SetScrollbar(WID_BO_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BO_SCROLLBAR), EndContainer(), - NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 0, 5), + NWidget(NWID_HORIZONTAL), NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BO_OBJECT_MATRIX), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BO_OBJECT_SPRITE), SetDataTip(0x0, STR_OBJECT_BUILD_PREVIEW_TOOLTIP), EndContainer(), EndContainer(), EndContainer(), - NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_NAME), SetDataTip(STR_ORANGE_STRING, STR_NULL), SetPadding(2, 5, 2, 5), - NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_SIZE), SetDataTip(STR_OBJECT_BUILD_SIZE, STR_NULL), SetPadding(2, 5, 2, 5), + NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_NAME), SetDataTip(STR_ORANGE_STRING, STR_NULL), + NWidget(WWT_TEXT, COLOUR_DARK_GREEN, WID_BO_OBJECT_SIZE), SetDataTip(STR_OBJECT_BUILD_SIZE, STR_NULL), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BO_SELECT_SCROLL), NWidget(NWID_HORIZONTAL), @@ -691,7 +691,7 @@ static const NWidgetPart _nested_build_object_widgets[] = { EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BO_INFO), SetPadding(2, 5, 0, 5), SetFill(1, 0), SetResize(1, 0), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BO_INFO), SetPadding(0, 5, 0, 1), SetFill(1, 0), SetResize(1, 0), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_DARK_GREEN), diff --git a/src/openttd.cpp b/src/openttd.cpp index 6e56197839..f38042f020 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -465,7 +465,7 @@ struct AfterNewGRFScan : NewGRFScanCallback { /* restore saved music volume */ MusicDriver::GetInstance()->SetVolume(_settings_client.music.music_vol); - if (startyear != INVALID_YEAR) _settings_newgame.game_creation.starting_year = startyear; + if (startyear != INVALID_YEAR) IConsoleSetSetting("game_creation.starting_year", startyear); if (generation_seed != GENERATE_NEW_SEED) _settings_newgame.game_creation.generation_seed = generation_seed; if (dedicated_host != nullptr) { @@ -483,29 +483,10 @@ struct AfterNewGRFScan : NewGRFScanCallback { if (_switch_mode != SM_NONE) MakeNewgameSettingsLive(); if (_network_available && network_conn != nullptr) { - const char *port = nullptr; - const char *company = nullptr; - uint16 rport = NETWORK_DEFAULT_PORT; - CompanyID join_as = COMPANY_NEW_COMPANY; - - ParseConnectionString(&company, &port, network_conn); - - if (company != nullptr) { - join_as = (CompanyID)atoi(company); - - if (join_as != COMPANY_SPECTATOR) { - join_as--; - if (join_as >= MAX_COMPANIES) { - delete this; - return; - } - } - } - if (port != nullptr) rport = atoi(port); - LoadIntroGame(); _switch_mode = SM_NONE; - NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password); + + NetworkClientConnectGame(network_conn, COMPANY_NEW_COMPANY, join_server_password, join_company_password); } /* After the scan we're not used anymore. */ @@ -594,11 +575,8 @@ int openttd_main(int argc, char *argv[]) dedicated = true; SetDebugString("net=6"); if (mgo.opt != nullptr) { - /* Use the existing method for parsing (openttd -n). - * However, we do ignore the #company part. */ - const char *temp = nullptr; const char *port = nullptr; - ParseConnectionString(&temp, &port, mgo.opt); + ParseFullConnectionString(nullptr, &port, mgo.opt); if (!StrEmpty(mgo.opt)) scanner->dedicated_host = mgo.opt; if (port != nullptr) scanner->dedicated_port = atoi(port); } @@ -794,16 +772,7 @@ int openttd_main(int argc, char *argv[]) NetworkStartUp(); // initialize network-core if (debuglog_conn != nullptr && _network_available) { - const char *not_used = nullptr; - const char *port = nullptr; - uint16 rport; - - rport = NETWORK_DEFAULT_DEBUGLOG_PORT; - - ParseConnectionString(¬_used, &port, debuglog_conn); - if (port != nullptr) rport = atoi(port); - - NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport)); + NetworkStartDebugLog(debuglog_conn); } if (!HandleBootstrap()) { @@ -1082,9 +1051,6 @@ void SwitchToMode(SwitchMode new_mode) case SM_RESTARTGAME: // Restart --> 'Random game' with current settings case SM_NEWGAME: // New Game --> 'Random game' - if (_network_server) { - seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "Random Map"); - } MakeNewGame(false, new_mode == SM_NEWGAME); break; @@ -1107,18 +1073,12 @@ void SwitchToMode(SwitchMode new_mode) IConsoleCmdExec("exec scripts/game_start.scr 0"); /* Decrease pause counter (was increased from opening load dialog) */ DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE); - if (_network_server) { - seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Loaded game)", _file_to_saveload.title); - } } break; } case SM_RESTART_HEIGHTMAP: // Load a heightmap and start a new game from it with current settings case SM_START_HEIGHTMAP: // Load a heightmap and start a new game from it - if (_network_server) { - seprintf(_network_game_info.map_name, lastof(_network_game_info.map_name), "%s (Heightmap)", _file_to_saveload.title); - } MakeNewGame(true, new_mode == SM_START_HEIGHTMAP); break; @@ -1142,6 +1102,11 @@ void SwitchToMode(SwitchMode new_mode) break; } + case SM_JOIN_GAME: // Join a multiplayer game + LoadIntroGame(); + NetworkClientJoinGame(); + break; + case SM_MENU: // Switch to game intro menu LoadIntroGame(); if (BaseSounds::ini_set.empty() && BaseSounds::GetUsedSet()->fallback && SoundDriver::GetInstance()->HasOutput()) { @@ -1501,11 +1466,15 @@ static void DoAutosave() * done in the game-thread, and not in the draw-thread (which most often * triggers this request). * @param callback Optional callback to call when NewGRF scan is completed. + * @return True when the NewGRF scan was actually requested, false when the scan was already running. */ -void RequestNewGRFScan(NewGRFScanCallback *callback) +bool RequestNewGRFScan(NewGRFScanCallback *callback) { + if (_request_newgrf_scan) return false; + _request_newgrf_scan = true; _request_newgrf_scan_callback = callback; + return true; } void GameLoop() @@ -1551,7 +1520,7 @@ void GameLoop() if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ - NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); + NetworkClientConnectGame(_settings_client.network.last_joined, COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); diff --git a/src/openttd.h b/src/openttd.h index 791c7676ed..efd27e76f3 100644 --- a/src/openttd.h +++ b/src/openttd.h @@ -36,6 +36,7 @@ enum SwitchMode { SM_START_HEIGHTMAP, ///< Load a heightmap and start a new game from it. SM_LOAD_HEIGHTMAP, ///< Load heightmap from scenario editor. SM_RESTART_HEIGHTMAP, ///< Load a heightmap and start a new game from it with current settings. + SM_JOIN_GAME, ///< Join a network game. }; /** Display Options */ @@ -82,6 +83,6 @@ void HandleExitGameRequest(); void SwitchToMode(SwitchMode new_mode); -void RequestNewGRFScan(struct NewGRFScanCallback *callback = nullptr); +bool RequestNewGRFScan(struct NewGRFScanCallback *callback = nullptr); #endif /* OPENTTD_H */ diff --git a/src/os/os2/os2.cpp b/src/os/os2/os2.cpp index f1128b0c61..009a3e0ede 100644 --- a/src/os/os2/os2.cpp +++ b/src/os/os2/os2.cpp @@ -203,9 +203,6 @@ bool GetClipboardContents(char *buffer, const char *last) } -const char *FS2OTTD(const char *name) {return name;} -const char *OTTD2FS(const char *name) {return name;} - void OSOpenBrowser(const char *url) { // stub only diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 11b8bcb55d..c11949cc1c 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -150,9 +150,8 @@ static const char *GetLocalCode() * Convert between locales, which from and which to is set in the calling * functions OTTD2FS() and FS2OTTD(). */ -static const char *convert_tofrom_fs(iconv_t convd, const char *name) +static const char *convert_tofrom_fs(iconv_t convd, const char *name, char *outbuf, size_t outlen) { - static char buf[1024]; /* There are different implementations of iconv. The older ones, * e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g. * IEEE 1003.1 (2004), pass a non-const pointer. */ @@ -162,9 +161,8 @@ static const char *convert_tofrom_fs(iconv_t convd, const char *name) const char *inbuf = name; #endif - char *outbuf = buf; - size_t outlen = sizeof(buf) - 1; size_t inlen = strlen(name); + char *buf = outbuf; strecpy(outbuf, name, outbuf + outlen); @@ -183,9 +181,10 @@ static const char *convert_tofrom_fs(iconv_t convd, const char *name) * @param name pointer to a valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ -const char *OTTD2FS(const char *name) +std::string OTTD2FS(const std::string &name) { static iconv_t convd = (iconv_t)(-1); + char buf[1024] = {}; if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); @@ -196,17 +195,18 @@ const char *OTTD2FS(const char *name) } } - return convert_tofrom_fs(convd, name); + return convert_tofrom_fs(convd, name.c_str(), buf, lengthof(buf)); } /** * Convert to OpenTTD's encoding from that of the local environment - * @param name pointer to a valid string that will be converted + * @param name valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ -const char *FS2OTTD(const char *name) +std::string FS2OTTD(const std::string &name) { static iconv_t convd = (iconv_t)(-1); + char buf[1024] = {}; if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); @@ -217,12 +217,9 @@ const char *FS2OTTD(const char *name) } } - return convert_tofrom_fs(convd, name); + return convert_tofrom_fs(convd, name.c_str(), buf, lengthof(buf)); } -#else -const char *FS2OTTD(const char *name) {return name;} -const char *OTTD2FS(const char *name) {return name;} #endif /* WITH_ICONV */ void ShowInfo(const char *str) diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 76a05eaa9e..a7ff8e4110 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -189,7 +189,7 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) GetModuleFileName(mod, buffer, MAX_PATH); GetFileInfo(&dfi, buffer); output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n", - FS2OTTD(buffer), + FS2OTTD(buffer).c_str(), mod, dfi.size, dfi.crc32, @@ -501,7 +501,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c MiniDumpWriteDump_t funcMiniDumpWriteDump = (MiniDumpWriteDump_t)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (funcMiniDumpWriteDump != nullptr) { seprintf(filename, filename_last, "%scrash.dmp", _personal_dir.c_str()); - HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); + HANDLE file = CreateFile(OTTD2FS(filename).c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); HANDLE proc = GetCurrentProcess(); DWORD procid = GetCurrentProcessId(); MINIDUMP_EXCEPTION_INFORMATION mdei; @@ -689,7 +689,8 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA switch (msg) { case WM_INITDIALOG: { /* We need to put the crash-log in a separate buffer because the default - * buffer in OTTD2FS is not large enough (512 chars) */ + * buffer in MB_TO_WIDE is not large enough (512 chars) */ + wchar_t filenamebuf[MAX_PATH * 2]; wchar_t crash_msgW[lengthof(CrashLogWindows::current->crashlog)]; /* Convert unix -> dos newlines because the edit box only supports that properly :( */ const char *unix_nl = CrashLogWindows::current->crashlog; @@ -704,19 +705,23 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA /* Add path to crash.log and crash.dmp (if any) to the crash window text */ size_t len = wcslen(_crash_desc) + 2; - len += wcslen(OTTD2FS(CrashLogWindows::current->crashlog_filename)) + 2; - len += wcslen(OTTD2FS(CrashLogWindows::current->crashdump_filename)) + 2; - len += wcslen(OTTD2FS(CrashLogWindows::current->screenshot_filename)) + 1; + len += wcslen(convert_to_fs(CrashLogWindows::current->crashlog_filename, filenamebuf, lengthof(filenamebuf))) + 2; + len += wcslen(convert_to_fs(CrashLogWindows::current->crashdump_filename, filenamebuf, lengthof(filenamebuf))) + 2; + len += wcslen(convert_to_fs(CrashLogWindows::current->screenshot_filename, filenamebuf, lengthof(filenamebuf))) + 1; wchar_t *text = AllocaM(wchar_t, len); - _snwprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename)); - if (OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != L'\0') { - wcscat(text, L"\n"); - wcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename)); + int printed = _snwprintf(text, len, _crash_desc, convert_to_fs(CrashLogWindows::current->crashlog_filename, filenamebuf, lengthof(filenamebuf))); + if (printed < 0 || (size_t)printed > len) { + MessageBox(wnd, L"Catastrophic failure trying to display crash message. Could not perform text formatting.", L"OpenTTD", MB_ICONERROR); + return FALSE; } - if (OTTD2FS(CrashLogWindows::current->screenshot_filename)[0] != L'\0') { + if (convert_to_fs(CrashLogWindows::current->crashdump_filename, filenamebuf, lengthof(filenamebuf))[0] != L'\0') { wcscat(text, L"\n"); - wcscat(text, OTTD2FS(CrashLogWindows::current->screenshot_filename)); + wcscat(text, filenamebuf); + } + if (convert_to_fs(CrashLogWindows::current->screenshot_filename, filenamebuf, lengthof(filenamebuf))[0] != L'\0') { + wcscat(text, L"\n"); + wcscat(text, filenamebuf); } SetDlgItemText(wnd, 10, text); @@ -730,18 +735,20 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA CrashLog::AfterCrashLogCleanup(); ExitProcess(2); case 13: // Emergency save + wchar_t filenamebuf[MAX_PATH * 2]; char filename[MAX_PATH]; if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename))) { - size_t len = wcslen(_save_succeeded) + wcslen(OTTD2FS(filename)) + 1; + convert_to_fs(filename, filenamebuf, lengthof(filenamebuf)); + size_t len = lengthof(_save_succeeded) + wcslen(filenamebuf) + 1; wchar_t *text = AllocaM(wchar_t, len); - _snwprintf(text, len, _save_succeeded, OTTD2FS(filename)); + _snwprintf(text, len, _save_succeeded, filenamebuf); MessageBox(wnd, text, L"Save successful", MB_ICONINFORMATION); } else { MessageBox(wnd, L"Save failed", L"Save failed", MB_ICONINFORMATION); } break; case 15: // Expand window to show crash-message - _expanded ^= 1; + _expanded = !_expanded; SetWndSize(wnd, _expanded); break; } diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 9a9dba2f2e..55d4193e89 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -83,7 +83,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) } /* Convert font name to file system encoding. */ - wchar_t *font_namep = wcsdup(OTTD2FS(font_name)); + wchar_t *font_namep = wcsdup(OTTD2FS(font_name).c_str()); for (index = 0;; index++) { wchar_t *s; @@ -377,6 +377,7 @@ Win32FontCache::Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels) { this->dc = CreateCompatibleDC(nullptr); this->SetFontSize(fs, pixels); + this->fontname = FS2OTTD(this->logfont.lfFaceName); } Win32FontCache::~Win32FontCache() @@ -438,7 +439,7 @@ void Win32FontCache::SetFontSize(FontSize fs, int pixels) this->glyph_size.cx = otm->otmTextMetrics.tmMaxCharWidth; this->glyph_size.cy = otm->otmTextMetrics.tmHeight; - DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPTSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)), pixels); + DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)).c_str(), pixels); } /** @@ -497,7 +498,7 @@ void Win32FontCache::ClearFontCache() * For anti-aliased rendering, GDI uses the strange value range of 0 to 64, * inclusively. To map this to 0 to 255, we shift left by two and then * subtract one. */ - uint pitch = Align(aa ? gm.gmBlackBoxX : std::max(gm.gmBlackBoxX / 8u, 1u), 4); + uint pitch = Align(aa ? gm.gmBlackBoxX : std::max((gm.gmBlackBoxX + 7u) / 8u, 1u), 4); /* Draw shadow for medium size. */ if (this->fs == FS_NORMAL && !aa) { @@ -541,10 +542,10 @@ void Win32FontCache::ClearFontCache() /* Convert characters outside of the BMP into surrogate pairs. */ WCHAR chars[2]; if (key >= 0x010000U) { - chars[0] = (WCHAR)(((key - 0x010000U) >> 10) + 0xD800); - chars[1] = (WCHAR)(((key - 0x010000U) & 0x3FF) + 0xDC00); + chars[0] = (wchar_t)(((key - 0x010000U) >> 10) + 0xD800); + chars[1] = (wchar_t)(((key - 0x010000U) & 0x3FF) + 0xDC00); } else { - chars[0] = (WCHAR)(key & 0xFFFF); + chars[0] = (wchar_t)(key & 0xFFFF); } WORD glyphs[2] = { 0, 0 }; @@ -605,12 +606,12 @@ void LoadWin32Font(FontSize fs) /* See if this is an absolute path. */ if (FileExists(settings->font)) { - convert_to_fs(settings->font, fontPath, lengthof(fontPath), false); + convert_to_fs(settings->font, fontPath, lengthof(fontPath)); } 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); + convert_to_fs(full_font.c_str(), fontPath, lengthof(fontPath)); } } @@ -648,7 +649,7 @@ void LoadWin32Font(FontSize fs) if (logfont.lfFaceName[0] == 0) { logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts. - convert_to_fs(settings->font, logfont.lfFaceName, lengthof(logfont.lfFaceName), false); + convert_to_fs(settings->font, logfont.lfFaceName, lengthof(logfont.lfFaceName)); } HFONT font = CreateFontIndirect(&logfont); diff --git a/src/os/windows/font_win32.h b/src/os/windows/font_win32.h index ba413fae5e..6ab304c89c 100644 --- a/src/os/windows/font_win32.h +++ b/src/os/windows/font_win32.h @@ -21,6 +21,7 @@ private: HDC dc = nullptr; ///< Cached GDI device context. HGDIOBJ old_font; ///< Old font selected into the GDI context. SIZE glyph_size; ///< Maximum size of regular glyphs. + std::string fontname; ///< Cached copy of this->logfont.lfFaceName void SetFontSize(FontSize fs, int pixels); @@ -33,7 +34,7 @@ public: ~Win32FontCache(); void ClearFontCache() override; GlyphID MapCharToGlyph(WChar key) override; - const char *GetFontName() override { return FS2OTTD(this->logfont.lfFaceName); } + const char *GetFontName() override { return this->fontname.c_str(); } const void *GetOSHandle() override { return &this->logfont; } }; diff --git a/src/os/windows/ottdres.rc.in b/src/os/windows/ottdres.rc.in index 741fa0e105..31309382cf 100644 --- a/src/os/windows/ottdres.rc.in +++ b/src/os/windows/ottdres.rc.in @@ -77,8 +77,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,11,0,${REV_ISODATE} - PRODUCTVERSION 1,11,0,${REV_ISODATE} + FILEVERSION ${REV_MAJOR},${REV_MINOR},${REV_BUILD},${REV_ISODATE} + PRODUCTVERSION ${REV_MAJOR},${REV_MINOR},${REV_BUILD},${REV_ISODATE} FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index cfe7d42d95..eee81be402 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -57,7 +57,7 @@ bool LoadLibraryList(Function proc[], const char *dll) { while (*dll != '\0') { HMODULE lib; - lib = LoadLibrary(OTTD2FS(dll)); + lib = LoadLibrary(OTTD2FS(dll).c_str()); if (lib == nullptr) return false; for (;;) { @@ -77,12 +77,12 @@ bool LoadLibraryList(Function proc[], const char *dll) void ShowOSErrorBox(const char *buf, bool system) { MyShowCursor(true); - MessageBox(GetActiveWindow(), OTTD2FS(buf), L"Error!", MB_ICONSTOP | MB_TASKMODAL); + MessageBox(GetActiveWindow(), OTTD2FS(buf).c_str(), L"Error!", MB_ICONSTOP | MB_TASKMODAL); } void OSOpenBrowser(const char *url) { - ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url), nullptr, nullptr, SW_SHOWNORMAL); + ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } /* Code below for windows version of opendir/readdir/closedir copied and @@ -141,14 +141,14 @@ DIR *opendir(const wchar_t *path) if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { d = dir_calloc(); if (d != nullptr) { - wchar_t search_path[MAX_PATH]; + std::wstring search_path = path; bool slash = path[wcslen(path) - 1] == '\\'; /* build search path for FindFirstFile, try not to append additional slashes * as it throws Win9x off its groove for root directories */ - _snwprintf(search_path, lengthof(search_path), L"%s%s*", path, slash ? L"" : L"\\"); - *lastof(search_path) = '\0'; - d->hFind = FindFirstFile(search_path, &d->fd); + if (!slash) search_path += L"\\"; + search_path += L"*"; + d->hFind = FindFirstFile(search_path.c_str(), &d->fd); if (d->hFind != INVALID_HANDLE_VALUE || GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty @@ -209,7 +209,7 @@ void FiosGetDrives(FileList &file_list) GetLogicalDriveStrings(lengthof(drives), drives); for (s = drives; *s != '\0';) { - FiosItem *fios = file_list.Append(); + FiosItem *fios = &file_list.emplace_back(); fios->type = FIOS_TYPE_DRIVE; fios->mtime = 0; seprintf(fios->name, lastof(fios->name), "%c:", s[0] & 0xFF); @@ -246,8 +246,8 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box ULARGE_INTEGER bytes_free; - bool retval = GetDiskFreeSpaceEx(OTTD2FS(path), &bytes_free, nullptr, nullptr); - if (retval) *tot = bytes_free.QuadPart; + bool retval = GetDiskFreeSpaceEx(OTTD2FS(path).c_str(), &bytes_free, nullptr, nullptr); + if (retval && tot != nullptr) *tot = bytes_free.QuadPart; SetErrorMode(sem); // reset previous setting return retval; @@ -415,7 +415,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi /* Convert the command line to UTF-8. We need a dedicated buffer * for this because argv[] points into this buffer and this needs to * be available between subsequent calls to FS2OTTD(). */ - char *cmdline = stredup(FS2OTTD(GetCommandLine())); + char *cmdline = stredup(FS2OTTD(GetCommandLine()).c_str()); #if defined(_DEBUG) CreateConsole(); @@ -553,34 +553,40 @@ bool GetClipboardContents(char *buffer, const char *last) /** - * Convert to OpenTTD's encoding from wide characters. + * Convert to OpenTTD's encoding from a wide string. * OpenTTD internal encoding is UTF8. - * The returned value's contents can only be guaranteed until the next call to - * this function. So if the value is needed for anything else, use convert_from_fs - * @param name pointer to a valid string that will be converted (local, or wide) - * @return pointer to the converted string; if failed string is of zero-length + * @param name valid string that will be converted (local, or wide) + * @return converted string; if failed string is of zero-length * @see the current code-page comes from video\win32_v.cpp, event-notification * WM_INPUTLANGCHANGE */ -const char *FS2OTTD(const wchar_t *name) +std::string FS2OTTD(const std::wstring &name) { - static char utf8_buf[512]; - return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); + int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length(); + int len = WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0, nullptr, nullptr); + if (len <= 0) return std::string(); + char *utf8_buf = AllocaM(char, len + 1); + utf8_buf[len] = '\0'; + WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, utf8_buf, len, nullptr, nullptr); + return std::string(utf8_buf, static_cast(len)); } /** - * Convert from OpenTTD's encoding to wide characters. + * Convert from OpenTTD's encoding to a wide string. * OpenTTD internal encoding is UTF8. - * The returned value's contents can only be guaranteed until the next call to - * this function. So if the value is needed for anything else, use convert_from_fs - * @param name pointer to a valid string that will be converted (UTF8) + * @param name valid string that will be converted (UTF8) * @param console_cp convert to the console encoding instead of the normal system encoding. - * @return pointer to the converted string; if failed string is of zero-length + * @return converted string; if failed string is of zero-length */ -const wchar_t *OTTD2FS(const char *name, bool console_cp) +std::wstring OTTD2FS(const std::string &name) { - static wchar_t system_buf[512]; - return convert_to_fs(name, system_buf, lengthof(system_buf), console_cp); + int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length(); + int len = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0); + if (len <= 0) return std::wstring(); + wchar_t *system_buf = AllocaM(wchar_t, len + 1); + system_buf[len] = L'\0'; + MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, system_buf, len); + return std::wstring(system_buf, static_cast(len)); } @@ -594,10 +600,8 @@ const wchar_t *OTTD2FS(const char *name, bool console_cp) */ char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen) { - const wchar_t *wide_buf = name; - /* Convert UTF-16 string to UTF-8. */ - int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, nullptr, nullptr); + int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, nullptr, nullptr); if (len == 0) utf8_buf[0] = '\0'; return utf8_buf; @@ -614,7 +618,7 @@ char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen) * @param console_cp convert to the console encoding instead of the normal system encoding. * @return pointer to system_buf. If conversion fails the string is of zero-length */ -wchar_t *convert_to_fs(const char *name, wchar_t *system_buf, size_t buflen, bool console_cp) +wchar_t *convert_to_fs(const char *name, wchar_t *system_buf, size_t buflen) { int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen); if (len == 0) system_buf[0] = '\0'; @@ -625,9 +629,12 @@ wchar_t *convert_to_fs(const char *name, wchar_t *system_buf, size_t buflen, boo /** Determine the current user's locale. */ const char *GetCurrentLocale(const char *) { + const LANGID userUiLang = GetUserDefaultUILanguage(); + const LCID userUiLocale = MAKELCID(userUiLang, SORT_DEFAULT); + char lang[9], country[9]; - if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 || - GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) { + if (GetLocaleInfoA(userUiLocale, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 || + GetLocaleInfoA(userUiLocale, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) { /* Unable to retrieve the locale. */ return nullptr; } diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 60cbed6e97..095181c46c 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -17,7 +17,7 @@ typedef void (*Function)(int); bool LoadLibraryList(Function proc[], const char *dll); char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen); -wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen, bool console_cp = false); +wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen); #if defined(__MINGW32__) && !defined(__MINGW64__) #define SHGFP_TYPE_CURRENT 0 diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp index b1509f2aa6..4ab8b270e2 100644 --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -103,10 +103,7 @@ struct OskWindow : public Window { if (widget < WID_OSK_LETTERS) return; widget -= WID_OSK_LETTERS; - DrawCharCentered(_keyboard[this->shift][widget], - r.left + (r.right - r.left) / 2, - r.top + (r.bottom - r.top - FONT_HEIGHT_NORMAL) / 2, - TC_BLACK); + DrawCharCentered(_keyboard[this->shift][widget], r, TC_BLACK); } void OnClick(Point pt, int widget, int click_count) override @@ -215,10 +212,13 @@ struct OskWindow : public Window { static const int HALF_KEY_WIDTH = 7; // Width of 1/2 key in pixels. static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. +static const int TOP_KEY_PADDING = 2; // Vertical padding for the top row of keys. +static const int KEY_PADDING = 6; // Vertical padding for remaining key rows. + /** * Add a key widget to a row of the keyboard. * @param hor Row container to add key widget to. - * @param height Height of the key (all keys in a row should have equal height). + * @param pad_y Vertical padding of the key (all keys in a row should have equal padding). * @param num_half Number of 1/2 key widths that this key has. * @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget. * @param widnum Widget number of the key. @@ -226,22 +226,25 @@ static const int INTER_KEY_SPACE = 2; // Number of pixels between two keys. * @param biggest_index Collected biggest widget index so far. * @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows. */ -static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) +static void AddKey(NWidgetHorizontal *hor, int pad_y, int num_half, WidgetType widtype, int widnum, uint16 widdata, int *biggest_index) { int min_half_key = std::max(GetMinSizing(NWST_BUTTON), HALF_KEY_WIDTH); int key_width = min_half_key + (INTER_KEY_SPACE + min_half_key) * (num_half - 1); if (widtype == NWID_SPACER) { if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE; - NWidgetSpacer *spc = new NWidgetSpacer(ScaleGUITrad(key_width), height); + NWidgetSpacer *spc = new NWidgetSpacer(key_width, 0); + spc->SetMinimalTextLines(1, pad_y, FS_NORMAL); hor->Add(spc); } else { if (!hor->IsEmpty()) { - NWidgetSpacer *spc = new NWidgetSpacer(ScaleGUITrad(INTER_KEY_SPACE), height); + NWidgetSpacer *spc = new NWidgetSpacer(INTER_KEY_SPACE, 0); + spc->SetMinimalTextLines(1, pad_y, FS_NORMAL); hor->Add(spc); } NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL); - leaf->SetMinimalSize(ScaleGUITrad(key_width), height); + leaf->SetMinimalSize(key_width, 0); + leaf->SetMinimalTextLines(1, pad_y, FS_NORMAL); hor->Add(leaf); } @@ -252,11 +255,10 @@ static void AddKey(NWidgetHorizontal *hor, int height, int num_half, WidgetType static NWidgetBase *MakeTopKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); - int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 2); - AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); - AddKey(hor, key_height, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); - AddKey(hor, key_height, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); + AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); + AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); + AddKey(hor, TOP_KEY_PADDING, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); return hor; } @@ -264,10 +266,13 @@ static NWidgetBase *MakeTopKeys(int *biggest_index) static NWidgetBase *MakeNumberKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); +<<<<<<< HEAD int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); +======= +>>>>>>> 6bd7f8816dfee1a5e697d18e30aad4b5ef7e320f for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } return hor; } @@ -276,13 +281,16 @@ static NWidgetBase *MakeNumberKeys(int *biggest_index) static NWidgetBase *MakeQwertyKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); +<<<<<<< HEAD int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); +======= +>>>>>>> 6bd7f8816dfee1a5e697d18e30aad4b5ef7e320f - AddKey(hor, key_height, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); + AddKey(hor, KEY_PADDING, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } - AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0, biggest_index); return hor; } @@ -290,11 +298,14 @@ static NWidgetBase *MakeQwertyKeys(int *biggest_index) static NWidgetBase *MakeAsdfgKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); +<<<<<<< HEAD int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); +======= +>>>>>>> 6bd7f8816dfee1a5e697d18e30aad4b5ef7e320f - AddKey(hor, key_height, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); + AddKey(hor, KEY_PADDING, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } return hor; } @@ -303,13 +314,16 @@ static NWidgetBase *MakeAsdfgKeys(int *biggest_index) static NWidgetBase *MakeZxcvbKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); +<<<<<<< HEAD int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); +======= +>>>>>>> 6bd7f8816dfee1a5e697d18e30aad4b5ef7e320f - AddKey(hor, key_height, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); + AddKey(hor, KEY_PADDING, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { - AddKey(hor, key_height, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); } - AddKey(hor, key_height, 1, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0, biggest_index); return hor; } @@ -317,13 +331,16 @@ static NWidgetBase *MakeZxcvbKeys(int *biggest_index) static NWidgetBase *MakeSpacebarKeys(int *biggest_index) { NWidgetHorizontal *hor = new NWidgetHorizontal(); +<<<<<<< HEAD int key_height = GetMinSizing(NWST_KEYBOARD, FONT_HEIGHT_NORMAL + 6); +======= +>>>>>>> 6bd7f8816dfee1a5e697d18e30aad4b5ef7e320f - AddKey(hor, key_height, 8, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, key_height, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); - AddKey(hor, key_height, 3, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); - AddKey(hor, key_height, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); + AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); + AddKey(hor, KEY_PADDING, 3, NWID_SPACER, 0, 0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); return hor; } diff --git a/src/pathfinder/CMakeLists.txt b/src/pathfinder/CMakeLists.txt index 2e275706f2..0616371622 100644 --- a/src/pathfinder/CMakeLists.txt +++ b/src/pathfinder/CMakeLists.txt @@ -5,5 +5,4 @@ add_files( follow_track.hpp pathfinder_func.h pathfinder_type.h - pf_performance_timer.hpp ) diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp index 9b95578fd5..7e5e0e39b7 100644 --- a/src/pathfinder/follow_track.hpp +++ b/src/pathfinder/follow_track.hpp @@ -18,7 +18,6 @@ #include "../tunnelbridge_map.h" #include "../depot_map.h" #include "pathfinder_func.h" -#include "pf_performance_timer.hpp" /** * Track follower helper template class (can serve pathfinders and vehicle @@ -49,34 +48,32 @@ struct CFollowTrackT bool m_is_station; ///< last turn passed station int m_tiles_skipped; ///< number of skipped tunnel or station tiles ErrorCode m_err; - CPerformanceTimer *m_pPerf; RailTypes m_railtypes; - inline CFollowTrackT(const VehicleType *v = nullptr, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr) + inline CFollowTrackT(const VehicleType *v = nullptr, RailTypes railtype_override = INVALID_RAILTYPES) { - Init(v, railtype_override, pPerf); + Init(v, railtype_override); } - inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES, CPerformanceTimer *pPerf = nullptr) + inline CFollowTrackT(Owner o, RailTypes railtype_override = INVALID_RAILTYPES) { assert(IsRailTT()); m_veh = nullptr; - Init(o, railtype_override, pPerf); + Init(o, railtype_override); } - inline void Init(const VehicleType *v, RailTypes railtype_override, CPerformanceTimer *pPerf) + inline void Init(const VehicleType *v, RailTypes railtype_override) { assert(!IsRailTT() || (v != nullptr && v->type == VEH_TRAIN)); m_veh = v; - Init(v != nullptr ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override, pPerf); + Init(v != nullptr ? v->owner : INVALID_OWNER, IsRailTT() && railtype_override == INVALID_RAILTYPES ? Train::From(v)->compatible_railtypes : railtype_override); } - inline void Init(Owner o, RailTypes railtype_override, CPerformanceTimer *pPerf) + inline void Init(Owner o, RailTypes railtype_override) { assert(!IsRoadTT() || m_veh != nullptr); assert(!IsRailTT() || railtype_override != INVALID_RAILTYPES); m_veh_owner = o; - m_pPerf = pPerf; /* don't worry, all is inlined so compiler should remove unnecessary initializations */ m_old_tile = INVALID_TILE; m_old_td = INVALID_TRACKDIR; @@ -237,7 +234,6 @@ protected: /** stores track status (available trackdirs) for the new tile into m_new_td_bits */ inline bool QueryNewTileTrackStatus() { - CPerfStart perf(*m_pPerf); if (IsRailTT() && IsPlainRailTile(m_new_tile)) { m_new_td_bits = (TrackdirBits)(GetTrackBits(m_new_tile) * 0x101); } else if (IsRoadTT()) { diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp index 315b43b0e7..0094521615 100644 --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -8,6 +8,7 @@ /** @file npf.cpp Implementation of the NPF pathfinder. */ #include "../../stdafx.h" +#include "../../debug.h" #include "../../network/network.h" #include "../../viewport_func.h" #include "../../ship.h" diff --git a/src/pathfinder/pf_performance_timer.hpp b/src/pathfinder/pf_performance_timer.hpp deleted file mode 100644 index 66ec9695f8..0000000000 --- a/src/pathfinder/pf_performance_timer.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** @file pf_performance_timer.hpp Performance timer for pathfinders. */ - -#ifndef PF_PERFORMANCE_TIMER_HPP -#define PF_PERFORMANCE_TIMER_HPP - -#include "../debug.h" - -struct CPerformanceTimer -{ - int64 m_start; - int64 m_acc; - - CPerformanceTimer() : m_start(0), m_acc(0) {} - - inline void Start() - { - m_start = QueryTime(); - } - - inline void Stop() - { - m_acc += QueryTime() - m_start; - } - - inline int Get(int64 coef) - { - return (int)(m_acc * coef / QueryFrequency()); - } - - inline int64 QueryTime() - { - return ottd_rdtsc(); - } - - inline int64 QueryFrequency() - { - return ((int64)2200 * 1000000); - } -}; - -struct CPerfStartReal -{ - CPerformanceTimer *m_pperf; - - inline CPerfStartReal(CPerformanceTimer& perf) : m_pperf(&perf) - { - if (m_pperf != nullptr) m_pperf->Start(); - } - - inline ~CPerfStartReal() - { - Stop(); - } - - inline void Stop() - { - if (m_pperf != nullptr) { - m_pperf->Stop(); - m_pperf = nullptr; - } - } -}; - -struct CPerfStartFake -{ - inline CPerfStartFake(CPerformanceTimer& perf) {} - inline ~CPerfStartFake() {} - inline void Stop() {} -}; - -typedef CPerfStartFake CPerfStart; - -#endif /* PF_PERFORMANCE_TIMER_HPP */ diff --git a/src/pathfinder/yapf/yapf.hpp b/src/pathfinder/yapf/yapf.hpp index 867c6188ff..36df4db951 100644 --- a/src/pathfinder/yapf/yapf.hpp +++ b/src/pathfinder/yapf/yapf.hpp @@ -12,14 +12,8 @@ #include "../../landscape.h" #include "../pathfinder_func.h" -#include "../pf_performance_timer.hpp" #include "yapf.h" -//#undef FORCEINLINE -//#define inline inline - -#include "../../misc/blob.hpp" -#include "../../misc/str.hpp" #include "../../misc/fixedsizearray.hpp" #include "../../misc/array.hpp" #include "../../misc/hashtable.hpp" diff --git a/src/pathfinder/yapf/yapf_base.hpp b/src/pathfinder/yapf/yapf_base.hpp index 0bdd81dffe..b34e40a673 100644 --- a/src/pathfinder/yapf/yapf_base.hpp +++ b/src/pathfinder/yapf/yapf_base.hpp @@ -13,8 +13,6 @@ #include "../../debug.h" #include "../../settings_type.h" -extern int _total_pf_time_us; - /** * CYapfBaseT - A-star type path finder base class. * Derive your own pathfinder from it. You must provide the following template argument: @@ -67,12 +65,6 @@ protected: int m_stats_cost_calcs; ///< stats - how many node's costs were calculated int m_stats_cache_hits; ///< stats - how many node's costs were reused from cache -public: - CPerformanceTimer m_perf_cost; ///< stats - total CPU time of this run - CPerformanceTimer m_perf_slope_cost; ///< stats - slope calculation CPU time - CPerformanceTimer m_perf_ts_cost; ///< stats - GetTrackStatus() CPU time - CPerformanceTimer m_perf_other_cost; ///< stats - other CPU time - public: int m_num_steps; ///< this is there for debugging purposes (hope it doesn't hurt) @@ -120,9 +112,6 @@ public: { m_veh = v; - CPerformanceTimer perf; - perf.Start(); - Yapf().PfSetStartupNodes(); bool bDestFound = true; @@ -150,25 +139,18 @@ public: bDestFound &= (m_pBestDestNode != nullptr); - perf.Stop(); - if (_debug_yapf_level >= 2) { - int t = perf.Get(1000000); - _total_pf_time_us += t; + if (_debug_yapf_level >= 3) { + UnitID veh_idx = (m_veh != nullptr) ? m_veh->unitnumber : 0; + char ttc = Yapf().TransportTypeChar(); + float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f); + int cost = bDestFound ? m_pBestDestNode->m_cost : -1; + int dist = bDestFound ? m_pBestDestNode->m_estimate - m_pBestDestNode->m_cost : -1; - if (_debug_yapf_level >= 3) { - UnitID veh_idx = (m_veh != nullptr) ? m_veh->unitnumber : 0; - char ttc = Yapf().TransportTypeChar(); - float cache_hit_ratio = (m_stats_cache_hits == 0) ? 0.0f : ((float)m_stats_cache_hits / (float)(m_stats_cache_hits + m_stats_cost_calcs) * 100.0f); - int cost = bDestFound ? m_pBestDestNode->m_cost : -1; - int dist = bDestFound ? m_pBestDestNode->m_estimate - m_pBestDestNode->m_cost : -1; - - DEBUG(yapf, 3, "[YAPF%c]%c%4d- %d us - %d rounds - %d open - %d closed - CHR %4.1f%% - C %d D %d - c%d(sc%d, ts%d, o%d) -- ", - ttc, bDestFound ? '-' : '!', veh_idx, t, m_num_steps, m_nodes.OpenCount(), m_nodes.ClosedCount(), - cache_hit_ratio, cost, dist, m_perf_cost.Get(1000000), m_perf_slope_cost.Get(1000000), - m_perf_ts_cost.Get(1000000), m_perf_other_cost.Get(1000000) - ); - } + DEBUG(yapf, 3, "[YAPF%c]%c%4d- %d rounds - %d open - %d closed - CHR %4.1f%% - C %d D %d", + ttc, bDestFound ? '-' : '!', veh_idx, m_num_steps, m_nodes.OpenCount(), m_nodes.ClosedCount(), cache_hit_ratio, cost, dist + ); } + return bDestFound; } @@ -317,7 +299,7 @@ public: void DumpBase(DumpTarget &dmp) const { dmp.WriteStructT("m_nodes", &m_nodes); - dmp.WriteLine("m_num_steps = %d", m_num_steps); + dmp.WriteValue("m_num_steps", m_num_steps); } /* methods that should be implemented at derived class Types::Tpf (derived from CYapfBaseT) */ diff --git a/src/pathfinder/yapf/yapf_costcache.hpp b/src/pathfinder/yapf/yapf_costcache.hpp index c56c47b5f2..1b4d52cff2 100644 --- a/src/pathfinder/yapf/yapf_costcache.hpp +++ b/src/pathfinder/yapf/yapf_costcache.hpp @@ -182,16 +182,8 @@ protected: inline static Cache& stGetGlobalCache() { static int last_rail_change_counter = 0; - static Date last_date = 0; static Cache C; - /* some statistics */ - if (last_date != _date) { - last_date = _date; - DEBUG(yapf, 2, "Pf time today: %5d ms", _total_pf_time_us / 1000); - _total_pf_time_us = 0; - } - /* delete the cache sometimes... */ if (last_rail_change_counter != Cache::s_rail_change_counter) { last_rail_change_counter = Cache::s_rail_change_counter; diff --git a/src/pathfinder/yapf/yapf_costrail.hpp b/src/pathfinder/yapf/yapf_costrail.hpp index 2f4834633a..b50300b618 100644 --- a/src/pathfinder/yapf/yapf_costrail.hpp +++ b/src/pathfinder/yapf/yapf_costrail.hpp @@ -10,6 +10,8 @@ #ifndef YAPF_COSTRAIL_HPP #define YAPF_COSTRAIL_HPP +#include + #include "../../pbs.h" template @@ -52,9 +54,9 @@ protected: * @note maximum cost doesn't work with caching enabled * @todo fix maximum cost failing with caching (e.g. FS#2900) */ - int m_max_cost; - CBlobT m_sig_look_ahead_costs; - bool m_disable_cache; + int m_max_cost; + bool m_disable_cache; + std::vector m_sig_look_ahead_costs; public: bool m_stopped_on_first_two_way_signal; @@ -68,9 +70,10 @@ protected: int p0 = Yapf().PfGetSettings().rail_look_ahead_signal_p0; int p1 = Yapf().PfGetSettings().rail_look_ahead_signal_p1; int p2 = Yapf().PfGetSettings().rail_look_ahead_signal_p2; - int *pen = m_sig_look_ahead_costs.GrowSizeNC(Yapf().PfGetSettings().rail_look_ahead_max_signals); + m_sig_look_ahead_costs.clear(); + m_sig_look_ahead_costs.reserve(Yapf().PfGetSettings().rail_look_ahead_max_signals); for (uint i = 0; i < Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) { - pen[i] = p0 + i * (p1 + i * p2); + m_sig_look_ahead_costs.push_back(p0 + i * (p1 + i * p2)); } } @@ -83,7 +86,6 @@ protected: public: inline int SlopeCost(TileIndex tile, Trackdir td) { - CPerfStart perf_cost(Yapf().m_perf_slope_cost); if (!stSlopeCost(tile, td)) return 0; return Yapf().PfGetSettings().rail_slope_penalty; } @@ -152,7 +154,7 @@ public: /** The cost for reserved tiles, including skipped ones. */ inline int ReservationCost(Node &n, TileIndex tile, Trackdir trackdir, int skipped) { - if (n.m_num_signals_passed >= m_sig_look_ahead_costs.Size() / 2) return 0; + if (n.m_num_signals_passed >= m_sig_look_ahead_costs.size() / 2) return 0; if (!IsPbsSignal(n.m_last_signal_type)) return 0; if (IsRailStationTile(tile) && IsAnyStationTileReserved(tile, trackdir, skipped)) { @@ -169,7 +171,6 @@ public: { int cost = 0; /* if there is one-way signal in the opposite direction, then it is not our way */ - CPerfStart perf_cost(Yapf().m_perf_other_cost); if (IsTileType(tile, MP_RAILWAY)) { bool has_signal_against = HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir)); bool has_signal_along = HasSignalOnTrackdir(tile, trackdir); @@ -184,7 +185,7 @@ public: n.m_last_signal_type = sig_type; /* cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is */ - int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) ? m_sig_look_ahead_costs.Data()[n.m_num_signals_passed] : 0; + int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.size()) ? m_sig_look_ahead_costs[n.m_num_signals_passed] : 0; if (sig_state != SIGNAL_STATE_RED) { /* green signal */ n.flags_u.flags_s.m_last_signal_was_red = false; @@ -272,8 +273,6 @@ public: assert(tf->m_new_tile == n.m_key.m_tile); assert((HasTrackdir(tf->m_new_td_bits, n.m_key.m_td))); - CPerfStart perf_cost(Yapf().m_perf_cost); - /* Does the node have some parent node? */ bool has_parent = (n.m_parent != nullptr); @@ -323,7 +322,7 @@ public: EndSegmentReasonBits end_segment_reason = ESRB_NONE; - TrackFollower tf_local(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost); + TrackFollower tf_local(v, Yapf().GetCompatibleRailTypes()); if (!has_parent) { /* We will jump to the middle of the cost calculator assuming that segment cache is not used. */ @@ -460,7 +459,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* Apply min/max speed penalties only when inside the look-ahead radius. Otherwise * it would cause desync in MP. */ - if (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) + if (n.m_num_signals_passed < m_sig_look_ahead_costs.size()) { int min_speed = 0; int max_speed = tf->GetSpeedLimit(&min_speed); @@ -481,7 +480,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th /* Move to the next tile/trackdir. */ tf = &tf_local; - tf_local.Init(v, Yapf().GetCompatibleRailTypes(), &Yapf().m_perf_ts_cost); + tf_local.Init(v, Yapf().GetCompatibleRailTypes()); if (!tf_local.Follow(cur.tile, cur.td)) { assert(tf_local.m_err != TrackFollower::EC_NONE); @@ -615,7 +614,7 @@ no_entry_cost: // jump here at the beginning if the node has no parent (it is th { return !m_disable_cache && (n.m_parent != nullptr) - && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size()); + && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.size()); } inline void ConnectNodeToCachedData(Node &n, CachedData &ci) diff --git a/src/pathfinder/yapf/yapf_node.hpp b/src/pathfinder/yapf/yapf_node.hpp index 689a8e9752..ce4ba3b289 100644 --- a/src/pathfinder/yapf/yapf_node.hpp +++ b/src/pathfinder/yapf/yapf_node.hpp @@ -126,8 +126,8 @@ struct CYapfNodeT { { dmp.WriteStructT("m_key", &m_key); dmp.WriteStructT("m_parent", m_parent); - dmp.WriteLine("m_cost = %d", m_cost); - dmp.WriteLine("m_estimate = %d", m_estimate); + dmp.WriteValue("m_cost", m_cost); + dmp.WriteValue("m_estimate", m_estimate); } }; diff --git a/src/pathfinder/yapf/yapf_node_rail.hpp b/src/pathfinder/yapf/yapf_node_rail.hpp index fce909ac9b..df369fcdd7 100644 --- a/src/pathfinder/yapf/yapf_node_rail.hpp +++ b/src/pathfinder/yapf/yapf_node_rail.hpp @@ -109,7 +109,7 @@ struct CYapfRailSegment dmp.WriteStructT("m_key", &m_key); dmp.WriteTile("m_last_tile", m_last_tile); dmp.WriteEnumT("m_last_td", m_last_td); - dmp.WriteLine("m_cost = %d", m_cost); + dmp.WriteValue("m_cost", m_cost); dmp.WriteTile("m_last_signal_tile", m_last_signal_tile); dmp.WriteEnumT("m_last_signal_td", m_last_signal_td); dmp.WriteEnumT("m_end_segment_reason", m_end_segment_reason); @@ -207,10 +207,10 @@ struct CYapfRailNodeT { base::Dump(dmp); dmp.WriteStructT("m_segment", m_segment); - dmp.WriteLine("m_num_signals_passed = %d", m_num_signals_passed); - dmp.WriteLine("m_targed_seen = %s", flags_u.flags_s.m_targed_seen ? "Yes" : "No"); - dmp.WriteLine("m_choice_seen = %s", flags_u.flags_s.m_choice_seen ? "Yes" : "No"); - dmp.WriteLine("m_last_signal_was_red = %s", flags_u.flags_s.m_last_signal_was_red ? "Yes" : "No"); + dmp.WriteValue("m_num_signals_passed", m_num_signals_passed); + dmp.WriteValue("m_targed_seen", flags_u.flags_s.m_targed_seen ? "Yes" : "No"); + dmp.WriteValue("m_choice_seen", flags_u.flags_s.m_choice_seen ? "Yes" : "No"); + dmp.WriteValue("m_last_signal_was_red", flags_u.flags_s.m_last_signal_was_red ? "Yes" : "No"); dmp.WriteEnumT("m_last_red_signal_type", m_last_red_signal_type); } }; diff --git a/src/pathfinder/yapf/yapf_rail.cpp b/src/pathfinder/yapf/yapf_rail.cpp index 6922c0b89d..41aa5fdbd8 100644 --- a/src/pathfinder/yapf/yapf_rail.cpp +++ b/src/pathfinder/yapf/yapf_rail.cpp @@ -28,14 +28,12 @@ template void DumpState(Tpf &pf1, Tpf &pf2) FILE *f2 = fopen("yapf2.txt", "wt"); assert(f1 != nullptr); assert(f2 != nullptr); - fwrite(dmp1.m_out.Data(), 1, dmp1.m_out.Size(), f1); - fwrite(dmp2.m_out.Data(), 1, dmp2.m_out.Size(), f2); + fwrite(dmp1.m_out.c_str(), 1, dmp1.m_out.size(), f1); + fwrite(dmp2.m_out.c_str(), 1, dmp2.m_out.size(), f2); fclose(f1); fclose(f2); } -int _total_pf_time_us = 0; - template class CYapfReserveTrack { diff --git a/src/pathfinder/yapf/yapf_type.hpp b/src/pathfinder/yapf/yapf_type.hpp index ff63c1304a..4f301b0fb7 100644 --- a/src/pathfinder/yapf/yapf_type.hpp +++ b/src/pathfinder/yapf/yapf_type.hpp @@ -10,6 +10,9 @@ #ifndef YAPF_TYPE_HPP #define YAPF_TYPE_HPP +#include +#include + /* Enum used in PfCalcCost() to see why was the segment closed. */ enum EndSegmentReason { /* The following reasons can be saved into cached segment */ @@ -66,7 +69,7 @@ enum EndSegmentReasonBits { DECLARE_ENUM_AS_BIT_SET(EndSegmentReasonBits) -inline CStrA ValueStr(EndSegmentReasonBits bits) +inline std::string ValueStr(EndSegmentReasonBits bits) { static const char * const end_segment_reason_names[] = { "DEAD_END", "RAIL_TYPE", "INFINITE_LOOP", "SEGMENT_TOO_LONG", "CHOICE_FOLLOWS", @@ -74,9 +77,10 @@ inline CStrA ValueStr(EndSegmentReasonBits bits) "PATH_TOO_LONG", "FIRST_TWO_WAY_RED", "LOOK_AHEAD_END", "TARGET_REACHED" }; - CStrA out; - out.Format("0x%04X (%s)", bits, ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE").Data()); - return out.Transfer(); + std::stringstream ss; + ss << "0x" << std::setfill('0') << std::setw(4) << std::hex << bits; // 0x%04X + ss << " (" << ComposeNameT(bits, end_segment_reason_names, "UNK", ESRB_NONE, "NONE") << ")"; + return ss.str(); } #endif /* YAPF_TYPE_HPP */ diff --git a/src/rail.h b/src/rail.h index c5775b9467..a0bbb0109b 100644 --- a/src/rail.h +++ b/src/rail.h @@ -464,10 +464,4 @@ RailType AllocateRailType(RailTypeLabel label); extern std::vector _sorted_railtypes; extern RailTypes _railtypes_hidden_mask; -/** - * Loop header for iterating over railtypes, sorted by sortorder. - * @param var Railtype. - */ -#define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes.size() && (var = _sorted_railtypes[index], true) ; index++) - #endif /* RAIL_H */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index a5e985c022..888b98e943 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -1197,7 +1197,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1, MarkTileDirtyByTile(tile); AddTrackToSignalBuffer(tile, track, _current_company); YapfNotifyTrackLayoutChange(tile, track); - if (v != nullptr) { + if (v != nullptr && v->track != TRACK_BIT_DEPOT) { /* Extend the train's path if it's not stopped or loading, or not at a safe position. */ if (!(((v->vehstatus & VS_STOPPED) && v->cur_speed == 0) || v->current_order.IsType(OT_LOADING)) || !IsSafeWaitingPosition(v, v->tile, v->GetVehicleTrackdir(), true, _settings_game.pf.forbid_90_deg)) { diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index da9e726edc..a2a6b6fdc5 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -1519,7 +1519,7 @@ public: break; case WID_BRAS_NEWST_LIST: { - int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST, 0, this->line_height); + int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_BRAS_NEWST_LIST); if (y >= (int)this->station_classes.size()) return; StationClassID station_class_id = this->station_classes[y]; if (_railstation.station_class != station_class_id) { @@ -1609,17 +1609,17 @@ static const NWidgetPart _nested_station_builder_widgets[] = { EndContainer(), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), - NWidget(NWID_HORIZONTAL), + NWidget(NWID_HORIZONTAL), SetPadding(2, 0, 0, 2), NWidget(NWID_VERTICAL), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_FILTER_CONTAINER), - NWidget(NWID_HORIZONTAL), SetPadding(2, 2, 0, 5), + NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 0), NWidget(WWT_TEXT, COLOUR_DARK_GREEN), SetFill(0, 1), SetDataTip(STR_LIST_FILTER_TITLE, STR_NULL), NWidget(WWT_EDITBOX, COLOUR_GREY, WID_BRAS_FILTER_EDITBOX), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_ADDITIONS), - NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0), + NWidget(NWID_HORIZONTAL), SetPadding(0, 5, 2, 0), NWidget(WWT_MATRIX, COLOUR_GREY, WID_BRAS_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP), SetScrollbar(WID_BRAS_NEWST_SCROLL), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_BRAS_NEWST_SCROLL), @@ -1627,7 +1627,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0), NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAS_PLATFORM_DIR_X), SetSizingType(NWST_BUTTON), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(), @@ -1671,7 +1671,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(NWID_SPACER), SetMinimalSize(0, 2), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2), + NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAS_HIGHLIGHT_OFF), SetMinimalSize(60, 12), @@ -1689,7 +1689,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetScrollbar(WID_BRAS_MATRIX_SCROLL), NWidget(NWID_HORIZONTAL), - NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0), + NWidget(NWID_MATRIX, COLOUR_DARK_GREEN, WID_BRAS_MATRIX), SetScrollbar(WID_BRAS_MATRIX_SCROLL), SetPIP(0, 2, 0), NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BRAS_IMAGE), SetMinimalSize(66, 60), SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP), SetScrollbar(WID_BRAS_MATRIX_SCROLL), EndContainer(), @@ -1704,7 +1704,7 @@ static const NWidgetPart _nested_station_builder_widgets[] = { EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BRAS_COVERAGE_TEXTS), SetFill(1, 1), SetResize(1, 0), + NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BRAS_COVERAGE_TEXTS), SetPadding(2, 5, 0, 1), SetFill(1, 1), SetResize(1, 0), NWidget(NWID_SELECTION, INVALID_COLOUR, WID_BRAS_SHOW_NEWST_RESIZE), NWidget(NWID_VERTICAL), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(0, 1), EndContainer(), @@ -2260,17 +2260,16 @@ DropDownList GetRailTypeDropDownList(bool for_replacement, bool all_option) } Dimension d = { 0, 0 }; - RailType rt; /* Get largest icon size, to ensure text is aligned on each menu item. */ if (!for_replacement) { - FOR_ALL_SORTED_RAILTYPES(rt) { + for (const auto &rt : _sorted_railtypes) { if (!HasBit(used_railtypes, rt)) continue; const RailtypeInfo *rti = GetRailTypeInfo(rt); d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_rail)); } } - FOR_ALL_SORTED_RAILTYPES(rt) { + for (const auto &rt : _sorted_railtypes) { /* If it's not used ever, don't show it to the user. */ if (!HasBit(used_railtypes, rt)) continue; diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 208588a711..3939ca5a0e 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -85,4 +85,4 @@ const byte _openttd_revision_tagged = ${REV_ISTAG}; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 12 << 24 | 0 << 20 | ${REV_ISSTABLETAG} << 19 | 28004; +const uint32 _openttd_newgrf_version = ${REV_MAJOR} << 28 | ${REV_MINOR} << 24 | ${REV_BUILD} << 20 | ${REV_ISSTABLETAG} << 19 | 28004; diff --git a/src/road.h b/src/road.h index 1082ab2729..becbf40512 100644 --- a/src/road.h +++ b/src/road.h @@ -305,10 +305,4 @@ bool HasAnyRoadTypesAvail(CompanyID company, RoadTramType rtt); extern std::vector _sorted_roadtypes; extern RoadTypes _roadtypes_hidden_mask; -/** - * Loop header for iterating over roadtypes, sorted by sortorder. - * @param var Roadtype. - */ -#define FOR_ALL_SORTED_ROADTYPES(var) for (uint8 index = 0; index < _sorted_roadtypes.size() && (var = _sorted_roadtypes[index], true) ; index++) - #endif /* ROAD_H */ diff --git a/src/road_gui.cpp b/src/road_gui.cpp index da25fcf8e7..0937bb1617 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -1349,17 +1349,16 @@ DropDownList GetRoadTypeDropDownList(RoadTramTypes rtts, bool for_replacement, b } Dimension d = { 0, 0 }; - RoadType rt; /* Get largest icon size, to ensure text is aligned on each menu item. */ if (!for_replacement) { - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (!HasBit(used_roadtypes, rt)) continue; const RoadTypeInfo *rti = GetRoadTypeInfo(rt); d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); } } - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { /* If it's not used ever, don't show it to the user. */ if (!HasBit(used_roadtypes, rt)) continue; @@ -1401,13 +1400,12 @@ DropDownList GetScenRoadTypeDropDownList(RoadTramTypes rtts) /* If it's not used ever, don't show it to the user. */ Dimension d = { 0, 0 }; - RoadType rt; - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (!HasBit(used_roadtypes, rt)) continue; const RoadTypeInfo *rti = GetRoadTypeInfo(rt); d = maxdim(d, GetSpriteSize(rti->gui_sprites.build_x_road)); } - FOR_ALL_SORTED_ROADTYPES(rt) { + for (const auto &rt : _sorted_roadtypes) { if (!HasBit(used_roadtypes, rt)) continue; const RoadTypeInfo *rti = GetRoadTypeInfo(rt); diff --git a/src/safeguards.h b/src/safeguards.h index 5351116ecb..aca461175f 100644 --- a/src/safeguards.h +++ b/src/safeguards.h @@ -69,4 +69,17 @@ #undef abs #endif +#if defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) +/* Use NetworkError::GetLast() instead of errno, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock does not set errno, but one should rather call WSAGetLastError. NetworkError::GetLast abstracts that away. */ +#ifdef errno +#undef errno +#endif +#define errno SAFEGUARD_DO_NOT_USE_THIS_METHOD + +/* Use NetworkError::AsString() instead of strerror, or do not (indirectly) include network/core/os_abstraction.h. + * Winsock errors are not handled by strerror, but one should rather call FormatMessage. NetworkError::AsString abstracts that away. */ +#define strerror SAFEGUARD_DO_NOT_USE_THIS_METHOD +#endif /* defined(NETWORK_CORE_OS_ABSTRACTION_H) && defined(_WIN32) */ + #endif /* SAFEGUARDS_H */ diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index be6be8de69..56680511cb 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -219,6 +219,7 @@ void UpdateAllVirtCoords() UpdateAllStationVirtCoords(); UpdateAllSignVirtCoords(); UpdateAllTownVirtCoords(); + UpdateAllTextEffectVirtCoords(); RebuildViewportKdtree(); } @@ -3127,6 +3128,23 @@ bool AfterLoadGame() } } + if (IsSavegameVersionBefore(SLV_GROUP_REPLACE_WAGON_REMOVAL)) { + /* Propagate wagon removal flag for compatibility */ + /* Temporary bitmask of company wagon removal setting */ + uint16 wagon_removal = 0; + for (const Company *c : Company::Iterate()) { + if (c->settings.renew_keep_length) SetBit(wagon_removal, c->index); + } + for (Group *g : Group::Iterate()) { + if (g->flags != 0) { + /* Convert old replace_protection value to flag. */ + g->flags = 0; + SetBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION); + } + if (HasBit(wagon_removal, g->owner)) SetBit(g->flags, GroupFlags::GF_REPLACE_WAGON_REMOVAL); + } + } + /* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */ Station::RecomputeCatchmentForAll(); diff --git a/src/saveload/gamelog_sl.cpp b/src/saveload/gamelog_sl.cpp index 6bff1b154c..d68297c9a7 100644 --- a/src/saveload/gamelog_sl.cpp +++ b/src/saveload/gamelog_sl.cpp @@ -107,8 +107,11 @@ static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_action assert(gamelog_action == nullptr); assert(gamelog_actions == 0); - GamelogActionType at; - while ((at = (GamelogActionType)SlReadByte()) != GLAT_NONE) { + byte type; + while ((type = SlReadByte()) != GLAT_NONE) { + if (type >= GLAT_END) SlErrorCorrupt("Invalid gamelog action type"); + GamelogActionType at = (GamelogActionType)type; + gamelog_action = ReallocT(gamelog_action, gamelog_actions + 1); LoggedAction *la = &gamelog_action[gamelog_actions++]; @@ -118,8 +121,10 @@ static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_action la->change = nullptr; la->changes = 0; - GamelogChangeType ct; - while ((ct = (GamelogChangeType)SlReadByte()) != GLCT_NONE) { + while ((type = SlReadByte()) != GLCT_NONE) { + if (type >= GLCT_END) SlErrorCorrupt("Invalid gamelog change type"); + GamelogChangeType ct = (GamelogChangeType)type; + la->change = ReallocT(la->change, la->changes + 1); LoggedChange *lc = &la->change[la->changes++]; @@ -127,8 +132,6 @@ static void Load_GLOG_common(LoggedAction *&gamelog_action, uint &gamelog_action memset(lc, 0, sizeof(*lc)); lc->ct = ct; - assert((uint)ct < GLCT_END); - SlObject(lc, _glog_desc[ct]); } } diff --git a/src/saveload/group_sl.cpp b/src/saveload/group_sl.cpp index cae313ff83..c5f7e2b507 100644 --- a/src/saveload/group_sl.cpp +++ b/src/saveload/group_sl.cpp @@ -21,7 +21,7 @@ static const SaveLoad _group_desc[] = { SLE_CONDNULL(2, SL_MIN_VERSION, SLV_164), // num_vehicle SLE_VAR(Group, owner, SLE_UINT8), SLE_VAR(Group, vehicle_type, SLE_UINT8), - SLE_VAR(Group, replace_protection, SLE_BOOL), + SLE_VAR(Group, flags, SLE_UINT8), SLE_CONDVAR(Group, livery.in_use, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), SLE_CONDVAR(Group, livery.colour1, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), SLE_CONDVAR(Group, livery.colour2, SLE_UINT8, SLV_GROUP_LIVERIES, SL_MAX_VERSION), diff --git a/src/saveload/linkgraph_sl.cpp b/src/saveload/linkgraph_sl.cpp index a597edfc43..f571e331a5 100644 --- a/src/saveload/linkgraph_sl.cpp +++ b/src/saveload/linkgraph_sl.cpp @@ -151,6 +151,7 @@ void SaveLoad_LinkGraph(LinkGraph &lg) } else { /* ... but as that wasted a lot of space we save a sparse matrix now. */ for (NodeID to = from; to != INVALID_NODE; to = lg.edges[from][to].next_edge) { + if (to >= size) SlErrorCorrupt("Link graph structure overflow"); SlObject(&lg.edges[from][to], _edge_desc); } } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index dcfcc9f431..f5e823a0df 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -19,7 +19,6 @@ *
  • repeat this until everything is done, and flush any remaining output to file * */ -#include #include "../stdafx.h" #include "../debug.h" @@ -44,6 +43,7 @@ #include "../fios.h" #include "../error.h" #include +#include #include #ifdef __EMSCRIPTEN__ # include diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index 8ad29a6407..cda6af82b6 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -325,6 +325,7 @@ enum SaveLoadVersion : uint16 { SLV_VEH_MOTION_COUNTER, ///< 288 PR#8591 Desync safe motion counter SLV_INDUSTRY_TEXT, ///< 289 PR#8576 v1.11.0-RC1 Additional GS text for industries. SLV_MAPGEN_SETTINGS_REVAMP, ///< 290 PR#8891 v1.11 Revamp of some mapgen settings (snow coverage, desert coverage, heightmap height, custom terrain type). + SLV_GROUP_REPLACE_WAGON_REMOVAL, ///< 291 PR#7441 Per-group wagon removal flag. SL_MAX_VERSION, ///< Highest possible saveload version }; diff --git a/src/screenshot.cpp b/src/screenshot.cpp index 54d8ded4d8..bf4c2527bd 100644 --- a/src/screenshot.cpp +++ b/src/screenshot.cpp @@ -877,7 +877,7 @@ static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the curre */ static void ScreenshotConfirmationCallback(Window *w, bool confirmed) { - if (confirmed) MakeScreenshot(_confirmed_screenshot_type, nullptr); + if (confirmed) MakeScreenshot(_confirmed_screenshot_type, {}); } /** @@ -903,24 +903,20 @@ void MakeScreenshotWithConfirm(ScreenshotType t) ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, nullptr, ScreenshotConfirmationCallback); } else { /* Less than 64M pixels, just do it */ - MakeScreenshot(t, nullptr); + MakeScreenshot(t, {}); } } /** * Make a screenshot. - * Unconditionally take a screenshot of the requested type. * @param t the type of screenshot to make. * @param name the name to give to the screenshot. * @param width the width of the screenshot of, or 0 for current viewport width (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). * @param height the height of the screenshot of, or 0 for current viewport height (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). * @return true iff the screenshot was made successfully - * @see MakeScreenshotWithConfirm */ -bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 height) +static bool RealMakeScreenshot(ScreenshotType t, std::string name, uint32 width, uint32 height) { - VideoDriver::VideoBufferLocker lock; - if (t == SC_VIEWPORT) { /* First draw the dirty parts of the screen and only then change the name * of the screenshot. This way the screenshot will always show the name @@ -931,7 +927,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei } _screenshot_name[0] = '\0'; - if (name != nullptr) strecpy(_screenshot_name, name, lastof(_screenshot_name)); + if (!name.empty()) strecpy(_screenshot_name, name.c_str(), lastof(_screenshot_name)); bool ret; switch (t) { @@ -970,7 +966,7 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei if (t == SC_HEIGHTMAP) { SetDParamStr(0, _screenshot_name); SetDParam(1, _heightmap_highest_peak); - ShowErrorMessage(STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY, INVALID_STRING_ID, WL_CRITICAL); + ShowErrorMessage(STR_MESSAGE_HEIGHTMAP_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING); } else { SetDParamStr(0, _screenshot_name); // ShowErrorMessage(STR_MESSAGE_SCREENSHOT_SUCCESSFULLY, INVALID_STRING_ID, WL_WARNING); // No need for message when we're doing cloudsave @@ -982,6 +978,32 @@ bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width, uint32 hei return ret; } +/** + * Schedule making a screenshot. + * Unconditionally take a screenshot of the requested type. + * @param t the type of screenshot to make. + * @param name the name to give to the screenshot. + * @param width the width of the screenshot of, or 0 for current viewport width (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). + * @param height the height of the screenshot of, or 0 for current viewport height (only works for SC_ZOOMEDIN and SC_DEFAULTZOOM). + * @return true iff the screenshot was successfully made. + * @see MakeScreenshotWithConfirm + */ +bool MakeScreenshot(ScreenshotType t, std::string name, uint32 width, uint32 height) +{ + if (t == SC_CRASHLOG) { + /* Video buffer might or might not be locked. */ + VideoDriver::VideoBufferLocker lock; + + return RealMakeScreenshot(t, name, width, height); + } + + VideoDriver::GetInstance()->QueueOnMainThread([=] { // Capture by value to not break scope. + RealMakeScreenshot(t, name, width, height); + }); + + return true; +} + /** * Return the owner of a tile to display it with in the small map in mode "Owner". diff --git a/src/screenshot.h b/src/screenshot.h index 148c018e1e..e65813573f 100644 --- a/src/screenshot.h +++ b/src/screenshot.h @@ -28,7 +28,7 @@ enum ScreenshotType { void SetupScreenshotViewport(ScreenshotType t, struct Viewport *vp, uint32 width = 0, uint32 height = 0); bool MakeHeightmapScreenshot(const char *filename); void MakeScreenshotWithConfirm(ScreenshotType t); -bool MakeScreenshot(ScreenshotType t, const char *name, uint32 width = 0, uint32 height = 0); +bool MakeScreenshot(ScreenshotType t, std::string name, uint32 width = 0, uint32 height = 0); bool MakeMinimapWorldScreenshot(); extern char _screenshot_format_name[8]; diff --git a/src/script/api/script_cargolist.cpp b/src/script/api/script_cargolist.cpp index fbd150c6cf..0019dc5e91 100644 --- a/src/script/api/script_cargolist.cpp +++ b/src/script/api/script_cargolist.cpp @@ -19,8 +19,7 @@ ScriptCargoList::ScriptCargoList() { - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { this->AddItem(cs->Index()); } } diff --git a/src/script/api/script_date.cpp b/src/script/api/script_date.cpp index 57415ecb94..ae3dff78c6 100644 --- a/src/script/api/script_date.cpp +++ b/src/script/api/script_date.cpp @@ -7,11 +7,12 @@ /** @file script_date.cpp Implementation of ScriptDate. */ -#include "../../stdafx.h" /* Have to be included before time.h, if we want UINT32_MAX macro defined on Android */ -#include +#include "../../stdafx.h" #include "script_date.hpp" #include "../../date_func.h" +#include + #include "../../safeguards.h" /* static */ bool ScriptDate::IsValidDate(Date date) diff --git a/src/script/api/script_group.cpp b/src/script/api/script_group.cpp index 7f80815864..9cf6c7c957 100644 --- a/src/script/api/script_group.cpp +++ b/src/script/api/script_group.cpp @@ -89,14 +89,14 @@ { EnforcePrecondition(false, IsValidGroup(group_id)); - return ScriptObject::DoCommand(0, group_id, enable ? 1 : 0, CMD_SET_GROUP_REPLACE_PROTECTION); + return ScriptObject::DoCommand(0, group_id | GroupFlags::GF_REPLACE_PROTECTION, enable ? 1 : 0, CMD_SET_GROUP_FLAG); } /* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id) { if (!IsValidGroup(group_id)) return false; - return ::Group::Get(group_id)->replace_protection; + return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION); } /* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id) diff --git a/src/script/script_fatalerror.hpp b/src/script/script_fatalerror.hpp index 5d1a2c1250..96c64e0b9d 100644 --- a/src/script/script_fatalerror.hpp +++ b/src/script/script_fatalerror.hpp @@ -19,7 +19,7 @@ public: * Creates a "fatal error" exception. * @param msg The message describing the cause of the fatal error. */ - Script_FatalError(const char *msg) : + Script_FatalError(const std::string &msg) : msg(msg) {} @@ -27,10 +27,10 @@ public: * The error message associated with the fatal error. * @return The error message. */ - const char *GetErrorMessage() { return msg; } + const std::string &GetErrorMessage() const { return msg; } private: - const char *msg; ///< The error message. + const std::string msg; ///< The error message. }; #endif /* SCRIPT_FATALERROR_HPP */ diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp index 8227060d35..f7f9de4fc8 100644 --- a/src/script/script_instance.cpp +++ b/src/script/script_instance.cpp @@ -100,7 +100,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na ScriptObject::SetAllowDoCommand(true); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ThrowError(e.GetErrorMessage().c_str()); this->engine->ResumeError(); this->Died(); } @@ -228,7 +228,7 @@ void ScriptInstance::GameLoop() this->callback = e.GetSuspendCallback(); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ThrowError(e.GetErrorMessage().c_str()); this->engine->ResumeError(); this->Died(); } @@ -249,7 +249,7 @@ void ScriptInstance::GameLoop() this->callback = e.GetSuspendCallback(); } catch (Script_FatalError &e) { this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ThrowError(e.GetErrorMessage().c_str()); this->engine->ResumeError(); this->Died(); } @@ -505,7 +505,7 @@ void ScriptInstance::Save() /* If we don't mark the script as dead here cleaning up the squirrel * stack could throw Script_FatalError again. */ this->is_dead = true; - this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ThrowError(e.GetErrorMessage().c_str()); this->engine->ResumeError(); SaveEmpty(); /* We can't kill the script here, so mark it as crashed (not dead) and diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index 6fa88bfee5..8b48809bf7 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -38,7 +38,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length, try { this->engine->LoadScript(filename.c_str()); } catch (Script_FatalError &e) { - DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename.c_str()); + DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage().c_str(), filename.c_str()); return false; } return true; diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index f97896eb93..77f84a6416 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -7,8 +7,6 @@ /** @file squirrel.cpp the implementation of the Squirrel class. It handles all Squirrel-stuff and gives a nice API back to work with. */ -#include -#include #include "../stdafx.h" #include "../debug.h" #include "squirrel_std.hpp" @@ -21,7 +19,16 @@ #include <../squirrel/sqvm.h> #include "../core/alloc_func.hpp" -#include "../safeguards.h" +#include +#include + +/** + * In the memory allocator for Squirrel we want to directly use malloc/realloc, so when the OS + * does not have enough memory the game does not go into unrecoverable error mode and kill the + * whole game, but rather let the AI die though then we need to circumvent MallocT/ReallocT. + * + * So no #include "../safeguards.h" here as is required, but after the allocator's implementation. + */ /* * If changing the call paths into the scripting engine, define this symbol to enable full debugging of allocations. @@ -32,6 +39,13 @@ struct ScriptAllocator { size_t allocated_size; ///< Sum of allocated data size size_t allocation_limit; ///< Maximum this allocator may use before allocations fail + /** + * Whether the error has already been thrown, so to not throw secondary errors in + * the handling of the allocation error. This as the handling of the error will + * throw a Squirrel error so the Squirrel stack can be dumped, however that gets + * allocated by this allocator and then you might end up in an infinite loop. + */ + bool error_thrown; static const size_t SAFE_LIMIT = 0x8000000; ///< 128 MiB, a safe choice for almost any situation @@ -44,11 +58,52 @@ struct ScriptAllocator { if (this->allocated_size > this->allocation_limit) throw Script_FatalError("Maximum memory allocation exceeded"); } + /** + * Catch all validation for the allocation; did it allocate too much memory according + * to the allocation limit or did the allocation at the OS level maybe fail? In those + * error situations a Script_FatalError is thrown, but once that has been done further + * allocations are allowed to make it possible for Squirrel to throw the error and + * clean everything up. + * @param requested_size The requested size that was requested to be allocated. + * @param p The pointer to the allocated object, or null if allocation failed. + */ + void CheckAllocation(size_t requested_size, const void *p) + { + if (this->allocated_size > this->allocation_limit && !this->error_thrown) { + /* Do not allow allocating more than the allocation limit, except when an error is + * already as then the allocation is for throwing that error in Squirrel, the + * associated stack trace information and while cleaning up the AI. */ + this->error_thrown = true; + char buff[128]; + seprintf(buff, lastof(buff), "Maximum memory allocation exceeded by " PRINTF_SIZE " bytes when allocating " PRINTF_SIZE " bytes", + this->allocated_size - this->allocation_limit, requested_size); + throw Script_FatalError(buff); + } + + if (p == nullptr) { + /* The OS did not have enough memory to allocate the object, regardless of the + * limit imposed by OpenTTD on the amount of memory that may be allocated. */ + if (this->error_thrown) { + /* The allocation is called in the error handling of a memory allocation + * failure, then not being able to allocate that small amount of memory + * means there is no other choice than to bug out completely. */ + MallocError(requested_size); + } + + this->error_thrown = true; + char buff[64]; + seprintf(buff, lastof(buff), "Out of memory. Cannot allocate " PRINTF_SIZE " bytes", requested_size); + throw Script_FatalError(buff); + } + } + void *Malloc(SQUnsignedInteger size) { - void *p = MallocT(size); + void *p = malloc(size); this->allocated_size += size; + this->CheckAllocation(size, p); + #ifdef SCRIPT_DEBUG_ALLOCATIONS assert(p != nullptr); assert(this->allocations.find(p) == this->allocations.end()); @@ -73,11 +128,13 @@ struct ScriptAllocator { this->allocations.erase(p); #endif - void *new_p = ReallocT(static_cast(p), size); + void *new_p = realloc(p, size); this->allocated_size -= oldsize; this->allocated_size += size; + this->CheckAllocation(size, p); + #ifdef SCRIPT_DEBUG_ALLOCATIONS assert(new_p != nullptr); assert(this->allocations.find(p) == this->allocations.end()); @@ -104,6 +161,7 @@ struct ScriptAllocator { this->allocated_size = 0; this->allocation_limit = static_cast(_settings_game.script.script_max_memory_megabytes) << 20; if (this->allocation_limit == 0) this->allocation_limit = SAFE_LIMIT; // in case the setting is somehow zero + this->error_thrown = false; } ~ScriptAllocator() @@ -114,6 +172,14 @@ struct ScriptAllocator { } }; +/** + * In the memory allocator for Squirrel we want to directly use malloc/realloc, so when the OS + * does not have enough memory the game does not go into unrecoverable error mode and kill the + * whole game, but rather let the AI die though then we need to circumvent MallocT/ReallocT. + * For the rest of this code, the safeguards should be in place though! + */ +#include "../safeguards.h" + ScriptAllocator *_squirrel_allocator = nullptr; /* See 3rdparty/squirrel/squirrel/sqmem.cpp for the default allocator implementation, which this overrides */ diff --git a/src/settings.cpp b/src/settings.cpp index eeebb3057f..66771fae6f 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -65,6 +65,7 @@ #include "fios.h" #include "strings_func.h" #include "toolbar_gui.h" +#include "vehicle_func.h" #include "void_map.h" #include "station_base.h" @@ -496,6 +497,59 @@ static void Write_ValidateSetting(void *ptr, const SettingDesc *sd, int32 val) WriteValue(ptr, sd->save.conv, (int64)val); } +/** + * Set the string value of a setting. + * @param ptr Pointer to the storage location (might be a pointer to a pointer). + * @param sld Pointer to the information for the conversions and limitations to apply. + * @param p The string to save. + */ +static void Write_ValidateString(void *ptr, const SaveLoad *sld, const char *p) +{ + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STRB: + case SLE_VAR_STRBQ: + if (p != nullptr) { + char *begin = (char*)ptr; + char *end = begin + sld->length - 1; + strecpy(begin, p, end); + str_validate(begin, end, SVS_NONE); + } + break; + + case SLE_VAR_STR: + case SLE_VAR_STRQ: + free(*(char**)ptr); + *(char**)ptr = p == nullptr ? nullptr : stredup(p); + break; + + default: NOT_REACHED(); + } +} + +/** + * Set the string value of a setting. + * @param ptr Pointer to the std::string. + * @param sld Pointer to the information for the conversions and limitations to apply. + * @param p The string to save. + */ +static void Write_ValidateStdString(void *ptr, const SaveLoad *sld, const char *p) +{ + std::string *dst = reinterpret_cast(ptr); + + switch (GetVarMemType(sld->conv)) { + case SLE_VAR_STR: + case SLE_VAR_STRQ: + if (p != nullptr) { + dst->assign(p); + } else { + dst->clear(); + } + break; + + default: NOT_REACHED(); + } +} + /** * Load values from a group of an IniFile structure into the internal representation * @param ini pointer to IniFile structure that holds administrative information @@ -552,38 +606,11 @@ static void IniLoadSettings(IniFile *ini, const SettingDesc *sd, const char *grp break; case SDT_STRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STRB: - case SLE_VAR_STRBQ: - if (p != nullptr) strecpy((char*)ptr, (const char*)p, (char*)ptr + sld->length - 1); - break; - - case SLE_VAR_STR: - case SLE_VAR_STRQ: - free(*(char**)ptr); - *(char**)ptr = p == nullptr ? nullptr : stredup((const char*)p); - break; - - case SLE_VAR_CHAR: if (p != nullptr) *(char *)ptr = *(const char *)p; break; - - default: NOT_REACHED(); - } + Write_ValidateString(ptr, sld, (const char *)p); break; case SDT_STDSTRING: - switch (GetVarMemType(sld->conv)) { - case SLE_VAR_STR: - case SLE_VAR_STRQ: - if (p != nullptr) { - reinterpret_cast(ptr)->assign((const char *)p); - } else { - reinterpret_cast(ptr)->clear(); - } - break; - - default: NOT_REACHED(); - } - + Write_ValidateStdString(ptr, sld, (const char *)p); break; case SDT_INTLIST: { @@ -717,7 +744,6 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp } break; - case SLE_VAR_CHAR: buf[0] = *(char*)ptr; buf[1] = '\0'; break; default: NOT_REACHED(); } break; @@ -1158,13 +1184,14 @@ static bool InvalidateNewGRFChangeWindows(int32 p1) { InvalidateWindowClassesData(WC_SAVELOAD); DeleteWindowByClass(WC_GAME_OPTIONS); - ReInitAllWindows(); + ReInitAllWindows(_gui_zoom_cfg); return true; } static bool InvalidateCompanyLiveryWindow(int32 p1) { InvalidateWindowClassesData(WC_COMPANY_COLOUR, -1); + ResetVehicleColourMap(); return RedrawScreen(p1); } @@ -2095,13 +2122,13 @@ bool SetSettingValue(uint index, const char *value, bool force_newgame) const SettingDesc *sd = &_settings[index]; assert(sd->save.conv & SLF_NO_NETWORK_SYNC); - if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ) { - char **var = (char**)GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); - free(*var); - *var = strcmp(value, "(null)") == 0 ? nullptr : stredup(value); - } else { - char *var = (char*)GetVariableAddress(nullptr, &sd->save); - strecpy(var, value, &var[sd->save.length - 1]); + if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && strcmp(value, "(null)") == 0) { + value = nullptr; + } + + void *ptr = GetVariableAddress((_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game, &sd->save); + if (sd->desc.cmd == SDT_STRING) { + Write_ValidateString(ptr, &sd->save, value); } if (sd->desc.proc != nullptr) sd->desc.proc(0); diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index 8a73b84fe7..d90942b192 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -21,6 +21,7 @@ #include "string_func.h" #include "widgets/dropdown_type.h" #include "widgets/dropdown_func.h" +#include "widgets/slider_func.h" #include "highscore.h" #include "base_media_base.h" #include "company_base.h" @@ -36,7 +37,9 @@ #include "fontcache.h" #include "settings_func.h" #include "zoom_func.h" +#include "rev.h" #include "video/video_driver.hpp" +#include "music/music_driver.hpp" #include #include @@ -224,7 +227,10 @@ struct GameOptionsWindow : Window { case WID_GO_LANG_DROPDOWN: { // Setup interface language dropdown for (uint i = 0; i < _languages.size(); i++) { - auto item = new DropDownListParamStringItem(STR_JUST_RAW_STRING, i, false); + bool hide_language = IsReleasedVersion() && !_languages[i].IsReasonablyFinished(); + if (hide_language) continue; + bool hide_percentage = IsReleasedVersion() || _languages[i].missing < _settings_client.gui.missing_strings_threshold; + auto item = new DropDownListParamStringItem(hide_percentage ? STR_JUST_RAW_STRING : STR_GAME_OPTIONS_LANGUAGE_PERCENTAGE, i, false); if (&_languages[i] == _current_language) { *selected_index = i; item->SetParamStr(0, _languages[i].own_name); @@ -236,6 +242,7 @@ struct GameOptionsWindow : Window { * entries in the dropdown list. */ item->SetParamStr(0, _languages[i].name); } + item->SetParam(1, (LANGUAGE_TOTAL_STRINGS - _languages[i].missing) * 100 / LANGUAGE_TOTAL_STRINGS); list.emplace_back(item); } std::sort(list.begin(), list.end(), DropDownListStringItem::NatSortFunc); @@ -359,6 +366,14 @@ struct GameOptionsWindow : Window { SetDParamStr(0, BaseMusic::GetUsedSet()->GetDescription(GetCurrentLanguageIsoCode())); DrawString(r.left, r.right, r.top, STR_BLACK_RAW_STRING); break; + + case WID_GO_BASE_SFX_VOLUME: + DrawVolumeSliderWidget(r, _settings_client.music.effect_vol); + break; + + case WID_GO_BASE_MUSIC_VOLUME: + DrawVolumeSliderWidget(r, _settings_client.music.music_vol); + break; } } @@ -507,9 +522,35 @@ struct GameOptionsWindow : Window { _video_hw_accel = !_video_hw_accel; ShowErrorMessage(STR_GAME_OPTIONS_VIDEO_ACCELERATION_RESTART, INVALID_STRING_ID, WL_INFO); this->SetWidgetLoweredState(WID_GO_VIDEO_ACCEL_BUTTON, _video_hw_accel); +#ifndef __APPLE__ + this->SetWidgetDisabledState(WID_GO_VIDEO_VSYNC_BUTTON, !_video_hw_accel); +#endif this->SetDirty(); break; + case WID_GO_VIDEO_VSYNC_BUTTON: + if (!_video_hw_accel) break; + + _video_vsync = !_video_vsync; + VideoDriver::GetInstance()->ToggleVsync(_video_vsync); + + this->SetWidgetLoweredState(WID_GO_VIDEO_VSYNC_BUTTON, _video_vsync); + this->SetDirty(); + break; + + case WID_GO_BASE_SFX_VOLUME: + case WID_GO_BASE_MUSIC_VOLUME: { + byte &vol = (widget == WID_GO_BASE_MUSIC_VOLUME) ? _settings_client.music.music_vol : _settings_client.music.effect_vol; + if (ClickVolumeSliderWidget(this->GetWidget(widget)->GetCurrentRect(), pt, vol)) { + if (widget == WID_GO_BASE_MUSIC_VOLUME) MusicDriver::GetInstance()->SetVolume(vol); + this->SetDirty(); + SetWindowClassesDirty(WC_MUSIC_WINDOW); + } + + if (click_count > 0) this->mouse_capture_widget = widget; + break; + } + default: { int selected; DropDownList list = this->BuildDropDownList(widget, &selected); @@ -548,7 +589,7 @@ struct GameOptionsWindow : Window { case WID_GO_CURRENCY_DROPDOWN: // Currency if (index == CURRENCY_CUSTOM) ShowCustCurrency(); this->opt->locale.currency = index; - ReInitAllWindows(); + ReInitAllWindows(false); break; case WID_GO_AUTOSAVE_DROPDOWN: // Autosave options @@ -563,7 +604,7 @@ struct GameOptionsWindow : Window { ClearAllCachedNames(); UpdateAllVirtCoords(); CheckBlitter(); - ReInitAllWindows(); + ReInitAllWindows(false); break; case WID_GO_RESOLUTION_DROPDOWN: // Change resolution @@ -606,7 +647,7 @@ struct GameOptionsWindow : Window { UpdateCursorSize(); UpdateAllVirtCoords(); FixTitleGameZoom(); - ReInitAllWindows(); + ReInitAllWindows(true); } break; } @@ -620,6 +661,7 @@ struct GameOptionsWindow : Window { ClearFontCache(); LoadStringWidthTable(); UpdateAllVirtCoords(); + ReInitAllWindows(true); } break; } @@ -654,6 +696,11 @@ struct GameOptionsWindow : Window { this->SetWidgetLoweredState(WID_GO_16BPP_BUTTON, _ini_blitter == "16bpp-simple"); this->SetWidgetLoweredState(WID_GO_32BPP_BUTTON, _ini_blitter == "32bpp-anim" || _ini_blitter == ""); +#ifndef __APPLE__ + this->SetWidgetLoweredState(WID_GO_VIDEO_VSYNC_BUTTON, _video_vsync); + this->SetWidgetDisabledState(WID_GO_VIDEO_VSYNC_BUTTON, !_video_hw_accel); +#endif + bool missing_files = BaseGraphics::GetUsedSet()->GetNumMissing() == 0; this->GetWidget(WID_GO_BASE_GRF_STATUS)->SetDataTip(missing_files ? STR_EMPTY : STR_GAME_OPTIONS_BASE_GRF_STATUS, STR_NULL); @@ -822,6 +869,7 @@ struct BaseSettingEntry { virtual void Init(byte level = 0); virtual void FoldAll() {} virtual void UnFoldAll() {} + virtual void ResetAll() = 0; /** * Set whether this is the last visible entry of the parent node. @@ -858,6 +906,7 @@ struct SettingEntry : BaseSettingEntry { SettingEntry(const char *name); virtual void Init(byte level = 0); + virtual void ResetAll(); virtual uint Length() const; virtual uint GetMaxHelpHeight(int maxw); virtual bool UpdateFilterState(SettingFilter &filter, bool force_visible); @@ -895,6 +944,7 @@ struct SettingsContainer { } void Init(byte level = 0); + void ResetAll(); void FoldAll(); void UnFoldAll(); @@ -917,6 +967,7 @@ struct SettingsPage : BaseSettingEntry, SettingsContainer { SettingsPage(StringID title); virtual void Init(byte level = 0); + virtual void ResetAll(); virtual void FoldAll(); virtual void UnFoldAll(); @@ -1059,6 +1110,13 @@ void SettingEntry::Init(byte level) assert(this->setting != nullptr); } +/* Sets the given setting entry to its default value */ +void SettingEntry::ResetAll() +{ + int32 default_value = ReadValue(&this->setting->desc.def, this->setting->save.conv); + SetSettingValue(this->index, default_value); +} + /** * Set the button-depressed flags (#SEF_LEFT_DEPRESSED and #SEF_RIGHT_DEPRESSED) to a specified value * @param new_val New value for the button flags @@ -1260,6 +1318,14 @@ void SettingsContainer::Init(byte level) } } +/** Resets all settings to their default values */ +void SettingsContainer::ResetAll() +{ + for (auto settings_entry : this->entries) { + settings_entry->ResetAll(); + } +} + /** Recursively close all folds of sub-pages */ void SettingsContainer::FoldAll() { @@ -1411,6 +1477,14 @@ void SettingsPage::Init(byte level) SettingsContainer::Init(level + 1); } +/** Resets all settings to their default values */ +void SettingsPage::ResetAll() +{ + for (auto settings_entry : this->entries) { + settings_entry->ResetAll(); + } +} + /** Recursively close all (filtered) folds of sub-pages */ void SettingsPage::FoldAll() { @@ -1887,6 +1961,20 @@ enum WarnHiddenResult { WHR_CATEGORY_TYPE, ///< Both category and type settings filtered matches away. }; +/** + * Callback function for the reset all settings button + * @param w Window which is calling this callback + * @param confirmed boolean value, true when yes was clicked, false otherwise + */ +static void ResetAllSettingsConfirmationCallback(Window *w, bool confirmed) +{ + if (confirmed) { + GetSettingsTree().ResetAll(); + GetSettingsTree().FoldAll(); + w->InvalidateData(); + } +} + /** Window to edit settings of the game. */ struct GameSettingsWindow : Window { static const int SETTINGTREE_LEFT_OFFSET = 5; ///< Position of left edge of setting values @@ -2129,6 +2217,15 @@ struct GameSettingsWindow : Window { this->InvalidateData(); break; + case WID_GS_RESET_ALL: + ShowQuery( + STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_CAPTION, + STR_CONFIG_SETTING_RESET_ALL_CONFIRMATION_DIALOG_TEXT, + this, + ResetAllSettingsConfirmationCallback + ); + break; + case WID_GS_RESTRICT_DROPDOWN: { DropDownList list = this->BuildDropDownList(widget); if (!list.empty()) { @@ -2485,6 +2582,7 @@ static const NWidgetPart _nested_settings_selection_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_EXPAND_ALL), SetDataTip(STR_CONFIG_SETTING_EXPAND_ALL, STR_NULL), NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_COLLAPSE_ALL), SetDataTip(STR_CONFIG_SETTING_COLLAPSE_ALL, STR_NULL), + NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_GS_RESET_ALL), SetDataTip(STR_CONFIG_SETTING_RESET_ALL, STR_NULL), NWidget(WWT_PANEL, COLOUR_MAUVE), SetFill(1, 0), SetResize(1, 0), EndContainer(), NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), @@ -2655,7 +2753,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_SEPARATOR: SetDParamStr(0, _custom_currency.separator); str = STR_JUST_RAW_STRING; - len = 1; + len = sizeof(_custom_currency.separator) - 1; // Number of characters excluding '\0' termination line = WID_CC_SEPARATOR; break; @@ -2663,7 +2761,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_PREFIX: SetDParamStr(0, _custom_currency.prefix); str = STR_JUST_RAW_STRING; - len = 12; + len = sizeof(_custom_currency.prefix) - 1; // Number of characters excluding '\0' termination line = WID_CC_PREFIX; break; @@ -2671,7 +2769,7 @@ struct CustomCurrencyWindow : Window { case WID_CC_SUFFIX: SetDParamStr(0, _custom_currency.suffix); str = STR_JUST_RAW_STRING; - len = 12; + len = sizeof(_custom_currency.suffix) - 1; // Number of characters excluding '\0' termination line = WID_CC_SUFFIX; break; diff --git a/src/settings_type.h b/src/settings_type.h index 68012ce697..7b619e7380 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -277,7 +277,7 @@ struct NetworkSettings { bool server_advertise; ///< advertise the server to the masterserver char client_name[NETWORK_CLIENT_NAME_LENGTH]; ///< name of the player (as client) char default_company_pass[NETWORK_PASSWORD_LENGTH]; ///< default password for new companies in encrypted form - char connect_to_ip[NETWORK_HOSTNAME_LENGTH]; ///< default for the "Add server" query + char connect_to_ip[NETWORK_HOSTNAME_PORT_LENGTH]; ///< default for the "Add server" query char network_id[NETWORK_SERVER_ID_LENGTH]; ///< network ID for servers bool autoclean_companies; ///< automatically remove companies that are not in use uint8 autoclean_unprotected; ///< remove passwordless companies after this many months @@ -288,10 +288,8 @@ struct NetworkSettings { uint8 max_spectators; ///< maximum amount of spectators Year restart_game_year; ///< year the server restarts uint8 min_active_clients; ///< minimum amount of active clients to unpause the game - uint8 server_lang; ///< language of the server bool reload_cfg; ///< reload the config file before restarting - char last_host[NETWORK_HOSTNAME_LENGTH]; ///< IP address of the last joined server - uint16 last_port; ///< port of the last joined server + char last_joined[NETWORK_HOSTNAME_PORT_LENGTH]; ///< Last joined server bool no_http_content_downloads; ///< do not do content downloads over HTTP }; diff --git a/src/signs_gui.cpp b/src/signs_gui.cpp index 088aa50e7d..7e482b122f 100644 --- a/src/signs_gui.cpp +++ b/src/signs_gui.cpp @@ -194,15 +194,17 @@ struct SignListWindow : Window, SignList { { switch (widget) { case WID_SIL_LIST: { - uint y = Center(r.top + WD_FRAMERECT_TOP, this->resize.step_height); // Offset from top of widget. + uint y = r.top + WD_FRAMERECT_TOP; // Offset from top of widget. + uint text_offset_y = (this->resize.step_height - FONT_HEIGHT_NORMAL + 1) / 2; /* No signs? */ if (this->vscroll->GetCount() == 0) { - DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y, STR_STATION_LIST_NONE); + DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, y + text_offset_y, STR_STATION_LIST_NONE); return; } + Dimension d = GetSpriteSize(SPR_COMPANY_ICON); bool rtl = _current_text_dir == TD_RTL; - int sprite_offset_y = (FONT_HEIGHT_NORMAL - 10) / 2 + 1; + int sprite_offset_y = (this->resize.step_height - d.height + 1) / 2; uint icon_left = 4 + (rtl ? r.right - this->text_offset : r.left); uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : this->text_offset); uint text_right = r.right - (rtl ? this->text_offset : WD_FRAMERECT_RIGHT); @@ -214,7 +216,7 @@ struct SignListWindow : Window, SignList { if (si->owner != OWNER_NONE) DrawCompanyIcon(si->owner, icon_left, y + sprite_offset_y); SetDParam(0, si->index); - DrawString(text_left, text_right, y, STR_SIGN_NAME, TC_YELLOW); + DrawString(text_left, text_right, y + text_offset_y, STR_SIGN_NAME, TC_YELLOW); y += this->resize.step_height; } break; @@ -265,7 +267,7 @@ struct SignListWindow : Window, SignList { case WID_SIL_LIST: { Dimension spr_dim = GetSpriteSize(SPR_COMPANY_ICON); this->text_offset = WD_FRAMETEXT_LEFT + spr_dim.width + 2; // 2 pixels space between icon and the sign text. - resize->height = std::max(FONT_HEIGHT_NORMAL, spr_dim.height); + resize->height = std::max(FONT_HEIGHT_NORMAL, spr_dim.height + 2); resize->height = std::max(GetMinSizing(NWST_STEP), resize->height); Dimension d = {(uint)(this->text_offset + WD_FRAMETEXT_RIGHT), WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM}; *size = maxdim(*size, d); @@ -368,8 +370,8 @@ static const NWidgetPart _nested_sign_list_widgets[] = { EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_SIL_LIST), SetMinimalSize(WD_FRAMETEXT_LEFT + 16 + 255 + WD_FRAMETEXT_RIGHT, 50), - SetResize(1, 10), SetFill(1, 0), SetScrollbar(WID_SIL_SCROLLBAR), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_SIL_LIST), SetMinimalSize(WD_FRAMETEXT_LEFT + 16 + 255 + WD_FRAMETEXT_RIGHT, 0), + SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_SIL_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PANEL, COLOUR_BROWN), SetFill(1, 1), NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_SIL_FILTER_TEXT), SetMinimalSize(80, 12), SetResize(1, 0), SetFill(1, 0), SetPadding(2, 2, 2, 2), diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index ad7105c938..1fbad3d779 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -22,6 +22,7 @@ #include "window_func.h" #include "company_base.h" #include "guitimer_func.h" +#include "zoom_func.h" #include "smallmap_gui.h" @@ -1183,8 +1184,12 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() this->min_number_of_fixed_rows = std::max(this->min_number_of_fixed_rows, height); this->min_number_of_columns = std::max(this->min_number_of_columns, num_columns); } + + /* Width of the legend blob. */ + this->legend_width = (FONT_HEIGHT_SMALL - ScaleFontTrad(1)) * 8 / 5; + /* The width of a column is the minimum width of all texts + the size of the blob + some spacing */ - this->column_width = min_width + LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + this->column_width = min_width + this->legend_width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; } /* virtual */ void SmallMapWindow::OnPaint() @@ -1221,11 +1226,13 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() uint x = rtl ? r.right - this->column_width - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT; uint y = Center(y_org, this->row_height, FONT_HEIGHT_SMALL); uint i = 0; // Row counter for industry legend. + uint row_height = FONT_HEIGHT_SMALL; + int padding = ScaleFontTrad(1); - uint text_left = rtl ? 0 : LEGEND_BLOB_WIDTH + WD_FRAMERECT_LEFT; - uint text_right = this->column_width - 1 - (rtl ? LEGEND_BLOB_WIDTH + WD_FRAMERECT_RIGHT : 0); - uint blob_left = rtl ? this->column_width - 1 - LEGEND_BLOB_WIDTH : 0; - uint blob_right = rtl ? this->column_width - 1 : LEGEND_BLOB_WIDTH; + uint text_left = rtl ? 0 : this->legend_width + WD_FRAMERECT_LEFT; + uint text_right = this->column_width - padding - (rtl ? this->legend_width + WD_FRAMERECT_RIGHT : 0); + uint blob_left = rtl ? this->column_width - padding - this->legend_width : 0; + uint blob_right = rtl ? this->column_width - padding : this->legend_width; StringID string = STR_NULL; switch (this->map_type) { @@ -1277,7 +1284,7 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() DrawString(x + text_left, x + text_right, y, string, TC_GREY); } else { DrawString(x + text_left, x + text_right, y, string, TC_BLACK); - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); // Outer border of the legend colour + GfxFillRect(x + blob_left, y + padding, x + blob_right, y + row_height - 1, PC_BLACK); // Outer border of the legend colour } break; } @@ -1286,11 +1293,11 @@ void SmallMapWindow::RebuildColourIndexIfNecessary() default: if (this->map_type == SMT_CONTOUR) SetDParam(0, tbl->height * TILE_HEIGHT_STEP); /* Anything that is not an industry or a company is using normal process */ - GfxFillRect(x + blob_left, y + 1, x + blob_right, y + FONT_HEIGHT_SMALL - 1, PC_BLACK); + GfxFillRect(x + blob_left, y + padding, x + blob_right, y + row_height - 1, PC_BLACK); DrawString(x + text_left, x + text_right, y, tbl->legend); break; } - GfxFillRect(x + blob_left + 1, y + 2, x + blob_right - 1, y + FONT_HEIGHT_SMALL - 2, legend_colour); // Legend colour + GfxFillRect(x + blob_left + 1, y + padding + 1, x + blob_right - 1, y + row_height - 2, legend_colour); // Legend colour y += this->row_height; } diff --git a/src/smallmap_gui.h b/src/smallmap_gui.h index fc73f70d8e..df10c4ada8 100644 --- a/src/smallmap_gui.h +++ b/src/smallmap_gui.h @@ -64,7 +64,6 @@ protected: static bool show_towns; ///< Display town names in the smallmap. static int map_height_limit; ///< Currently used/cached map height limit. - static const uint LEGEND_BLOB_WIDTH = 8; ///< Width of the coloured blob in front of a line text in the #WID_SM_LEGEND widget. static const uint INDUSTRY_MIN_NUMBER_OF_COLUMNS = 2; ///< Minimal number of columns in the #WID_SM_LEGEND widget for the #SMT_INDUSTRY legend. static const uint FORCE_REFRESH_PERIOD = 930; ///< map is redrawn after that many milliseconds. static const uint BLINK_PERIOD = 450; ///< highlight blinking interval in milliseconds. @@ -72,6 +71,7 @@ protected: uint min_number_of_columns; ///< Minimal number of columns in legends. uint min_number_of_fixed_rows; ///< Minimal number of rows in the legends for the fixed layouts only (all except #SMT_INDUSTRY). uint column_width; ///< Width of a column in the #WID_SM_LEGEND widget. + uint legend_width; ///< Width of legend 'blob'. const uint row_height; ///< Heigth of each row in the #WID_SM_LEGEND widget. bool show_legend; ///< Display map legend. Point lmb_scroll_pt; ///< Starting point for scrolling minimap with left mouse button. diff --git a/src/sound.cpp b/src/sound.cpp index e6c1cb07c8..d91476729b 100644 --- a/src/sound.cpp +++ b/src/sound.cpp @@ -238,8 +238,7 @@ static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, in { if (_settings_client.music.effect_vol == 0) return; - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { const Viewport *vp = w->viewport; if (vp != nullptr && @@ -252,7 +251,7 @@ static void SndPlayScreenCoordFx(SoundID sound, int left, int right, int top, in StartSound( sound, panning, - (_settings_client.music.effect_vol * _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN]) / 256 + _vol_factor_by_zoom[vp->zoom - ZOOM_LVL_BEGIN] ); return; } @@ -281,7 +280,7 @@ void SndPlayVehicleFx(SoundID sound, const Vehicle *v) void SndPlayFx(SoundID sound) { - StartSound(sound, 0.5, _settings_client.music.effect_vol); + StartSound(sound, 0.5, UINT8_MAX); } INSTANTIATE_BASE_MEDIA_METHODS(BaseMedia, SoundsSet) diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 7266ad6187..451dedbad4 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1109,13 +1109,13 @@ static inline byte *CreateMulti(byte *layout, int n, byte b) * @param plat_len The length of the platforms. * @param statspec The specification of the station to (possibly) get the layout from. */ -void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec) +void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const StationSpec *statspec) { - if (statspec != nullptr && statspec->lengths >= plat_len && - statspec->platforms[plat_len - 1] >= numtracks && - statspec->layouts[plat_len - 1][numtracks - 1]) { + if (statspec != nullptr && statspec->layouts.size() >= plat_len && + statspec->layouts[plat_len - 1].size() >= numtracks && + !statspec->layouts[plat_len - 1][numtracks - 1].empty()) { /* Custom layout defined, follow it. */ - memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1], + memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1].data(), plat_len * numtracks); return; } @@ -1124,9 +1124,9 @@ void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSp CreateSingle(layout, numtracks); } else { if (numtracks & 1) layout = CreateSingle(layout, plat_len); - numtracks >>= 1; + int n = numtracks >> 1; - while (--numtracks >= 0) { + while (--n >= 0) { layout = CreateMulti(layout, plat_len, 4); layout = CreateMulti(layout, plat_len, 6); } @@ -2394,9 +2394,9 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) if (flags & DC_EXEC) { for (uint i = 0; i < st->airport.GetNumHangars(); ++i) { - DeleteWindowById( - WC_VEHICLE_DEPOT, st->airport.GetHangarTile(i) - ); + TileIndex tile_cur = st->airport.GetHangarTile(i); + OrderBackup::Reset(tile_cur, false); + DeleteWindowById(WC_VEHICLE_DEPOT, tile_cur); } const AirportSpec *as = st->airport.GetSpec(); @@ -2418,7 +2418,6 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags) cost.AddCost(_price[PR_CLEAR_STATION_AIRPORT]); if (flags & DC_EXEC) { - if (IsHangarTile(tile_cur)) OrderBackup::Reset(tile_cur, false); DeleteAnimatedTile(tile_cur); DoClearSquare(tile_cur); DeleteNewGRFInspectWindow(GSF_AIRPORTTILES, tile_cur); @@ -2844,8 +2843,8 @@ static void DrawTile_Station(TileInfo *ti) } /* Ensure the chosen tile layout is valid for this custom station */ - if (statspec->renderdata != nullptr) { - layout = &statspec->renderdata[tile_layout < statspec->tiles ? tile_layout : (uint)GetRailStationAxis(ti->tile)]; + if (!statspec->renderdata.empty()) { + layout = &statspec->renderdata[tile_layout < statspec->renderdata.size() ? tile_layout : (uint)GetRailStationAxis(ti->tile)]; if (!layout->NeedsPreprocessing()) { t = layout; layout = nullptr; @@ -3467,8 +3466,7 @@ static void UpdateStationRating(Station *st) byte_inc_sat(&st->time_since_load); byte_inc_sat(&st->time_since_unload); - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { GoodsEntry *ge = &st->goods[cs->Index()]; /* Slowly increase the rating back to his original level in the case we * didn't deliver cargo yet to this station. This happens when a bribe diff --git a/src/station_gui.cpp b/src/station_gui.cpp index cd893410d9..d71ae3ac16 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -153,9 +153,6 @@ void CheckRedrawStationCoverage(const Window *w) * @param type Cargo type * @param amount Cargo amount * @param rating ratings data for that particular cargo - * - * @note Each cargo-bar is 16 pixels wide and 6 pixels high - * @note Each rating 14 pixels wide and 1 pixel high and is 1 pixel below the cargo-bar */ static void StationsWndShowStationRating(int left, int right, int y, CargoID type, uint amount, byte rating) { @@ -165,32 +162,33 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoID typ const CargoSpec *cs = CargoSpec::Get(type); if (!cs->IsValid()) return; + int padding = ScaleFontTrad(1); + int width = right - left; int colour = cs->rating_colour; TextColour tc = GetContrastColour(colour); - uint w = (std::min(amount, units_full) + 5) / 36; + uint w = std::min(amount + 5, units_full) * width / units_full; - int height = GetCharacterHeight(FS_SMALL); + int height = GetCharacterHeight(FS_SMALL) + padding - 1; - /* Draw total cargo (limited) on station (fits into 16 pixels) */ - if (w != 0) GfxFillRect(left, y, left + w - 1, y + height, colour); - - /* Draw a one pixel-wide bar of additional cargo meter, useful - * for stations with only a small amount (<=30) */ - if (w == 0) { - uint rest = amount / 5; + if (amount > 30) { + /* Draw total cargo (limited) on station */ + GfxFillRect(left, y, left + w - 1, y + height, colour); + } else { + /* Draw a (scaled) one pixel-wide bar of additional cargo meter, useful + * for stations with only a small amount (<=30) */ + uint rest = ScaleFontTrad(amount) / 5; if (rest != 0) { - w += left; - GfxFillRect(w, y + height - rest, w, y + height, colour); + GfxFillRect(left, y + height - rest, left + padding - 1, y + height, colour); } } - DrawString(left + 1, right, y, cs->abbrev, tc); + DrawString(left + padding, right, y, cs->abbrev, tc); - /* Draw green/red ratings bar (fits into 14 pixels) */ - y += height + 2; - GfxFillRect(left + 1, y, left + 14, y, PC_RED); - rating = std::min(rating, rating_full) / 16; - if (rating != 0) GfxFillRect(left + 1, y, left + rating, y, PC_GREEN); + /* Draw green/red ratings bar (fits under the waiting bar) */ + y += height + padding + 1; + GfxFillRect(left + padding, y, right - padding - 1, y + padding - 1, PC_RED); + w = std::min(rating, rating_full) * (width - padding - padding) / rating_full; + if (w != 0) GfxFillRect(left + padding, y, left + w - 1, y + padding - 1, PC_GREEN); } typedef GUIList GUIStationList; @@ -214,6 +212,7 @@ protected: GUIStationList stations; Scrollbar *vscroll; + uint rating_width; /** * (Re)Build station list @@ -392,16 +391,18 @@ public: } case WID_STL_LIST: - resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); + resize->height = std::max(FONT_HEIGHT_NORMAL, FONT_HEIGHT_SMALL + ScaleFontTrad(3)); + resize->height = GetMinSizing(NWST_STEP, resize->height); size->height = WD_FRAMERECT_TOP + 5 * resize->height + WD_FRAMERECT_BOTTOM; - break; - case WID_STL_TRAIN: - case WID_STL_TRUCK: - case WID_STL_BUS: - case WID_STL_AIRPLANE: - case WID_STL_SHIP: - size->height = std::max(FONT_HEIGHT_SMALL, 10) + padding.height; + /* Determine appropriate width for mini station rating graph */ + this->rating_width = 0; + const CargoSpec *cs; + FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) { + this->rating_width = std::max(this->rating_width, GetStringBoundingBox(cs->abbrev).width); + } + /* Approximately match original 16 pixel wide rating bars by multiplying string width by 1.6 */ + this->rating_width = this->rating_width * 16 / 10; break; case WID_STL_CARGOALL: @@ -444,8 +445,14 @@ public: case WID_STL_LIST: { bool rtl = _current_text_dir == TD_RTL; int max = std::min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.size()); - uint line_height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL); - int y = Center(r.top + WD_FRAMERECT_TOP, line_height); + int y = r.top + WD_FRAMERECT_TOP; + uint line_height = this->GetWidget(widget)->resize_y; + line_height = GetMinSizing(NWST_STEP, line_height); + /* Spacing between station name and first rating graph. */ + int text_spacing = ScaleFontTrad(5); + /* Spacing between additional rating graphs. */ + int rating_spacing = ScaleFontTrad(4); + for (int i = this->vscroll->GetPosition(); i < max; ++i) { // do until max number of stations of owner const Station *st = this->stations[i]; assert(st->xy != INVALID_TILE); @@ -456,8 +463,8 @@ public: SetDParam(0, st->index); SetDParam(1, st->facilities); - int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_STATION_LIST_STATION); - x += rtl ? -5 : 5; + int x = DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + (line_height - FONT_HEIGHT_NORMAL) / 2, STR_STATION_LIST_STATION); + x += rtl ? -text_spacing : text_spacing; /* show cargo waiting and station ratings */ for (uint j = 0; j < _sorted_standard_cargo_specs_size; j++) { @@ -468,17 +475,16 @@ public: * instead of drawing to the left and then incrementing * the space. */ if (rtl) { - x -= 20; + x -= rating_width + rating_spacing; if (x < r.left + WD_FRAMERECT_LEFT) break; } - StationsWndShowStationRating(x, x + 16, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); + StationsWndShowStationRating(x, x + rating_width, y, cid, st->goods[cid].cargo.TotalCount(), st->goods[cid].rating); if (!rtl) { - x += 20; + x += rating_width + rating_spacing; if (x > r.right - WD_FRAMERECT_RIGHT) break; } } } - y += line_height; } @@ -490,30 +496,30 @@ public: } case WID_STL_NOCARGOWAITING: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER); + int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_NONE, TC_BLACK, SA_HOR_CENTER); break; } case WID_STL_CARGOALL: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); + int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); break; } case WID_STL_FACILALL: { - int cg_ofst = this->IsWidgetLowered(widget) ? 2 : 1; - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); + int cg_ofst = this->IsWidgetLowered(widget) ? 1 : 0; + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, STR_ABBREV_ALL, TC_BLACK, SA_HOR_CENTER); break; } default: if (widget >= WID_STL_CARGOSTART) { const CargoSpec *cs = _sorted_cargo_specs[widget - WID_STL_CARGOSTART]; - int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 2 : 1; - GfxFillRect(r.left + cg_ofst, r.top + cg_ofst, r.right - 2 + cg_ofst, r.bottom - 2 + cg_ofst, cs->rating_colour); + int cg_ofst = HasBit(this->cargo_filter, cs->Index()) ? 1 : 0; + GfxFillRect(r.left + cg_ofst + 1, r.top + cg_ofst + 1, r.right - 1 + cg_ofst, r.bottom - 1 + cg_ofst, cs->rating_colour); TextColour tc = GetContrastColour(cs->rating_colour); - DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER); + DrawString(r.left + cg_ofst, r.right + cg_ofst, r.top + (r.bottom - r.top - FONT_HEIGHT_SMALL) / 2 + cg_ofst, cs->abbrev, tc, SA_HOR_CENTER); } break; } @@ -531,7 +537,7 @@ public: { switch (widget) { case WID_STL_LIST: { - uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST, 0, this->resize.step_height); + uint id_v = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_STL_LIST); if (id_v >= this->stations.size()) return; // click out of list bound const Station *st = this->stations[id_v]; @@ -722,7 +728,8 @@ static NWidgetBase *CargoWidgets(int *biggest_index) for (uint i = 0; i < _sorted_standard_cargo_specs_size; i++) { NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i); - panel->SetMinimalSize(14, 11); + panel->SetMinimalSize(14, 0); + panel->SetMinimalTextLines(1, 0, FS_NORMAL); panel->SetResize(0, 0); panel->SetFill(0, 1); panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); @@ -741,16 +748,16 @@ static const NWidgetPart _nested_company_stations_widgets[] = { NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), NWidget(NWID_HORIZONTAL), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 11), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 11), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 11), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 11), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 11), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1), - NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 11), SetFill(0, 1), EndContainer(), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRAIN), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_TRAIN, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_TRUCK), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_LORRY, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_BUS), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_BUS, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_SHIP), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_SHIP, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_STL_AIRPLANE), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(STR_PLANE, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE), SetFill(0, 1), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_FACILALL), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_FACILITIES), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(5, 0), SetFill(0, 1), EndContainer(), NWidgetFunction(CargoWidgets), - NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(), - NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 11), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1), + NWidget(WWT_PANEL, COLOUR_GREY, WID_STL_NOCARGOWAITING), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_NO_WAITING_CARGO), SetFill(0, 1), EndContainer(), + NWidget(WWT_PUSHBTN, COLOUR_GREY, WID_STL_CARGOALL), SetMinimalSize(14, 0), SetMinimalTextLines(1, 0), SetDataTip(0x0, STR_STATION_LIST_SELECT_ALL_TYPES), SetFill(0, 1), NWidget(WWT_PANEL, COLOUR_GREY), SetDataTip(0x0, STR_NULL), SetResize(1, 0), SetFill(1, 1), EndContainer(), EndContainer(), NWidget(NWID_HORIZONTAL), @@ -1914,7 +1921,7 @@ struct StationViewWindow : public Window { { switch (widget) { case WID_SV_WAITING: - this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP, FONT_HEIGHT_NORMAL) - this->vscroll->GetPosition()); + this->HandleCargoWaitingClick(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SV_WAITING, WD_FRAMERECT_TOP) - this->vscroll->GetPosition()); break; case WID_SV_CATCHMENT: diff --git a/src/stdafx.h b/src/stdafx.h index 42a6106e8a..819eb0e614 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -10,6 +10,15 @@ #ifndef STDAFX_H #define STDAFX_H +#if defined(_WIN32) + /* MinGW defaults to Windows 7 if none of these are set, and they must be set before any MinGW header is included */ +# define NTDDI_VERSION NTDDI_WINXP // Windows XP +# define _WIN32_WINNT 0x501 // Windows XP +# define _WIN32_WINDOWS 0x501 // Windows XP +# define WINVER 0x0501 // Windows XP +# define _WIN32_IE_ 0x0600 // 6.0 (XP+) +#endif + #ifdef _MSC_VER /* Stop Microsoft (and clang-cl) compilers from complaining about potentially-unsafe/potentially-non-standard functions */ # define _CRT_SECURE_NO_DEPRECATE @@ -93,6 +102,7 @@ #include #include #include +#include #ifndef SIZE_MAX # define SIZE_MAX ((size_t)-1) @@ -112,7 +122,7 @@ #endif /* Stuff for GCC */ -#if defined(__GNUC__) || defined(__clang__) +#if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) # define NORETURN __attribute__ ((noreturn)) # define CDECL # define __int64 long long @@ -137,6 +147,12 @@ # endif #endif /* __GNUC__ || __clang__ */ +#if __GNUC__ > 11 || (__GNUC__ == 11 && __GNUC_MINOR__ >= 1) +# define NOACCESS(args) __attribute__ ((access (none, args))) +#else +# define NOACCESS(args) +#endif + #if defined(__WATCOMC__) # define NORETURN # define CDECL @@ -157,12 +173,6 @@ /* Stuff for MSVC */ #if defined(_MSC_VER) # pragma once -# define NTDDI_VERSION NTDDI_WINXP // Windows XP -# define _WIN32_WINNT 0x501 // Windows XP -# define _WIN32_WINDOWS 0x501 // Windows XP -# define WINVER 0x0501 // Windows XP -# define _WIN32_IE_ 0x0600 // 6.0 (XP+) - # define NOMINMAX // Disable min/max macros in windows.h. # pragma warning(disable: 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data @@ -195,14 +205,10 @@ # define CDECL _cdecl # define WARN_FORMAT(string, args) -# ifndef __clang__ -# define FINAL sealed -# else -# define FINAL -# endif +# define FINAL final /* fallthrough attribute, VS 2017 */ -# if (_MSC_VER >= 1910) +# if (_MSC_VER >= 1910) || defined(__clang__) # define FALLTHROUGH [[fallthrough]] # else # define FALLTHROUGH @@ -252,25 +258,26 @@ #endif /* defined(_MSC_VER) */ -/* NOTE: the string returned by these functions is only valid until the next - * call to the same function and is not thread- or reentrancy-safe */ #if !defined(STRGEN) && !defined(SETTINGSGEN) # if defined(_WIN32) char *getcwd(char *buf, size_t size); -# include # include +# include - namespace std { using ::_wfopen; } -# define fopen(file, mode) _wfopen(OTTD2FS(file), _T(mode)) -# define unlink(file) _wunlink(OTTD2FS(file)) +# define fopen(file, mode) _wfopen(OTTD2FS(file).c_str(), _T(mode)) +# define unlink(file) _wunlink(OTTD2FS(file).c_str()) - const char *FS2OTTD(const wchar_t *name); - const wchar_t *OTTD2FS(const char *name, bool console_cp = false); + std::string FS2OTTD(const std::wstring &name); + std::wstring OTTD2FS(const std::string &name); +# elif defined(WITH_ICONV) +# define fopen(file, mode) fopen(OTTD2FS(file).c_str(), mode) + std::string FS2OTTD(const std::string &name); + std::string OTTD2FS(const std::string &name); # else -# define fopen(file, mode) fopen(OTTD2FS(file), mode) - const char *FS2OTTD(const char *name); - const char *OTTD2FS(const char *name); -# endif /* _WIN32 */ + // no override of fopen() since no transformation is required of the filename + template std::string FS2OTTD(T name) { return name; } + template std::string OTTD2FS(T name) { return name; } +# endif /* _WIN32 or WITH_ICONV */ #endif /* STRGEN || SETTINGSGEN */ #if defined(_WIN32) || defined(__OS2__) && !defined(__INNOTEK_LIBC__) diff --git a/src/strgen/strgen.cpp b/src/strgen/strgen.cpp index 9377e63622..68002cc3f0 100644 --- a/src/strgen/strgen.cpp +++ b/src/strgen/strgen.cpp @@ -273,13 +273,14 @@ struct HeaderFileWriter : HeaderWriter, FileWriter { const char *real_filename; /** The previous string ID that was printed. */ int prev; + uint total_strings; /** * Open a file to write to. * @param filename The file to open. */ HeaderFileWriter(const char *filename) : FileWriter("tmp.xxx"), - real_filename(stredup(filename)), prev(0) + real_filename(stredup(filename)), prev(0), total_strings(0) { fprintf(this->fh, "/* This file is automatically generated. Do not modify */\n\n"); fprintf(this->fh, "#ifndef TABLE_STRINGS_H\n"); @@ -297,6 +298,7 @@ struct HeaderFileWriter : HeaderWriter, FileWriter { if (prev + 1 != stringid) fprintf(this->fh, "\n"); fprintf(this->fh, "static const StringID %s = 0x%X;\n", name, stringid); prev = stringid; + total_strings++; } void Finalise(const StringData &data) @@ -311,8 +313,10 @@ struct HeaderFileWriter : HeaderWriter, FileWriter { "\n" "static const uint LANGUAGE_PACK_VERSION = 0x%X;\n" "static const uint LANGUAGE_MAX_PLURAL = %u;\n" - "static const uint LANGUAGE_MAX_PLURAL_FORMS = %d;\n\n", - (uint)data.Version(), (uint)lengthof(_plural_forms), max_plural_forms + "static const uint LANGUAGE_MAX_PLURAL_FORMS = %d;\n" + "static const uint LANGUAGE_TOTAL_STRINGS = %u;\n" + "\n", + (uint)data.Version(), (uint)lengthof(_plural_forms), max_plural_forms, total_strings ); fprintf(this->fh, "#endif /* TABLE_STRINGS_H */\n"); diff --git a/src/string.cpp b/src/string.cpp index adc757b871..38f7d1bd10 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -192,19 +192,35 @@ static void str_validate(T &dst, const char *str, const char *last, StringValida while (str <= last && *str != '\0') { size_t len = Utf8EncodedCharLen(*str); - /* If the character is unknown, i.e. encoded length is 0 - * we assume worst case for the length check. - * The length check is needed to prevent Utf8Decode to read - * over the terminating '\0' if that happens to be placed - * within the encoding of an UTF8 character. */ - if ((len == 0 && str + 4 > last) || str + len > last) break; - WChar c; - len = Utf8Decode(&c, str); - /* It's possible to encode the string termination character - * into a multiple bytes. This prevents those termination - * characters to be skipped */ - if (c == '\0') break; + /* If the first byte does not look like the first byte of an encoded + * character, i.e. encoded length is 0, then this byte is definitely bad + * and it should be skipped. + * When the first byte looks like the first byte of an encoded character, + * then the remaining bytes in the string are checked whether the whole + * encoded character can be there. If that is not the case, this byte is + * skipped. + * Finally we attempt to decode the encoded character, which does certain + * extra validations to see whether the correct number of bytes were used + * to encode the character. If that is not the case, the byte is probably + * invalid and it is skipped. We could emit a question mark, but then the + * logic below cannot just copy bytes, it would need to re-encode the + * decoded characters as the length in bytes may have changed. + * + * The goals here is to get as much valid Utf8 encoded characters from the + * source string to the destination string. + * + * Note: a multi-byte encoded termination ('\0') will trigger the encoded + * char length and the decoded length to differ, so it will be ignored as + * invalid character data. If it were to reach the termination, then we + * would also reach the "last" byte of the string and a normal '\0' + * termination will be placed after it. + */ + if (len == 0 || str + len > last || len != Utf8Decode(&c, str)) { + /* Maybe the next byte is still a valid character? */ + str++; + continue; + } if ((IsPrintable(c) && (c < SCC_SPRITE_START || c > SCC_SPRITE_END)) || ((settings & SVS_ALLOW_CONTROL_CODE) != 0 && c == SCC_ENCODED)) { /* Copy the character back. Even if dst is current the same as str @@ -225,6 +241,8 @@ static void str_validate(T &dst, const char *str, const char *last, StringValida if ((settings & SVS_REPLACE_WITH_QUESTION_MARK) != 0) *dst++ = '?'; } } + + /* String termination, if needed, is left to the caller of this function. */ } /** @@ -302,6 +320,66 @@ bool StrValid(const char *str, const char *last) return *str == '\0'; } +/** + * Trim the spaces from the begin of given string in place, i.e. the string buffer + * that is passed will be modified whenever spaces exist in the given string. + * When there are spaces at the begin, the whole string is moved forward. + * @param str The string to perform the in place left trimming on. + */ +static void StrLeftTrimInPlace(char *str) +{ + if (StrEmpty(str)) return; + + char *first_non_space = str; + while (*first_non_space == ' ') first_non_space++; + + if (first_non_space == str) return; + + /* The source will reach '\0' first, but set the '\0' on the destination afterwards. */ + char *dst = str; + for (char *src = first_non_space; *src != '\0'; dst++, src++) *dst = *src; + *dst = '\0'; +} + +/** + * Trim the spaces from the end of given string in place, i.e. the string buffer + * that is passed will be modified whenever spaces exist in the given string. + * When there are spaces at the end, the '\0' will be moved forward. + * @param str The string to perform the in place left trimming on. + */ +static void StrRightTrimInPlace(char *str) +{ + if (StrEmpty(str)) return; + + char *end = str; + while (*end != '\0') end++; + + char *last_non_space = end - 1; + while (last_non_space >= str && *last_non_space == ' ') last_non_space--; + + /* The last non space points to the last character of the string that is not + * a space. For a string with only spaces or an empty string this would be + * the position before the begin of the string. The previous search ensures + * that this location before the string is not read. + * In any case, the character after the last non space character will be + * either a space or the existing termination, so it can be set to '\0'. + */ + last_non_space[1] = '\0'; +} + +/** + * Trim the spaces from given string in place, i.e. the string buffer that + * is passed will be modified whenever spaces exist in the given string. + * When there are spaces at the begin, the whole string is moved forward + * and when there are spaces at the back the '\0' termination is moved. + * @param str The string to perform the in place trimming on. + */ +void StrTrimInPlace(char *str) +{ + StrLeftTrimInPlace(str); + StrRightTrimInPlace(str); +} + /** Scans the string for colour codes and strips them */ void str_strip_colours(char *str) { diff --git a/src/string_func.h b/src/string_func.h index 13e14f2d39..4fe9d7b825 100644 --- a/src/string_func.h +++ b/src/string_func.h @@ -30,25 +30,26 @@ #include "core/bitmath_func.hpp" #include "string_type.h" -char *strecat(char *dst, const char *src, const char *last); -char *strecpy(char *dst, const char *src, const char *last); -char *stredup(const char *src, const char *last = nullptr); +char *strecat(char *dst, const char *src, const char *last) NOACCESS(3); +char *strecpy(char *dst, const char *src, const char *last) NOACCESS(3); +char *stredup(const char *src, const char *last = nullptr) NOACCESS(2); -int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4); -int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0); +int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4) NOACCESS(2); +int CDECL vseprintf(char *str, const char *last, const char *format, va_list ap) WARN_FORMAT(3, 0) NOACCESS(2); char *CDECL str_fmt(const char *str, ...) WARN_FORMAT(1, 2); -void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); +void str_validate(char *str, const char *last, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK) NOACCESS(2); std::string str_validate(const std::string &str, StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK); void ValidateString(const char *str); -void str_fix_scc_encoded(char *str, const char *last); +void str_fix_scc_encoded(char *str, const char *last) NOACCESS(2); void str_strip_colours(char *str); bool strtolower(char *str); bool strtolower(std::string &str, std::string::size_type offs = 0); -bool StrValid(const char *str, const char *last); +bool StrValid(const char *str, const char *last) NOACCESS(2); +void StrTrimInPlace(char *str); /** * Check if a string buffer is empty. diff --git a/src/strings.cpp b/src/strings.cpp index e28943c57a..398784e4f8 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -534,7 +534,7 @@ static int DeterminePluralForm(int64 count, int plural_form) /* Only one form. * Used in: - * Hungarian, Japanese, Korean, Turkish */ + * Hungarian, Japanese, Turkish */ case 1: return 0; @@ -628,6 +628,12 @@ static int DeterminePluralForm(int64 count, int plural_form) * Scottish Gaelic */ case 13: return ((n == 1 || n == 11) ? 0 : (n == 2 || n == 12) ? 1 : ((n > 2 && n < 11) || (n > 12 && n < 20)) ? 2 : 3); + + /* Three forms: special cases for 1, 0 and numbers ending in 01 to 19. + * Used in: + * Romanian */ + case 14: + return n == 1 ? 0 : (n == 0 || (n % 100 > 0 && n % 100 < 20)) ? 1 : 2; } } @@ -1165,8 +1171,7 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg CargoTypes cmask = args->GetInt64(SCC_CARGO_LIST); bool first = true; - const CargoSpec *cs; - FOR_ALL_SORTED_CARGOSPECS(cs) { + for (const auto &cs : _sorted_cargo_specs) { if (!HasBit(cmask, cs->Index())) continue; if (buff >= last - 2) break; // ',' and ' ' @@ -1689,8 +1694,6 @@ static char *GetSpecialNameString(char *buff, int ind, StringParameters *args, c NOT_REACHED(); } -extern void SortNetworkLanguages(); - /** * Check whether the header is a valid header for OpenTTD. * @return true iff the header is deemed valid. @@ -1712,6 +1715,15 @@ bool LanguagePackHeader::IsValid() const StrValid(this->digit_decimal_separator, lastof(this->digit_decimal_separator)); } +/** + * Check whether a translation is sufficiently finished to offer it to the public. + */ +bool LanguagePackHeader::IsReasonablyFinished() const +{ + /* "Less than 25% missing" is "sufficiently finished". */ + return 4 * this->missing < LANGUAGE_TOTAL_STRINGS; +} + /** * Read a particular language. * @param lang The metadata about the language. @@ -1807,7 +1819,6 @@ bool ReadLanguagePack(const LanguageMetadata *lang) InitializeSortedCargoSpecs(); SortIndustryTypes(); BuildIndustriesLegend(); - SortNetworkLanguages(); BuildContentTypeStringList(); InvalidateWindowClassesData(WC_BUILD_VEHICLE); // Build vehicle window. InvalidateWindowClassesData(WC_TRAINS_LIST); // Train group window. @@ -1910,14 +1921,14 @@ static void GetLanguageList(const char *path) if (dir != nullptr) { struct dirent *dirent; while ((dirent = readdir(dir)) != nullptr) { - const char *d_name = FS2OTTD(dirent->d_name); - const char *extension = strrchr(d_name, '.'); + std::string d_name = FS2OTTD(dirent->d_name); + const char *extension = strrchr(d_name.c_str(), '.'); /* Not a language file */ if (extension == nullptr || strcmp(extension, ".lng") != 0) continue; LanguageMetadata lmd; - seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name); + seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name.c_str()); /* Check whether the file is of the correct version */ if (!GetLanguageFileHeader(lmd.file, &lmd)) { @@ -1966,6 +1977,10 @@ void InitializeLanguagePacks() } if (strcmp (lng.isocode, "en_GB") == 0) en_GB_fallback = &lng; + + /* Only auto-pick finished translations */ + if (!lng.IsReasonablyFinished()) continue; + if (strncmp(lng.isocode, lang, 5) == 0) chosen_language = &lng; if (strncmp(lng.isocode, lang, 2) == 0) language_fallback = &lng; } diff --git a/src/subsidy.cpp b/src/subsidy.cpp index ff420455d8..2668a62bd7 100644 --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -50,14 +50,14 @@ void Subsidy::AwardTo(CompanyID company) char *cn = stredup(company_name); /* Add a news item */ - Pair reftype = SetupSubsidyDecodeParam(this, false); + std::pair reftype = SetupSubsidyDecodeParam(this, false); InjectDParam(1); SetDParamStr(0, cn); AddNewsItem( STR_NEWS_SERVICE_SUBSIDY_AWARDED_HALF + _settings_game.difficulty.subsidy_multiplier, NT_SUBSIDIES, NF_NORMAL, - (NewsReferenceType)reftype.a, this->src, (NewsReferenceType)reftype.b, this->dst, + reftype.first, this->src, reftype.second, this->dst, cn ); AI::BroadcastNewEvent(new ScriptEventSubsidyAwarded(this->index)); @@ -72,7 +72,7 @@ void Subsidy::AwardTo(CompanyID company) * @param mode Unit of cargo used, \c true means general name, \c false means singular form. * @return Reference of the subsidy in the news system. */ -Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) +std::pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) { NewsReferenceType reftype1 = NR_NONE; NewsReferenceType reftype2 = NR_NONE; @@ -107,10 +107,7 @@ Pair SetupSubsidyDecodeParam(const Subsidy *s, bool mode) } SetDParam(5, s->dst); - Pair p; - p.a = reftype1; - p.b = reftype2; - return p; + return std::pair(reftype1, reftype2); } /** @@ -219,8 +216,8 @@ void CreateSubsidy(CargoID cid, SourceType src_type, SourceID src, SourceType ds s->remaining = SUBSIDY_OFFER_MONTHS; s->awarded = INVALID_COMPANY; - Pair reftype = SetupSubsidyDecodeParam(s, false); - AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); + std::pair reftype = SetupSubsidyDecodeParam(s, false); + AddNewsItem(STR_NEWS_SERVICE_SUBSIDY_OFFERED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst); SetPartOfSubsidyFlag(s->src_type, s->src, POS_SRC); SetPartOfSubsidyFlag(s->dst_type, s->dst, POS_DST); AI::BroadcastNewEvent(new ScriptEventSubsidyOffer(s->index)); @@ -494,14 +491,14 @@ void SubsidyMonthlyLoop() for (Subsidy *s : Subsidy::Iterate()) { if (--s->remaining == 0) { if (!s->IsAwarded()) { - Pair reftype = SetupSubsidyDecodeParam(s, true); - AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); + std::pair reftype = SetupSubsidyDecodeParam(s, true); + AddNewsItem(STR_NEWS_OFFER_OF_SUBSIDY_EXPIRED, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst); AI::BroadcastNewEvent(new ScriptEventSubsidyOfferExpired(s->index)); Game::NewEvent(new ScriptEventSubsidyOfferExpired(s->index)); } else { if (s->awarded == _local_company) { - Pair reftype = SetupSubsidyDecodeParam(s, true); - AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, (NewsReferenceType)reftype.a, s->src, (NewsReferenceType)reftype.b, s->dst); + std::pair reftype = SetupSubsidyDecodeParam(s, true); + AddNewsItem(STR_NEWS_SUBSIDY_WITHDRAWN_SERVICE, NT_SUBSIDIES, NF_NORMAL, reftype.first, s->src, reftype.second, s->dst); } AI::BroadcastNewEvent(new ScriptEventSubsidyExpired(s->index)); Game::NewEvent(new ScriptEventSubsidyExpired(s->index)); diff --git a/src/subsidy_func.h b/src/subsidy_func.h index 4889ead249..cc63577d33 100644 --- a/src/subsidy_func.h +++ b/src/subsidy_func.h @@ -14,8 +14,9 @@ #include "station_type.h" #include "company_type.h" #include "cargo_type.h" +#include "news_type.h" -Pair SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode); +std::pair SetupSubsidyDecodeParam(const struct Subsidy *s, bool mode); void DeleteSubsidyWith(SourceType type, SourceID index); bool CheckSubsidised(CargoID cargo_type, CompanyID company, SourceType src_type, SourceID src, const Station *st); void RebuildSubsidisedSourceAndDestinationCache(); diff --git a/src/table/currency_settings.ini b/src/table/currency_settings.ini index c242c83a87..3e51d0240a 100644 --- a/src/table/currency_settings.ini +++ b/src/table/currency_settings.ini @@ -10,7 +10,6 @@ static const SettingDesc _currency_settings[] = { }; [templates] SDT_VAR = SDT_VAR($base, $var, $type, $flags, $guiflags, $def, $min, $max, $interval, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), -SDT_CHR = SDT_CHR($base, $var, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_STR = SDT_STR($base, $var, $type, $flags, $guiflags, $def, $str, $strhelp, $strval, $proc, $from, $to, $cat, $extra, $startup), SDT_END = SDT_END() @@ -42,9 +41,10 @@ def = 1 min = 0 max = UINT16_MAX -[SDT_CHR] +[SDT_STR] base = CurrencySpec var = separator +type = SLE_STRBQ def = ""."" cat = SC_BASIC diff --git a/src/table/gameopt_settings.ini b/src/table/gameopt_settings.ini index bf3c639890..19ec02a841 100644 --- a/src/table/gameopt_settings.ini +++ b/src/table/gameopt_settings.ini @@ -20,7 +20,6 @@ static const char *_autosave_interval = "off|monthly|quarterly|half year|yearly" static const char *_save_to_network = "disabled|enabled|ask"; static const char *_roadsides = "left|right"; static const char *_savegame_date = "long|short|iso"; -static const char *_server_langs = "ANY|ENGLISH|GERMAN|FRENCH|BRAZILIAN|BULGARIAN|CHINESE|CZECH|DANISH|DUTCH|ESPERANTO|FINNISH|HUNGARIAN|ICELANDIC|ITALIAN|JAPANESE|KOREAN|LITHUANIAN|NORWEGIAN|POLISH|PORTUGUESE|ROMANIAN|RUSSIAN|SLOVAK|SLOVENIAN|SPANISH|SWEDISH|TURKISH|UKRAINIAN|AFRIKAANS|CROATIAN|CATALAN|ESTONIAN|GALICIAN|GREEK|LATVIAN"; static const char *_osk_activation = "disabled|double|single|immediately"; static const char *_settings_profiles = "easy|medium|hard"; static const char *_news_display = "off|summarized|full"; diff --git a/src/table/misc_settings.ini b/src/table/misc_settings.ini index 5e19020ff6..8cd77217bf 100644 --- a/src/table/misc_settings.ini +++ b/src/table/misc_settings.ini @@ -77,6 +77,12 @@ var = _video_hw_accel def = true cat = SC_BASIC +[SDTG_BOOL] +name = ""video_vsync"" +var = _video_vsync +def = false +cat = SC_BASIC + [SDTG_OMANY] name = ""support8bpp"" type = SLE_UINT8 diff --git a/src/table/settings.h.preamble b/src/table/settings.h.preamble index d7084d7247..c3e0678b7b 100644 --- a/src/table/settings.h.preamble +++ b/src/table/settings.h.preamble @@ -107,9 +107,6 @@ static size_t ConvertLandscape(const char *value); #define SDT_STR(base, var, type, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ SDT_GENERAL(#var, SDT_STRING, SL_STR, type, flags, guiflags, base, var, sizeof(((base*)8)->var), def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) -#define SDT_CHR(base, var, flags, guiflags, def, str, strhelp, strval, proc, from, to, cat, extra, startup)\ - SDT_GENERAL(#var, SDT_STRING, SL_VAR, SLE_CHAR, flags, guiflags, base, var, 1, def, 0, 0, 0, nullptr, str, strhelp, strval, proc, nullptr, from, to, cat, extra, startup) - #define SDT_OMANY(base, var, type, flags, guiflags, def, max, full, str, strhelp, strval, proc, from, to, load, cat, extra, startup)\ SDT_GENERAL(#var, SDT_ONEOFMANY, SL_VAR, type, flags, guiflags, base, var, 1, def, 0, max, 0, full, str, strhelp, strval, proc, load, from, to, cat, extra, startup) diff --git a/src/table/settings.ini b/src/table/settings.ini index ae9b08824f..d5fc49c935 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -3573,7 +3573,7 @@ cat = SC_BASIC var = music.music_vol type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = 127 +def = 50 min = 0 max = 127 interval = 1 @@ -3583,7 +3583,7 @@ cat = SC_BASIC var = music.effect_vol type = SLE_UINT8 flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = 127 +def = 100 min = 0 max = 127 interval = 1 @@ -4112,16 +4112,6 @@ def = 0 min = 0 max = MAX_CLIENTS -[SDTC_OMANY] -var = network.server_lang -type = SLE_UINT8 -flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -guiflags = SGF_NETWORK_ONLY -def = 0 -max = 35 -full = _server_langs -cat = SC_BASIC - [SDTC_BOOL] var = network.reload_cfg flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC @@ -4130,21 +4120,12 @@ def = false cat = SC_EXPERT [SDTC_STR] -var = network.last_host +var = network.last_joined type = SLE_STRB flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC def = """" cat = SC_EXPERT -[SDTC_VAR] -var = network.last_port -type = SLE_UINT16 -flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC -def = 0 -min = 0 -max = UINT16_MAX -cat = SC_EXPERT - [SDTC_BOOL] var = network.no_http_content_downloads flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC diff --git a/src/table/sprites.h b/src/table/sprites.h index 9071e61dc6..b7bb910203 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -54,7 +54,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682; /** Extra graphic spritenumbers */ static const SpriteID SPR_OPENTTD_BASE = 4896; -static const uint16 OPENTTD_SPRITE_COUNT = 186; +static const uint16 OPENTTD_SPRITE_COUNT = 191; /* Halftile-selection sprites */ static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE; @@ -166,6 +166,12 @@ static const SpriteID SPR_WINDOW_DEFSIZE = SPR_OPENTTD_BASE + 168; static const SpriteID SPR_RENAME = SPR_OPENTTD_BASE + 184; static const SpriteID SPR_GOTO_LOCATION = SPR_OPENTTD_BASE + 185; +static const SpriteID SPR_CHAT = SPR_OPENTTD_BASE + 186; +static const SpriteID SPR_ADMIN = SPR_OPENTTD_BASE + 187; +static const SpriteID SPR_JOIN = SPR_OPENTTD_BASE + 188; +static const SpriteID SPR_PLAYER_SELF = SPR_OPENTTD_BASE + 189; +static const SpriteID SPR_PLAYER_HOST = SPR_OPENTTD_BASE + 190; + static const SpriteID SPR_IMG_CARGOFLOW = SPR_OPENTTD_BASE + 174; static const SpriteID SPR_SIGNALS_BASE = SPR_OPENTTD_BASE + OPENTTD_SPRITE_COUNT; diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index 1c565089ad..ecdafb3ee7 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -176,6 +176,7 @@ static const PluralForm _plural_forms[] = { { 2, "Two forms: cases for numbers ending with a consonant, and with a vowel.", "\"yeong,il,sam,yuk,chil,pal\" \"i,sa,o,gu\"" }, { 4, "Four forms: special cases for 1, 0 and numbers ending in 02 to 10, and numbers ending in 11 to 19.", "\"1\" \"0,2..10,102..110,202..210,...\" \"11..19,111..119,211..219,...\" \"other\"" }, { 4, "Four forms: special cases for 1 and 11, 2 and 12, 3..10 and 13..19.", "\"1,11\" \"2,12\" \"3..10,13..19\" \"other\"" }, + { 3, "Three forms: special cases for 1, 0 and numbers ending in 01 to 19.", "\"1\" \"0,2..19,101..119,201..219,...\" \"other\"" }, }; /* Flags: diff --git a/src/texteff.cpp b/src/texteff.cpp index f08701939f..1c4722ae61 100644 --- a/src/texteff.cpp +++ b/src/texteff.cpp @@ -73,7 +73,17 @@ void UpdateTextEffect(TextEffectID te_id, StringID msg) te->params_1 = GetDParam(0); te->params_2 = GetDParam(1); - te->UpdatePosition(te->center, te->top, msg); + te->UpdatePosition(te->center, te->top, te->string_id, te->string_id - 1); +} + +void UpdateAllTextEffectVirtCoords() +{ + for (auto &te : _text_effects) { + if (te.string_id == INVALID_STRING_ID) continue; + SetDParam(0, te.params_1); + SetDParam(1, te.params_2); + te.UpdatePosition(te.center, te.top, te.string_id, te.string_id - 1); + } } void RemoveTextEffect(TextEffectID te_id) diff --git a/src/texteff.hpp b/src/texteff.hpp index 789b12d540..d122b17e9b 100644 --- a/src/texteff.hpp +++ b/src/texteff.hpp @@ -32,6 +32,7 @@ void InitTextEffects(); void DrawTextEffects(DrawPixelInfo *dpi); void UpdateTextEffect(TextEffectID effect_id, StringID msg); void RemoveTextEffect(TextEffectID effect_id); +void UpdateAllTextEffectVirtCoords(); /* misc_gui.cpp */ TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID colour); diff --git a/src/textfile_gui.cpp b/src/textfile_gui.cpp index 2770a00381..7d42d7dd2d 100644 --- a/src/textfile_gui.cpp +++ b/src/textfile_gui.cpp @@ -67,7 +67,6 @@ TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc) this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar - this->vscroll->SetStepSize(FONT_HEIGHT_MONO); } /* virtual */ TextfileWindow::~TextfileWindow() @@ -79,23 +78,38 @@ TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc) * Get the total height of the content displayed in this window, if wrapping is disabled. * @return the height in pixels */ -uint TextfileWindow::GetContentHeight() +uint TextfileWindow::ReflowContent() { - int max_width = this->GetWidget(WID_TF_BACKGROUND)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; - uint height = 0; - for (uint i = 0; i < this->lines.size(); i++) { - height += GetStringHeight(this->lines[i], max_width, FS_MONO); + if (!IsWidgetLowered(WID_TF_WRAPTEXT)) { + for (auto &line : this->lines) { + line.top = height; + height++; + line.bottom = height; + } + } else { + int max_width = this->GetWidget(WID_TF_BACKGROUND)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; + for (auto &line : this->lines) { + line.top = height; + height += GetStringHeight(line.text, max_width, FS_MONO) / FONT_HEIGHT_MONO; + line.bottom = height; + } } return height; } +uint TextfileWindow::GetContentHeight() +{ + if (this->lines.size() == 0) return 0; + return this->lines.back().bottom; +} + /* virtual */ void TextfileWindow::UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) { switch (widget) { case WID_TF_BACKGROUND: - resize->height = 1; + resize->height = FONT_HEIGHT_MONO; size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING; // At least 4 lines are visible. size->width = std::max(200u, size->width); // At least 200 pixels wide. @@ -104,18 +118,17 @@ uint TextfileWindow::GetContentHeight() } /** Set scrollbars to the right lengths. */ -void TextfileWindow::SetupScrollbars() +void TextfileWindow::SetupScrollbars(bool force_reflow) { if (IsWidgetLowered(WID_TF_WRAPTEXT)) { - this->vscroll->SetCount(this->GetContentHeight()); + /* Reflow is mandatory if text wrapping is on */ + uint height = this->ReflowContent(); + this->vscroll->SetCount(std::min(UINT16_MAX, height)); this->hscroll->SetCount(0); } else { - uint max_length = 0; - for (uint i = 0; i < this->lines.size(); i++) { - max_length = std::max(max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width); - } - this->vscroll->SetCount((uint)this->lines.size() * FONT_HEIGHT_MONO); - this->hscroll->SetCount(max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); + uint height = force_reflow ? this->ReflowContent() : this->GetContentHeight(); + this->vscroll->SetCount(std::min(UINT16_MAX, height)); + this->hscroll->SetCount(this->max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); } this->SetWidgetDisabledState(WID_TF_HSCROLLBAR, IsWidgetLowered(WID_TF_WRAPTEXT)); @@ -126,7 +139,6 @@ void TextfileWindow::SetupScrollbars() switch (widget) { case WID_TF_WRAPTEXT: this->ToggleWidgetLoweredState(WID_TF_WRAPTEXT); - this->SetupScrollbars(); this->InvalidateData(); break; } @@ -148,14 +160,18 @@ void TextfileWindow::SetupScrollbars() /* Draw content (now coordinates given to DrawString* are local to the new clipping region). */ int line_height = FONT_HEIGHT_MONO; - int y_offset = -this->vscroll->GetPosition(); + int pos = this->vscroll->GetPosition(); + int cap = this->vscroll->GetCapacity(); - for (uint i = 0; i < this->lines.size(); i++) { + for (auto &line : this->lines) { + if (line.bottom < pos) continue; + if (line.top > pos + cap) break; + + int y_offset = (line.top - pos) * line_height; if (IsWidgetLowered(WID_TF_WRAPTEXT)) { - y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); + DrawStringMultiLine(0, right - x, y_offset, bottom - y, line.text, TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); } else { - DrawString(-this->hscroll->GetPosition(), right - x, y_offset, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); - y_offset += line_height; // margin to previous element + DrawString(-this->hscroll->GetPosition(), right - x, y_offset, line.text, TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO); } } @@ -167,7 +183,14 @@ void TextfileWindow::SetupScrollbars() this->vscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND, TOP_SPACING + BOTTOM_SPACING); this->hscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND); - this->SetupScrollbars(); + this->SetupScrollbars(false); +} + +/* virtual */ void TextfileWindow::OnInvalidateData(int data, bool gui_scope) +{ + if (!gui_scope) return; + + this->SetupScrollbars(true); } /* virtual */ void TextfileWindow::Reset() @@ -184,7 +207,7 @@ void TextfileWindow::SetupScrollbars() { if (this->search_iterator >= this->lines.size()) return nullptr; - return this->lines[this->search_iterator++]; + return this->lines[this->search_iterator++].text; } /* virtual */ bool TextfileWindow::Monospace() @@ -364,14 +387,22 @@ static void Xunzip(byte **bufp, size_t *sizep) str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); /* Split the string on newlines. */ - this->lines.push_back(p); + int row = 0; + this->lines.emplace_back(row, p); for (; *p != '\0'; p++) { if (*p == '\n') { *p = '\0'; - this->lines.push_back(p + 1); + this->lines.emplace_back(++row, p + 1); } } + /* Calculate maximum text line length. */ + uint max_length = 0; + for (auto &line : this->lines) { + max_length = std::max(max_length, GetStringBoundingBox(line.text, FS_MONO).width); + } + this->max_length = max_length; + CheckForMissingGlyphs(true, this); } diff --git a/src/textfile_gui.h b/src/textfile_gui.h index d67435c015..5f1db14ca9 100644 --- a/src/textfile_gui.h +++ b/src/textfile_gui.h @@ -19,13 +19,23 @@ const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filenam /** Window for displaying a textfile */ struct TextfileWindow : public Window, MissingGlyphSearcher { + struct Line { + int top; ///< Top scroll position. + int bottom; ///< Bottom scroll position. + const char *text; ///< Pointer to text buffer. + + Line(int top, const char *text) : top(top), bottom(top + 1), text(text) {} + }; + TextfileType file_type; ///< Type of textfile to view. Scrollbar *vscroll; ///< Vertical scrollbar. Scrollbar *hscroll; ///< Horizontal scrollbar. char *text; ///< Lines of text from the NewGRF's textfile. - std::vector lines; ///< #text, split into lines in a table with lines. + std::vector lines; ///< #text, split into lines in a table with lines. uint search_iterator; ///< Iterator for the font check search. + uint max_length; ///< Maximum length of unwrapped text line. + static const int TOP_SPACING = WD_FRAMETEXT_TOP; ///< Additional spacing at the top of the #WID_TF_BACKGROUND widget. static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM; ///< Additional spacing at the bottom of the #WID_TF_BACKGROUND widget. @@ -36,6 +46,7 @@ struct TextfileWindow : public Window, MissingGlyphSearcher { void OnClick(Point pt, int widget, int click_count) override; void DrawWidget(const Rect &r, int widget) const override; void OnResize() override; + void OnInvalidateData(int data = 0, bool gui_scope = true) override; void Reset() override; FontSize DefaultSize() override; @@ -46,8 +57,9 @@ struct TextfileWindow : public Window, MissingGlyphSearcher { virtual void LoadTextfile(const char *textfile, Subdirectory dir); private: + uint ReflowContent(); uint GetContentHeight(); - void SetupScrollbars(); + void SetupScrollbars(bool force_reflow); }; #endif /* TEXTFILE_GUI_H */ diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index b8b7dab63e..07116496c3 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -217,10 +217,8 @@ static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count /** Enum for the Company Toolbar's network related buttons */ static const int CTMN_CLIENT_LIST = -1; ///< Show the client list -static const int CTMN_NEW_COMPANY = -2; ///< Create a new company -static const int CTMN_SPECTATE = -3; ///< Become spectator -static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator -static const int CTMN_SPEAK_ALL = -5; ///< Send message to public chat +static const int CTMN_SPECTATOR = -2; ///< Show a company window as spectator +static const int CTMN_SPEAK_ALL = -3; ///< Send message to public chat /** * Pop up a generic company list menu. @@ -239,12 +237,6 @@ static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0) /* Add the client list button for the companies menu */ list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false)); list.emplace_back(new DropDownListStringItem(STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, CTMN_SPEAK_ALL, false)); - - if (_local_company == COMPANY_SPECTATOR) { - list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached())); - } else { - list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached())); - } break; case WID_TN_STORY: @@ -631,23 +623,6 @@ static CallBackFunction MenuClickCompany(int index) ShowClientList(); return CBF_NONE; - case CTMN_NEW_COMPANY: - if (_network_server) { - DoCommandP(0, CCA_NEW, _network_own_client_id, CMD_COMPANY_CTRL); - } else { - NetworkSendCommand(0, CCA_NEW, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company); - } - return CBF_NONE; - - case CTMN_SPECTATE: - if (_network_server) { - NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR); - MarkWholeScreenDirty(); - } else { - NetworkClientRequestMove(COMPANY_SPECTATOR); - } - return CBF_NONE; - case CTMN_SPEAK_ALL: ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0); return CBF_NONE; @@ -2971,7 +2946,9 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) hor->Add(new NWidgetSpacer(0, 0)); break; } - hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); + NWidgetLeaf *leaf = new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i); + leaf->SetMinimalSize(20, 20); + hor->Add(leaf); } hor->Add(new NWidgetSpacer(0, 0)); diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp index 43f3523f8e..a0f5df23ed 100644 --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -2779,8 +2779,7 @@ CommandCost CmdRenameTown(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 */ const CargoSpec *FindFirstCargoWithTownEffect(TownEffect effect) { - const CargoSpec *cs; - FOR_ALL_CARGOSPECS(cs) { + for (const CargoSpec *cs : CargoSpec::Iterate()) { if (cs->town_effect == effect) return cs; } return nullptr; diff --git a/src/town_gui.cpp b/src/town_gui.cpp index a729bdfa30..8e4da93db7 100644 --- a/src/town_gui.cpp +++ b/src/town_gui.cpp @@ -652,12 +652,12 @@ static const NWidgetPart _nested_town_directory_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetSizingType(NWST_STEP), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA), - NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(35, 12), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), + NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP), EndContainer(), - NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetMinimalSize(196, 0), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), - SetFill(1, 0), SetResize(0, 10), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetDataTip(0x0, STR_TOWN_DIRECTORY_LIST_TOOLTIP), + SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_TD_SCROLLBAR), EndContainer(), NWidget(WWT_PANEL, COLOUR_BROWN), - NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 0, 2), SetMinimalSize(196, 12), SetFill(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL), + NWidget(WWT_TEXT, COLOUR_BROWN, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 2, 2), SetMinimalTextLines(1, 0), SetFill(1, 0), SetResize(1, 0), SetDataTip(STR_TOWN_POPULATION, STR_NULL), EndContainer(), EndContainer(), NWidget(NWID_VERTICAL), diff --git a/src/vehicle.cpp b/src/vehicle.cpp index a9af24c55a..90accdd80e 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -1639,13 +1639,19 @@ void Vehicle::UpdateBoundingBoxCoordinates(bool update_cache) const */ void Vehicle::UpdateViewport(bool dirty) { - Rect old_coord = this->sprite_cache.old_coord; + /* If the existing cache is invalid we should ignore it, as it will be set to the current coords by UpdateBoundingBoxCoordinates */ + bool ignore_cached_coords = this->sprite_cache.old_coord.left == INVALID_COORD; this->UpdateBoundingBoxCoordinates(true); - UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, old_coord.left, old_coord.top); + + if (ignore_cached_coords) { + UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, INVALID_COORD, INVALID_COORD); + } else { + UpdateVehicleViewportHash(this, this->coord.left, this->coord.top, this->sprite_cache.old_coord.left, this->sprite_cache.old_coord.top); + } if (dirty) { - if (old_coord.left == INVALID_COORD) { + if (ignore_cached_coords) { this->sprite_cache.is_viewport_candidate = this->MarkAllViewportsDirty(); } else { this->sprite_cache.is_viewport_candidate = ::MarkAllViewportsDirty( diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 0eaeaabf8c..3573354ec1 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -240,6 +240,11 @@ Dimension BaseVehicleListWindow::GetActionDropdownSize(bool show_autoreplace, bo return d; } +void BaseVehicleListWindow::OnInit() +{ + this->order_arrow_width = GetStringBoundingBox(STR_TINY_RIGHT_ARROW).width; +} + /** * Display the Action dropdown window. * @param show_autoreplace If true include the autoreplace item. @@ -508,8 +513,7 @@ struct RefitWindow : public Window { /* Loop through all cargoes in the refit mask */ int current_index = 0; - const CargoSpec *cs; - FOR_ALL_SORTED_CARGOSPECS(cs) { + for (const auto &cs : _sorted_cargo_specs) { CargoID cid = cs->Index(); /* Skip cargo type if it's not listed */ if (!HasBit(cmask, cid)) { @@ -1407,14 +1411,14 @@ static const NWidgetPart _nested_vehicle_list[] = { EndContainer(), }; -static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0) +static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, uint order_arrow_width, VehicleOrderID start) { const Order *order = v->GetOrder(start); if (order == nullptr) return; bool rtl = _current_text_dir == TD_RTL; - int l_offset = rtl ? 0 : ScaleGUITrad(6); - int r_offset = rtl ? ScaleGUITrad(6) : 0; + int l_offset = rtl ? 0 : order_arrow_width; + int r_offset = rtl ? order_arrow_width : 0; int i = 0; VehicleOrderID oid = start; @@ -1439,11 +1443,11 @@ static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, Veh } /** Draw small order list in the vehicle GUI, but without the little black arrow. This is used for shared order groups. */ -static void DrawSmallOrderList(const Order *order, int left, int right, int y) +static void DrawSmallOrderList(const Order *order, int left, int right, int y, uint order_arrow_width) { bool rtl = _current_text_dir == TD_RTL; - int l_offset = rtl ? 0 : ScaleGUITrad(6); - int r_offset = rtl ? ScaleGUITrad(6) : 0; + int l_offset = rtl ? 0 : order_arrow_width; + int r_offset = rtl ? order_arrow_width : 0; int i = 0; while (order != nullptr) { if (order->IsType(OT_GOTO_STATION)) { @@ -1551,7 +1555,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); } - if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_real_order_index); + if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, this->order_arrow_width, v->cur_real_order_index); StringID str; if (v->IsChainInDepot()) { @@ -1573,7 +1577,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int DrawVehicleImage(vehgroup.vehicles_begin[i], image_left + 8 * i, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, EIT_IN_LIST, 0); } - if (show_orderlist) DrawSmallOrderList((vehgroup.vehicles_begin[0])->GetFirstOrder(), orderlist_left, orderlist_right, y); + if (show_orderlist) DrawSmallOrderList((vehgroup.vehicles_begin[0])->GetFirstOrder(), orderlist_left, orderlist_right, y, this->order_arrow_width); SetDParam(0, vehgroup.NumVehicles()); DrawString(left, right, y + 2, STR_BLACK_COMMA); @@ -1831,12 +1835,18 @@ public: break; } - case GB_SHARED_ORDERS: + case GB_SHARED_ORDERS: { assert(vehgroup.NumVehicles() > 0); + const Vehicle *v = vehgroup.vehicles_begin[0]; /* We do not support VehicleClicked() here since the contextual action may only make sense for individual vehicles */ - ShowVehicleListWindow(vehgroup.vehicles_begin[0]); + if (vehgroup.NumVehicles() == 1) { + ShowVehicleViewWindow(v); + } else { + ShowVehicleListWindow(v); + } break; + } default: NOT_REACHED(); } diff --git a/src/vehicle_gui_base.h b/src/vehicle_gui_base.h index 4bbfbf2a80..d724bc3433 100644 --- a/src/vehicle_gui_base.h +++ b/src/vehicle_gui_base.h @@ -83,6 +83,7 @@ struct BaseVehicleListWindow : public Window { byte unitnumber_digits; ///< The number of digits of the highest unit number. Scrollbar *vscroll; VehicleListIdentifier vli; ///< Identifier of the vehicle list we want to currently show. + uint order_arrow_width; ///< Width of the arrow in the small order list. typedef GUIVehicleGroupList::SortFunction VehicleGroupSortFunction; typedef GUIVehicleList::SortFunction VehicleIndividualSortFunction; @@ -104,6 +105,8 @@ struct BaseVehicleListWindow : public Window { BaseVehicleListWindow(WindowDesc *desc, WindowNumber wno); + void OnInit() override; + void UpdateSortingFromGrouping(); void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const; diff --git a/src/video/cocoa/cocoa_ogl.mm b/src/video/cocoa/cocoa_ogl.mm index 8d02428e0c..96c3ea1bfe 100644 --- a/src/video/cocoa/cocoa_ogl.mm +++ b/src/video/cocoa/cocoa_ogl.mm @@ -134,7 +134,7 @@ static bool _allowSoftware; CGLSetCurrentContext(ctx); OpenGLBackend::Get()->Paint(); - if (_cursor.in_window) OpenGLBackend::Get()->DrawMouseCursor(); + OpenGLBackend::Get()->DrawMouseCursor(); [ super drawInCGLContext:ctx pixelFormat:pf forLayerTime:t displayTime:ts ]; } @@ -254,7 +254,7 @@ const char *VideoDriver_CocoaOpenGL::AllocateContext(bool allow_software) CGLSetCurrentContext(this->gl_context); - return OpenGLBackend::Create(&GetOGLProcAddressCallback); + return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize()); } NSView *VideoDriver_CocoaOpenGL::AllocateDrawView() diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm index 9fb74cd041..c16d196906 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -224,7 +224,7 @@ bool VideoDriver_Cocoa::AfterBlitterChange() */ void VideoDriver_Cocoa::EditBoxLostFocus() { - [ [ this->cocoaview inputContext ] discardMarkedText ]; + [ [ this->cocoaview inputContext ] performSelectorOnMainThread:@selector(discardMarkedText) withObject:nil waitUntilDone:[ NSThread isMainThread ] ]; /* Clear any marked string from the current edit box. */ HandleTextInput(nullptr, true); } diff --git a/src/video/opengl.cpp b/src/video/opengl.cpp index e74ab7b5bc..ecafeb6138 100644 --- a/src/video/opengl.cpp +++ b/src/video/opengl.cpp @@ -464,16 +464,17 @@ void SetupDebugOutput() /** * Create and initialize the singleton back-end class. * @param get_proc Callback to get an OpenGL function from the OS driver. + * @param screen_res Current display resolution. * @return nullptr on success, error message otherwise. */ -/* static */ const char *OpenGLBackend::Create(GetOGLProcAddressProc get_proc) +/* static */ const char *OpenGLBackend::Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res) { if (OpenGLBackend::instance != nullptr) OpenGLBackend::Destroy(); GetOGLProcAddress = get_proc; OpenGLBackend::instance = new OpenGLBackend(); - return OpenGLBackend::instance->Init(); + return OpenGLBackend::instance->Init(screen_res); } /** @@ -510,7 +511,7 @@ OpenGLBackend::~OpenGLBackend() _glDeleteBuffers(1, &this->anim_pbo); } if (_glDeleteTextures != nullptr) { - ClearCursorCache(); + this->InternalClearCursorCache(); OpenGLSprite::Destroy(); _glDeleteTextures(1, &this->vid_texture); @@ -521,9 +522,10 @@ OpenGLBackend::~OpenGLBackend() /** * Check for the needed OpenGL functionality and allocate all resources. + * @param screen_res Current display resolution. * @return Error string or nullptr if successful. */ -const char *OpenGLBackend::Init() +const char *OpenGLBackend::Init(const Dimension &screen_res) { if (!BindBasicInfoProcs()) return "OpenGL not supported"; @@ -546,6 +548,12 @@ const char *OpenGLBackend::Init() _gl_major_ver = atoi(ver); _gl_minor_ver = minor != nullptr ? atoi(minor + 1) : 0; +#ifdef _WIN32 + /* Old drivers on Windows (especially if made by Intel) seem to be + * unstable, so cull the oldest stuff here. */ + if (!IsOpenGLVersionAtLeast(3, 2)) return "Need at least OpenGL version 3.2 on Windows"; +#endif + if (!BindBasicOpenGLProcs()) return "Failed to bind basic OpenGL functions."; SetupDebugOutput(); @@ -581,6 +589,11 @@ const char *OpenGLBackend::Init() } if (this->persistent_mapping_supported) DEBUG(driver, 3, "OpenGL: Using persistent buffer mapping"); + /* Check maximum texture size against screen resolution. */ + GLint max_tex_size = 0; + _glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_tex_size); + if (std::max(screen_res.width, screen_res.height) > (uint)max_tex_size) return "Max supported texture size is too small"; + /* Check available texture units. */ GLint max_tex_units = 0; _glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_tex_units); @@ -1053,18 +1066,20 @@ void OpenGLBackend::Paint() */ void OpenGLBackend::DrawMouseCursor() { + if (!this->cursor_in_window) return; + /* Draw cursor on screen */ _cur_dpi = &_screen; - for (uint i = 0; i < _cursor.sprite_count; ++i) { - SpriteID sprite = _cursor.sprite_seq[i].sprite; + for (uint i = 0; i < this->cursor_sprite_count; ++i) { + SpriteID sprite = this->cursor_sprite_seq[i].sprite; /* Sprites are cached by PopulateCursorCache(). */ if (this->cursor_cache.Contains(sprite)) { - const Sprite *spr = GetSprite(sprite, ST_NORMAL); + Sprite *spr = this->cursor_cache.Get(sprite); - this->RenderOglSprite((OpenGLSprite *)this->cursor_cache.Get(sprite)->data, _cursor.sprite_seq[i].pal, - _cursor.pos.x + _cursor.sprite_pos[i].x + UnScaleByZoom(spr->x_offs, ZOOM_LVL_GUI), - _cursor.pos.y + _cursor.sprite_pos[i].y + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI), + this->RenderOglSprite((OpenGLSprite *)spr->data, this->cursor_sprite_seq[i].pal, + this->cursor_pos.x + this->cursor_sprite_pos[i].x + UnScaleByZoom(spr->x_offs, ZOOM_LVL_GUI), + this->cursor_pos.y + this->cursor_sprite_pos[i].y + UnScaleByZoom(spr->y_offs, ZOOM_LVL_GUI), ZOOM_LVL_GUI); } } @@ -1072,20 +1087,24 @@ void OpenGLBackend::DrawMouseCursor() void OpenGLBackend::PopulateCursorCache() { + static_assert(lengthof(_cursor.sprite_seq) == lengthof(this->cursor_sprite_seq)); + static_assert(lengthof(_cursor.sprite_pos) == lengthof(this->cursor_sprite_pos)); + if (this->clear_cursor_cache) { /* We have a pending cursor cache clear to do first. */ this->clear_cursor_cache = false; this->last_sprite_pal = (PaletteID)-1; - Sprite *sp; - while ((sp = this->cursor_cache.Pop()) != nullptr) { - OpenGLSprite *sprite = (OpenGLSprite *)sp->data; - sprite->~OpenGLSprite(); - free(sp); - } + this->InternalClearCursorCache(); } + this->cursor_pos = _cursor.pos; + this->cursor_sprite_count = _cursor.sprite_count; + this->cursor_in_window = _cursor.in_window; + for (uint i = 0; i < _cursor.sprite_count; ++i) { + this->cursor_sprite_seq[i] = _cursor.sprite_seq[i]; + this->cursor_sprite_pos[i] = _cursor.sprite_pos[i]; SpriteID sprite = _cursor.sprite_seq[i].sprite; if (!this->cursor_cache.Contains(sprite)) { @@ -1102,6 +1121,19 @@ void OpenGLBackend::PopulateCursorCache() /** * Clear all cached cursor sprites. */ +void OpenGLBackend::InternalClearCursorCache() +{ + Sprite *sp; + while ((sp = this->cursor_cache.Pop()) != nullptr) { + OpenGLSprite *sprite = (OpenGLSprite *)sp->data; + sprite->~OpenGLSprite(); + free(sp); + } +} + +/** + * Queue a request for cursor cache clear. + */ void OpenGLBackend::ClearCursorCache() { /* If the game loop is threaded, this function might be called @@ -1122,6 +1154,7 @@ void *OpenGLBackend::GetVideoBuffer() #endif if (!this->persistent_mapping_supported) { + assert(this->vid_buffer == nullptr); _glBindBuffer(GL_PIXEL_UNPACK_BUFFER, this->vid_pbo); this->vid_buffer = _glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_READ_WRITE); } else if (this->vid_buffer == nullptr) { diff --git a/src/video/opengl.h b/src/video/opengl.h index c17a8536d9..e5cd749f2e 100644 --- a/src/video/opengl.h +++ b/src/video/opengl.h @@ -65,12 +65,20 @@ private: PaletteID last_sprite_pal = (PaletteID)-1; ///< Last uploaded remap palette. bool clear_cursor_cache = false; ///< A clear of the cursor cache is pending. + Point cursor_pos; ///< Cursor position + bool cursor_in_window; ///< Cursor inside this window + PalSpriteID cursor_sprite_seq[16]; ///< Current image of cursor + Point cursor_sprite_pos[16]; ///< Relative position of individual cursor sprites + uint cursor_sprite_count; ///< Number of cursor sprites to draw + OpenGLBackend(); ~OpenGLBackend(); - const char *Init(); + const char *Init(const Dimension &screen_res); bool InitShaders(); + void InternalClearCursorCache(); + void RenderOglSprite(OpenGLSprite *gl_sprite, PaletteID pal, int x, int y, ZoomLevel zoom); public: @@ -79,7 +87,7 @@ public: { return OpenGLBackend::instance; } - static const char *Create(GetOGLProcAddressProc get_proc); + static const char *Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res); static void Destroy(); void PrepareContext(); diff --git a/src/video/sdl2_opengl_v.cpp b/src/video/sdl2_opengl_v.cpp index 86dc104dd2..003e194380 100644 --- a/src/video/sdl2_opengl_v.cpp +++ b/src/video/sdl2_opengl_v.cpp @@ -69,8 +69,13 @@ const char *VideoDriver_SDL_OpenGL::Start(const StringList ¶m) int w, h; SDL_GetWindowSize(this->sdl_window, &w, &h); this->ClientSizeChanged(w, h, true); - - SDL_GL_SetSwapInterval(GetDriverParamBool(param, "vsync") ? 1 : 0); + /* We should have a valid screen buffer now. If not, something went wrong and we should abort. */ + if (_screen.dst_ptr == nullptr) { + this->Stop(); + return "Can't get pointer to screen buffer"; + } + /* Main loop expects to start with the buffer unmapped. */ + this->ReleaseVideoPointer(); return nullptr; } @@ -91,6 +96,11 @@ void VideoDriver_SDL_OpenGL::DestroyContext() } } +void VideoDriver_SDL_OpenGL::ToggleVsync(bool vsync) +{ + SDL_GL_SetSwapInterval(vsync); +} + const char *VideoDriver_SDL_OpenGL::AllocateContext() { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); @@ -107,7 +117,9 @@ const char *VideoDriver_SDL_OpenGL::AllocateContext() this->gl_context = SDL_GL_CreateContext(this->sdl_window); if (this->gl_context == nullptr) return "SDL2: Can't active GL context"; - return OpenGLBackend::Create(&GetOGLProcAddressCallback); + ToggleVsync(_video_vsync); + + return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize()); } void VideoDriver_SDL_OpenGL::PopulateSystemSprites() @@ -174,7 +186,7 @@ void VideoDriver_SDL_OpenGL::Paint() } OpenGLBackend::Get()->Paint(); - if (_cursor.in_window) OpenGLBackend::Get()->DrawMouseCursor(); + OpenGLBackend::Get()->DrawMouseCursor(); SDL_GL_SwapWindow(this->sdl_window); } diff --git a/src/video/sdl2_opengl_v.h b/src/video/sdl2_opengl_v.h index f749b1f459..c7e647ca88 100644 --- a/src/video/sdl2_opengl_v.h +++ b/src/video/sdl2_opengl_v.h @@ -29,6 +29,8 @@ public: bool HasAnimBuffer() override { return true; } uint8 *GetAnimBuffer() override { return this->anim_buffer; } + void ToggleVsync(bool vsync) override; + const char *GetName() const override { return "sdl-opengl"; } protected: diff --git a/src/video/sdl2_v.h b/src/video/sdl2_v.h index bd43f71f89..d706cc6654 100644 --- a/src/video/sdl2_v.h +++ b/src/video/sdl2_v.h @@ -17,7 +17,7 @@ /** The SDL video driver. */ class VideoDriver_SDL_Base : public VideoDriver { public: - VideoDriver_SDL_Base() : sdl_window(nullptr) {} + VideoDriver_SDL_Base() : sdl_window(nullptr), buffer_locked(false) {} const char *Start(const StringList ¶m) override; diff --git a/src/video/video_driver.cpp b/src/video/video_driver.cpp index bee67e1ea0..0af716f05e 100644 --- a/src/video/video_driver.cpp +++ b/src/video/video_driver.cpp @@ -21,6 +21,7 @@ #include "video_driver.hpp" bool _video_hw_accel; ///< Whether to consider hardware accelerated video drivers. +bool _video_vsync; ///< Whether we should use vsync (only if _video_hw_accel is enabled). void VideoDriver::GameLoop() { @@ -96,27 +97,6 @@ void VideoDriver::StopGameThread() this->game_thread.join(); } -void VideoDriver::RealChangeBlitter(const char *repl_blitter) -{ - const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName(); - - DEBUG(driver, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter); - Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter); - if (new_blitter == nullptr) NOT_REACHED(); - DEBUG(driver, 1, "Successfully switched to %s.", repl_blitter); - - if (!this->AfterBlitterChange()) { - /* Failed to switch blitter, let's hope we can return to the old one. */ - if (BlitterFactory::SelectBlitter(cur_blitter) == nullptr || !this->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); - } - - /* Clear caches that might have sprites for another blitter. */ - this->ClearSystemSprites(); - ClearFontCache(); - GfxClearSpriteCache(); - ReInitAllWindows(); -} - void VideoDriver::Tick() { if (!this->is_game_threaded && std::chrono::steady_clock::now() >= this->next_game_tick) { @@ -151,17 +131,15 @@ void VideoDriver::Tick() this->fast_forward_via_key = false; } + /* Locking video buffer can block (especially with vsync enabled), do it before taking game state lock. */ + this->LockVideoBuffer(); + { /* Tell the game-thread to stop so we can have a go. */ std::lock_guard lock_wait(this->game_thread_wait_mutex); std::lock_guard lock_state(this->game_state_mutex); - this->LockVideoBuffer(); - - if (this->change_blitter != nullptr) { - this->RealChangeBlitter(this->change_blitter); - this->change_blitter = nullptr; - } + this->DrainCommandQueue(); while (this->PollEvent()) {} ::InputLoop(); diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp index 7a859565a6..db522a761d 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -22,12 +22,14 @@ #include #include #include +#include extern std::string _ini_videodriver; extern std::vector _resolutions; extern Dimension _cur_resolution; extern bool _rightclick_emulate; extern bool _video_hw_accel; +extern bool _video_vsync; /** The base of all video drivers. */ class VideoDriver : public Driver { @@ -35,7 +37,7 @@ class VideoDriver : public Driver { const uint DEFAULT_WINDOW_HEIGHT = 480u; ///< Default window height. public: - VideoDriver() : is_game_threaded(true), change_blitter(nullptr) {} + VideoDriver() : fast_forward_key_pressed(false), fast_forward_via_key(false), is_game_threaded(true) {} /** * Mark a particular area dirty. @@ -66,6 +68,12 @@ public: */ virtual bool ToggleFullscreen(bool fullscreen) = 0; + /** + * Change the vsync setting. + * @param vsync The new setting. + */ + virtual void ToggleVsync(bool vsync) {} + /** * Callback invoked after the blitter was changed. * @return True if no error. @@ -171,12 +179,16 @@ public: } /** - * Queue a request to change the blitter. This is not executed immediately, - * but instead on the next draw-tick. + * Queue a function to be called on the main thread with game state + * lock held and video buffer locked. Queued functions will be + * executed on the next draw tick. + * @param func Function to call. */ - void ChangeBlitter(const char *new_blitter) + void QueueOnMainThread(std::function &&func) { - this->change_blitter = new_blitter; + std::lock_guard lock(this->cmd_queue_mutex); + + this->cmd_queue.emplace_back(std::forward>(func)); } void GameLoopPause(); @@ -321,11 +333,29 @@ protected: static void GameThreadThunk(VideoDriver *drv); private: + std::mutex cmd_queue_mutex; + std::vector> cmd_queue; + + /** Execute all queued commands. */ + void DrainCommandQueue() + { + std::vector> cmds{}; + + { + /* Exchange queue with an empty one to limit the time we + * hold the mutex. This also ensures that queued functions can + * add new functions to the queue without everything blocking. */ + std::lock_guard lock(this->cmd_queue_mutex); + cmds.swap(this->cmd_queue); + } + + for (auto &f : cmds) { + f(); + } + } + void GameLoop(); void GameThread(); - void RealChangeBlitter(const char *repl_blitter); - - const char *change_blitter; ///< Request to change the blitter. nullptr if no pending request. }; #endif /* VIDEO_VIDEO_DRIVER_HPP */ diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 1d9cd3e2bf..f0291db714 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -214,7 +214,7 @@ bool VideoDriver_Win32Base::MakeWindow(bool full_screen, bool resize) char window_title[64]; seprintf(window_title, lastof(window_title), "OpenTTD %s", _openttd_revision); - this->main_wnd = CreateWindow(L"OTTD", OTTD2FS(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), this); + this->main_wnd = CreateWindow(L"OTTD", OTTD2FS(window_title).c_str(), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), this); if (this->main_wnd == nullptr) usererror("CreateWindow failed"); ShowWindow(this->main_wnd, showstyle); } @@ -331,7 +331,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) /* Transmit text to windowing system. */ if (len > 0) { HandleTextInput(nullptr, true); // Clear marked string. - HandleTextInput(FS2OTTD(str)); + HandleTextInput(FS2OTTD(str).c_str()); } SetCompositionPos(hwnd); @@ -552,14 +552,6 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) uint scancode = GB(lParam, 16, 8); keycode = scancode == 41 ? (uint)WKC_BACKQUOTE : MapWindowsKey(wParam); - /* Silently drop all messages handled by WM_CHAR. */ - MSG msg; - if (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) { - if ((msg.message == WM_CHAR || msg.message == WM_DEADCHAR) && GB(lParam, 16, 8) == GB(msg.lParam, 16, 8)) { - return 0; - } - } - uint charcode = MapVirtualKey(wParam, MAPVK_VK_TO_CHAR); /* No character translation? */ @@ -568,21 +560,26 @@ LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) return 0; } - /* Is the console key a dead key? If yes, ignore the first key down event. */ - if (HasBit(charcode, 31) && !console) { - if (scancode == 41) { - console = true; - return 0; + /* If an edit box is in focus, wait for the corresponding WM_CHAR message. */ + if (!EditBoxInGlobalFocus()) { + /* Is the console key a dead key? If yes, ignore the first key down event. */ + if (HasBit(charcode, 31) && !console) { + if (scancode == 41) { + console = true; + return 0; + } } + console = false; + + /* IMEs and other input methods sometimes send a WM_CHAR without a WM_KEYDOWN, + * clear the keycode so a previous WM_KEYDOWN doesn't become 'stuck'. */ + uint cur_keycode = keycode; + keycode = 0; + + return HandleCharMsg(cur_keycode, LOWORD(charcode)); } - console = false; - /* IMEs and other input methods sometimes send a WM_CHAR without a WM_KEYDOWN, - * clear the keycode so a previous WM_KEYDOWN doesn't become 'stuck'. */ - uint cur_keycode = keycode; - keycode = 0; - - return HandleCharMsg(cur_keycode, LOWORD(charcode)); + return 0; } case WM_SYSKEYDOWN: // user presses F10 or Alt, both activating the title-menu @@ -1293,7 +1290,6 @@ const char *VideoDriver_Win32OpenGL::Start(const StringList ¶m) if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return "Only real blitters supported"; Dimension old_res = _cur_resolution; // Save current screen resolution in case of errors, as MakeWindow invalidates it. - this->vsync = GetDriverParamBool(param, "vsync"); LoadWGLExtensions(); @@ -1309,6 +1305,14 @@ const char *VideoDriver_Win32OpenGL::Start(const StringList ¶m) } this->ClientSizeChanged(this->width, this->height, true); + /* We should have a valid screen buffer now. If not, something went wrong and we should abort. */ + if (_screen.dst_ptr == nullptr) { + this->Stop(); + _cur_resolution = old_res; + return "Can't get pointer to screen buffer"; + } + /* Main loop expects to start with the buffer unmapped. */ + this->ReleaseVideoPointer(); MarkWholeScreenDirty(); @@ -1338,6 +1342,15 @@ void VideoDriver_Win32OpenGL::DestroyContext() } } +void VideoDriver_Win32OpenGL::ToggleVsync(bool vsync) +{ + if (_wglSwapIntervalEXT != nullptr) { + _wglSwapIntervalEXT(vsync); + } else if (vsync) { + DEBUG(driver, 0, "OpenGL: Vsync requested, but not supported by driver"); + } +} + const char *VideoDriver_Win32OpenGL::AllocateContext() { this->dc = GetDC(this->main_wnd); @@ -1349,14 +1362,22 @@ const char *VideoDriver_Win32OpenGL::AllocateContext() /* Create OpenGL device context. Try to get an 3.2+ context if possible. */ if (_wglCreateContextAttribsARB != nullptr) { + /* Try for OpenGL 4.5 first. */ int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, - WGL_CONTEXT_MINOR_VERSION_ARB, 2, + WGL_CONTEXT_MAJOR_VERSION_ARB, 4, + WGL_CONTEXT_MINOR_VERSION_ARB, 5, WGL_CONTEXT_FLAGS_ARB, _debug_driver_level >= 8 ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, _hasWGLARBCreateContextProfile ? WGL_CONTEXT_PROFILE_MASK_ARB : 0, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, // Terminate list if WGL_ARB_create_context_profile isn't supported. 0 }; rc = _wglCreateContextAttribsARB(this->dc, nullptr, attribs); + + if (rc == nullptr) { + /* Try again for a 3.2 context. */ + attribs[1] = 3; + attribs[3] = 2; + rc = _wglCreateContextAttribsARB(this->dc, nullptr, attribs); + } } if (rc == nullptr) { @@ -1366,15 +1387,10 @@ const char *VideoDriver_Win32OpenGL::AllocateContext() } if (!wglMakeCurrent(this->dc, rc)) return "Can't active GL context"; - /* Enable/disable Vsync if supported. */ - if (_wglSwapIntervalEXT != nullptr) { - _wglSwapIntervalEXT(this->vsync ? 1 : 0); - } else if (vsync) { - DEBUG(driver, 0, "OpenGL: Vsync requested, but not supported by driver"); - } + this->ToggleVsync(_video_vsync); this->gl_rc = rc; - return OpenGLBackend::Create(&GetOGLProcAddressCallback); + return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize()); } bool VideoDriver_Win32OpenGL::ToggleFullscreen(bool full_screen) @@ -1457,7 +1473,7 @@ void VideoDriver_Win32OpenGL::Paint() } OpenGLBackend::Get()->Paint(); - if (_cursor.in_window) OpenGLBackend::Get()->DrawMouseCursor(); + OpenGLBackend::Get()->DrawMouseCursor(); SwapBuffers(this->dc); } diff --git a/src/video/win32_v.h b/src/video/win32_v.h index f6ca291f10..4686df7160 100644 --- a/src/video/win32_v.h +++ b/src/video/win32_v.h @@ -17,7 +17,7 @@ /** Base class for Windows video drivers. */ class VideoDriver_Win32Base : public VideoDriver { public: - VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false) {} + VideoDriver_Win32Base() : main_wnd(nullptr), fullscreen(false), buffer_locked(false) {} void Stop() override; @@ -138,12 +138,13 @@ public: bool HasAnimBuffer() override { return true; } uint8 *GetAnimBuffer() override { return this->anim_buffer; } + void ToggleVsync(bool vsync) override; + const char *GetName() const override { return "win32-opengl"; } protected: HDC dc; ///< Window device context. HGLRC gl_rc; ///< OpenGL context. - bool vsync; ///< Enable VSync? uint8 *anim_buffer; ///< Animation buffer from OpenGL back-end. uint8 GetFullscreenBpp() override { return 32; } // OpenGL is always 32 bpp. diff --git a/src/viewport.cpp b/src/viewport.cpp index e0b2c506eb..b5f1b7d2ad 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -269,7 +269,7 @@ static Point _vp_move_offs; static void DoSetViewportPosition(const Window *w, int left, int top, int width, int height) { - FOR_ALL_WINDOWS_FROM_BACK_FROM(w, w) { + for (const Window *w : Window::IterateFromBack(w)) { if (left + width > w->left && w->left + w->width > left && top + height > w->top && @@ -1476,8 +1476,7 @@ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const zoomlevels[zoom].bottom = this->top + ScaleByZoom(VPSM_TOP + FONT_HEIGHT_NORMAL + VPSM_BOTTOM + 1, zoom); } - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { Viewport *vp = w->viewport; if (vp != nullptr && vp->zoom <= maxzoom) { assert(vp->width != 0); @@ -1950,8 +1949,7 @@ bool MarkAllViewportsDirty(int left, int top, int right, int bottom) { bool dirty = false; - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { Viewport *vp = w->viewport; if (vp != nullptr) { assert(vp->width != 0); @@ -1964,8 +1962,7 @@ bool MarkAllViewportsDirty(int left, int top, int right, int bottom) void ConstrainAllViewportsZoom() { - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if (w->viewport == nullptr) continue; ZoomLevel zoom = static_cast(Clamp(w->viewport->zoom, _settings_client.gui.zoom_min, _settings_client.gui.zoom_max)); @@ -2660,7 +2657,7 @@ void UpdateTileSelection() * @param params (optional) up to 5 pieces of additional information that may be added to a tooltip * @param close_cond Condition for closing this tooltip. */ -static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_NONE) +static inline void ShowMeasurementTooltips(StringID str, uint paramcount, const uint64 params[], TooltipCloseCondition close_cond = TCC_EXIT_VIEWPORT) { if (!_settings_client.gui.measure_tooltip) return; GuiShowTooltips(_thd.GetCallbackWnd(), str, paramcount, params, close_cond); diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index 6a3b730657..731954c2eb 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -437,7 +437,9 @@ bool RiverModifyDesertZone(TileIndex tile, void *) * @param tile end tile of stretch-dragging * @param flags type of operation * @param p1 start tile of stretch-dragging - * @param p2 waterclass to build. sea and river can only be built in scenario editor + * @param p2 various bitstuffed data + * bits 0-1: waterclass to build. sea and river can only be built in scenario editor + * bit 2: Whether to use the Orthogonal (0) or Diagonal (1) iterator. * @param text unused * @return the cost of this operation or an error */ @@ -449,13 +451,23 @@ CommandCost CmdBuildCanal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 /* Outside of the editor you can only build canals, not oceans */ if (wc != WATER_CLASS_CANAL && _game_mode != GM_EDITOR) return CMD_ERROR; - TileArea ta(tile, p1); - /* Outside the editor you can only drag canals, and not areas */ - if (_game_mode != GM_EDITOR && ta.w != 1 && ta.h != 1) return CMD_ERROR; + if (_game_mode != GM_EDITOR) { + TileArea ta(tile, p1); + if (ta.w != 1 && ta.h != 1) return CMD_ERROR; + } CommandCost cost(EXPENSES_CONSTRUCTION); - TILE_AREA_LOOP(tile, ta) { + + std::unique_ptr iter; + if (HasBit(p2, 2)) { + iter = std::make_unique(tile, p1); + } else { + iter = std::make_unique(tile, p1); + } + + for (; *iter != INVALID_TILE; ++(*iter)) { + TileIndex tile = *iter; CommandCost ret; Slope slope = GetTileSlope(tile); diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp index 01cdbc16e0..e8e9e69455 100644 --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -153,7 +153,7 @@ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID * return CommandCost(); } -extern void GetStationLayout(byte *layout, int numtracks, int plat_len, const StationSpec *statspec); +extern void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const StationSpec *statspec); extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp); extern CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis); diff --git a/src/widget.cpp b/src/widget.cpp index 45a7232577..91a1010b2e 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -27,6 +27,33 @@ #include "safeguards.h" +/** + * Calculate x and y coordinates for an aligned object within a window. + * @param r Rectangle of the widget to be drawn in. + * @param d Dimension of the object to be drawn. + * @param align Alignment of the object. + * @return A point containing the position at which to draw. + */ +static inline Point GetAlignedPosition(const Rect &r, const Dimension &d, StringAlignment align) +{ + Point p; + /* In case we have a RTL language we swap the alignment. */ + if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT; + switch (align & SA_HOR_MASK) { + case SA_LEFT: p.x = r.left; break; + case SA_HOR_CENTER: p.x = CenterBounds(r.left, r.right, d.width); break; + case SA_RIGHT: p.x = r.right - d.width; break; + default: NOT_REACHED(); + } + switch (align & SA_VERT_MASK) { + case SA_TOP: p.y = r.top; break; + case SA_VERT_CENTER: p.y = CenterBounds(r.top, r.bottom, d.height); break; + case SA_BOTTOM: p.y = r.bottom - d.height; break; + default: NOT_REACHED(); + } + return p; +} + /** * Compute the vertical position of the draggable part of scrollbar * @param sb Scrollbar list data @@ -234,15 +261,17 @@ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, Fra * @param colour Colour of the button. * @param clicked Button is lowered. * @param img Sprite to draw. + * @param align Alignment of the sprite. */ -static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img) +static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colour, bool clicked, SpriteID img, StringAlignment align) { assert(img != 0); DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, (clicked) ? FR_LOWERED : FR_NONE); if ((type & WWT_MASK) == WWT_IMGBTN_2 && clicked) img++; // Show different image when clicked for #WWT_IMGBTN_2. Dimension d = GetSpriteSize(img); - DrawSprite(img, PAL_NONE, CenterBounds(r.left, r.right, d.width) + clicked, CenterBounds(r.top, r.bottom, d.height) + clicked); + Point p = GetAlignedPosition(r, d, align); + DrawSprite(img, PAL_NONE, p.x + clicked, p.y + clicked); } /** @@ -250,15 +279,17 @@ static inline void DrawImageButtons(const Rect &r, WidgetType type, Colours colo * @param r Rectangle of the label background. * @param type Widget type (#WWT_TEXTBTN, #WWT_TEXTBTN_2, or #WWT_LABEL). * @param clicked Label is rendered lowered. + * @param colour Colour of the text. * @param str Text to draw. + * @param align Alignment of the text. */ -static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, StringID str) +static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, TextColour colour, StringID str, StringAlignment align) { if (str == STR_NULL) return; if ((type & WWT_MASK) == WWT_TEXTBTN_2 && clicked) str++; Dimension d = GetStringBoundingBox(str); - int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - DrawString(r.left + clicked, r.right + clicked, r.top + offset + clicked, str, TC_FROMSTRING, SA_HOR_CENTER); + Point p = GetAlignedPosition(r, d, align); + DrawString(r.left + clicked, r.right + clicked, p.y + clicked, str, colour, align); } /** @@ -266,24 +297,27 @@ static inline void DrawLabel(const Rect &r, WidgetType type, bool clicked, Strin * @param r Rectangle of the background. * @param colour Colour of the text. * @param str Text to draw. + * @param align Alignment of the text. */ -static inline void DrawText(const Rect &r, TextColour colour, StringID str) +static inline void DrawText(const Rect &r, TextColour colour, StringID str, StringAlignment align) { Dimension d = GetStringBoundingBox(str); - int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - if (str != STR_NULL) DrawString(r.left, r.right, r.top + offset, str, colour); + Point p = GetAlignedPosition(r, d, align); + if (str != STR_NULL) DrawString(r.left, r.right, p.y, str, colour, align); } /** * Draw an inset widget. - * @param r Rectangle of the background. - * @param colour Colour of the inset. - * @param str Text to draw. + * @param r Rectangle of the background. + * @param colour Colour of the inset. + * @param text_colour Colour of the text. + * @param str Text to draw. + * @param align Alignment of the text. */ -static inline void DrawInset(const Rect &r, Colours colour, StringID str) +static inline void DrawInset(const Rect &r, Colours colour, TextColour text_colour, StringID str, StringAlignment align) { DrawFrameRect(r.left, r.top, r.right, r.bottom, colour, FR_LOWERED | FR_DARKENED); - if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str); + if (str != STR_NULL) DrawString(r.left + WD_INSET_LEFT, r.right - WD_INSET_RIGHT, r.top + WD_INSET_TOP, str, text_colour, align); } /** @@ -425,15 +459,17 @@ static inline void DrawHorizontalScrollbar(const Rect &r, Colours colour, bool l /** * Draw a frame widget. - * @param r Rectangle of the frame. - * @param colour Colour of the frame. - * @param str Text of the frame. + * @param r Rectangle of the frame. + * @param colour Colour of the frame. + * @param text_colour Colour of the text. + * @param str Text of the frame. + * @param align Alignment of the text in the frame. */ -static inline void DrawFrame(const Rect &r, Colours colour, StringID str) +static inline void DrawFrame(const Rect &r, Colours colour, TextColour text_colour, StringID str, StringAlignment align) { int x2 = r.left; // by default the left side is the left side of the widget - if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str); + if (str != STR_NULL) x2 = DrawString(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top, str, text_colour, align); int c1 = _colour_gradient[colour][3]; int c2 = _colour_gradient[colour][7]; @@ -481,7 +517,7 @@ static inline void DrawFrame(const Rect &r, Colours colour, StringID str) */ static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked) { - DrawImageButtons(r, WWT_SHADEBOX, colour, clicked, clicked ? SPR_WINDOW_SHADE: SPR_WINDOW_UNSHADE); + DrawImageButtons(r, WWT_SHADEBOX, colour, clicked, clicked ? SPR_WINDOW_SHADE: SPR_WINDOW_UNSHADE, SA_CENTER); } /** @@ -492,7 +528,7 @@ static inline void DrawShadeBox(const Rect &r, Colours colour, bool clicked) */ static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked) { - DrawImageButtons(r, WWT_STICKYBOX, colour, clicked, clicked ? SPR_PIN_UP : SPR_PIN_DOWN); + DrawImageButtons(r, WWT_STICKYBOX, colour, clicked, clicked ? SPR_PIN_UP : SPR_PIN_DOWN, SA_CENTER); } /** @@ -503,7 +539,7 @@ static inline void DrawStickyBox(const Rect &r, Colours colour, bool clicked) */ static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked) { - DrawImageButtons(r, WWT_DEFSIZEBOX, colour, clicked, SPR_WINDOW_DEFSIZE); + DrawImageButtons(r, WWT_DEFSIZEBOX, colour, clicked, SPR_WINDOW_DEFSIZE, SA_CENTER); } /** @@ -514,7 +550,7 @@ static inline void DrawDefSizeBox(const Rect &r, Colours colour, bool clicked) */ static inline void DrawDebugBox(const Rect &r, Colours colour, bool clicked) { - DrawImageButtons(r, WWT_DEBUGBOX, colour, clicked, SPR_WINDOW_DEBUG); + DrawImageButtons(r, WWT_DEBUGBOX, colour, clicked, SPR_WINDOW_DEBUG, SA_CENTER); } /** @@ -553,12 +589,14 @@ static inline void DrawCloseBox(const Rect &r, Colours colour) /** * Draw a caption bar. - * @param r Rectangle of the bar. - * @param colour Colour of the window. - * @param owner 'Owner' of the window. - * @param str Text to draw in the bar. + * @param r Rectangle of the bar. + * @param colour Colour of the window. + * @param owner 'Owner' of the window. + * @param text_colour Colour of the text. + * @param str Text to draw in the bar. + * @param align Alignment of the text. */ -void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str, const NWidgetCore *widget, const Window *window) +void DrawCaption(const Rect &r, Colours colour, Owner owner, TextColour text_colour, StringID str, StringAlignment align, const NWidgetCore *widget, const Window *window) { bool company_owned = owner < MAX_COMPANIES; @@ -569,8 +607,8 @@ void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str, const if (str != STR_NULL) { Dimension d = GetStringBoundingBox(str); - int offset = std::max(0, ((int)(r.bottom - r.top + 1) - (int)d.height) / 2); // Offset for rendering the text vertically centered - DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, r.top + offset, str, TC_FROMSTRING, SA_HOR_CENTER); + Point p = GetAlignedPosition(r, d, align); + DrawString(r.left + WD_CAPTIONTEXT_LEFT, r.right - WD_CAPTIONTEXT_RIGHT, p.y, str, text_colour, align); } } @@ -581,10 +619,11 @@ void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str, const * @param clicked_button The button-part is lowered. * @param clicked_dropdown The drop-down part is lowered. * @param str Text of the button. + * @param align Alignment of the text within the dropdown. * * @note Magic constants are also used in #NWidgetLeaf::ButtonHit. */ -static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str) +static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicked_button, bool clicked_dropdown, StringID str, StringAlignment align) { int text_offset = std::max(0, ((int)(r.bottom - r.top + 1) - FONT_HEIGHT_NORMAL) / 2); // Offset for rendering the text vertically centered @@ -596,27 +635,15 @@ static inline void DrawButtonDropdown(const Rect &r, Colours colour, bool clicke DrawFrameRect(r.left, r.top, r.right - dd_width, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.right + 1 - dd_width, r.top, r.right, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); DrawSpriteCenteredRect(SPR_ARROW_DOWN, PAL_NONE, r.right - (dd_width - 2) + clicked_dropdown * 2, r.top + image_offset + clicked_dropdown * 2, r.right, r.bottom); - if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); + if (str != STR_NULL) DrawString(r.left + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - dd_width - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK, align); } else { DrawFrameRect(r.left + dd_width, r.top, r.right, r.bottom, colour, clicked_button ? FR_LOWERED : FR_NONE); DrawFrameRect(r.left, r.top, r.left + dd_width - 1, r.bottom, colour, clicked_dropdown ? FR_LOWERED : FR_NONE); DrawSpriteCenteredRect(SPR_ARROW_DOWN, PAL_NONE, r.left + 1 + clicked_dropdown * 2, r.top + image_offset + clicked_dropdown * 2, r.left + dd_width, r.bottom); - if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK); + if (str != STR_NULL) DrawString(r.left + dd_width + WD_DROPDOWNTEXT_LEFT + clicked_button, r.right - WD_DROPDOWNTEXT_RIGHT + clicked_button, r.top + text_offset + clicked_button, str, TC_BLACK, align); } } -/** - * Draw a dropdown #WWT_DROPDOWN widget. - * @param r Rectangle containing the widget. - * @param colour Background colour of the widget. - * @param clicked The widget is lowered. - * @param str Text of the button. - */ -static inline void DrawDropdown(const Rect &r, Colours colour, bool clicked, StringID str) -{ - DrawButtonDropdown(r, colour, false, clicked, str); -} - /** * Paint all widgets of a window. */ @@ -820,6 +847,14 @@ NWidgetBase *NWidgetBase::GetWidgetOfType(WidgetType tp) return (this->type == tp) ? this : nullptr; } +void NWidgetBase::AdjustPaddingForZoom() +{ + this->padding_top = ScaleGUITrad(this->uz_padding_top); + this->padding_right = ScaleGUITrad(this->uz_padding_right); + this->padding_bottom = ScaleGUITrad(this->uz_padding_bottom); + this->padding_left = ScaleGUITrad(this->uz_padding_left); +} + /** * Constructor for resizable nested widgets. * @param tp Nested widget type. @@ -833,6 +868,15 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : this->fill_y = fill_y; } +void NWidgetResizeBase::AdjustPaddingForZoom() +{ + if (!this->absolute) { + this->min_x = ScaleGUITrad(this->uz_min_x); + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); + } + NWidgetBase::AdjustPaddingForZoom(); +} + /** * Set minimal size of the widget. * @param min_x Horizontal minimal size of the widget. @@ -840,6 +884,20 @@ NWidgetResizeBase::NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y) : */ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) { + this->uz_min_x = std::max(this->uz_min_x, min_x); + this->uz_min_y = std::max(this->uz_min_y, min_y); + this->min_x = ScaleGUITrad(this->uz_min_x); + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); +} + +/** + * Set absolute (post-scaling) minimal size of the widget. + * @param min_x Horizontal minimal size of the widget. + * @param min_y Vertical minimal size of the widget. + */ +void NWidgetResizeBase::SetMinimalSizeAbsolute(uint min_x, uint min_y) +{ + this->absolute = true; this->min_x = std::max(this->min_x, min_x); this->min_y = std::max(this->min_y, min_y); uint min_size = 0; @@ -873,7 +931,10 @@ void NWidgetResizeBase::SetMinimalSize(uint min_x, uint min_y) */ void NWidgetResizeBase::SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size) { - this->min_y = min_lines * GetCharacterHeight(size) + spacing; + this->uz_text_lines = min_lines; + this->uz_text_spacing = spacing; + this->uz_text_size = size; + this->min_y = std::max(ScaleGUITrad(this->uz_min_y), this->uz_text_lines * GetCharacterHeight(this->uz_text_size) + ScaleGUITrad(this->uz_text_spacing)); } /** @@ -920,6 +981,8 @@ NWidgetCore::NWidgetCore(WidgetType tp, Colours colour, uint fill_x, uint fill_y this->widget_data = widget_data; this->tool_tip = tool_tip; this->scrollbar_index = -1; + this->text_colour = TC_FROMSTRING; + this->align = SA_CENTER; } /** @@ -943,6 +1006,15 @@ void NWidgetCore::SetDataTip(uint32 widget_data, StringID tool_tip) this->tool_tip = tool_tip; } +/** + * Set the text colour of the nested widget. + * @param colour TextColour to use. + */ +void NWidgetCore::SetTextColour(TextColour colour) +{ + this->text_colour = colour; +} + /** * Set the tool tip of the nested widget. * @param tool_tip Tool tip string to use. @@ -952,6 +1024,15 @@ void NWidgetCore::SetToolTip(StringID tool_tip) this->tool_tip = tool_tip; } +/** + * Set the text/image alignment of the nested widget. + * @param align Alignment to use. + */ +void NWidgetCore::SetAlignment(StringAlignment align) +{ + this->align = align; +} + void NWidgetCore::FillNestedArray(NWidgetBase **array, uint length) { if (this->index >= 0 && (uint)(this->index) < length) array[this->index] = this; @@ -1178,6 +1259,14 @@ NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) return nullptr; } +void NWidgetContainer::AdjustPaddingForZoom() +{ + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + child_wid->AdjustPaddingForZoom(); + } + NWidgetBase::AdjustPaddingForZoom(); +} + /** * Append widget \a wid to container. * @param wid Widget to append. @@ -1219,6 +1308,14 @@ void NWidgetStacked::SetIndex(int index) this->index = index; } +void NWidgetStacked::AdjustPaddingForZoom() +{ + for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + child_wid->AdjustPaddingForZoom(); + } + NWidgetContainer::AdjustPaddingForZoom(); +} + void NWidgetStacked::SetupSmallestSize(Window *w, bool init_array) { if (this->index >= 0 && init_array) { // Fill w->nested_array[] @@ -1332,6 +1429,14 @@ NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags this->flags = flags; } +void NWidgetPIPContainer::AdjustPaddingForZoom() +{ + this->pip_pre = ScaleGUITrad(this->uz_pip_pre); + this->pip_inter = ScaleGUITrad(this->uz_pip_inter); + this->pip_post = ScaleGUITrad(this->uz_pip_post); + NWidgetContainer::AdjustPaddingForZoom(); +} + /** * Set additional pre/inter/post space for the container. * @@ -1343,9 +1448,13 @@ NWidgetPIPContainer::NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags */ void NWidgetPIPContainer::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) { - this->pip_pre = pip_pre; - this->pip_inter = pip_inter; - this->pip_post = pip_post; + this->uz_pip_pre = pip_pre; + this->uz_pip_inter = pip_inter; + this->uz_pip_post = pip_post; + + this->pip_pre = ScaleGUITrad(this->uz_pip_pre); + this->pip_inter = ScaleGUITrad(this->uz_pip_inter); + this->pip_post = ScaleGUITrad(this->uz_pip_post); } void NWidgetPIPContainer::Draw(const Window *w) @@ -1677,12 +1786,12 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, uint x, uint y, uint /** * Generic spacer widget. - * @param length Horizontal size of the spacer widget. + * @param width Horizontal size of the spacer widget. * @param height Vertical size of the spacer widget. */ -NWidgetSpacer::NWidgetSpacer(int length, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0) +NWidgetSpacer::NWidgetSpacer(int width, int height) : NWidgetResizeBase(NWID_SPACER, 0, 0) { - this->SetMinimalSize(length, height); + this->SetMinimalSize(width, height); this->SetResize(0, 0); } @@ -1970,6 +2079,7 @@ NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, int index, N assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME); if (index >= 0) this->SetIndex(index); this->child = child; + this->SetAlignment(SA_TOP | SA_LEFT); } NWidgetBackground::~NWidgetBackground() @@ -2010,6 +2120,12 @@ void NWidgetBackground::SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post) this->child->SetPIP(pip_pre, pip_inter, pip_post); } +void NWidgetBackground::AdjustPaddingForZoom() +{ + if (child != nullptr) child->AdjustPaddingForZoom(); + NWidgetCore::AdjustPaddingForZoom(); +} + void NWidgetBackground::SetupSmallestSize(Window *w, bool init_array) { if (init_array && this->index >= 0) { @@ -2103,12 +2219,12 @@ void NWidgetBackground::Draw(const Window *w) case WWT_FRAME: if (this->index >= 0) w->SetStringParameters(this->index); - DrawFrame(r, this->colour, this->widget_data); + DrawFrame(r, this->colour, this->text_colour, this->widget_data, this->align); break; case WWT_INSET: if (this->index >= 0) w->SetStringParameters(this->index); - DrawInset(r, this->colour, this->widget_data); + DrawInset(r, this->colour, this->text_colour, this->widget_data, this->align); break; default: @@ -2161,6 +2277,8 @@ void NWidgetViewport::SetupSmallestSize(Window *w, bool init_array) void NWidgetViewport::Draw(const Window *w) { + if (this->current_x == 0 || this->current_y == 0) return; + if (this->disp_flags & ND_NO_TRANSPARENCY) { TransparencyOptionBits to_backup = _transparency_opt; _transparency_opt &= (1 << TO_SIGNS) | (1 << TO_LOADING); // Disable all transparency, except textual stuff @@ -2212,16 +2330,75 @@ void NWidgetViewport::UpdateViewportCoordinates(Window *w) * @param w The window the click was in. * @param widget Widget number of the widget clicked in. * @param padding Amount of empty space between the widget edge and the top of the first row. Default value is \c 0. - * @param line_height Height of a single row. A negative value means using the vertical resize step of the widget. * @return Row number clicked at. If clicked at a wrong position, #INT_MAX is returned. */ -int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding, int line_height) const +int Scrollbar::GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding) const { - uint pos = w->GetRowFromWidget(clickpos, widget, padding, line_height); + uint pos = w->GetRowFromWidget(clickpos, widget, padding, -1); if (pos != INT_MAX) pos += this->GetPosition(); return (pos >= this->GetCount()) ? INT_MAX : pos; } +/** + * Update the given list position as if it were on this scroll bar when the given keycode was pressed. + * This does not update the actual position of this scroll bar, that is left to the caller. It does, + * however use the capacity and count of the scroll bar for the bounds and amount to scroll. + * + * When the count is 0 or the return is ES_NOT_HANDLED, then the position is not updated. + * With WKC_UP and WKC_DOWN the position goes one up or down respectively. + * With WKC_PAGEUP and WKC_PAGEDOWN the position goes one capacity up or down respectively. + * With WKC_HOME the first position is selected and with WKC_END the last position is selected. + * This function ensures that pos is in the range [0..count). + * @param list_position The current position in the list. + * @param key_code The pressed key code. + * @return ES_NOT_HANDLED when another key than the 6 specific keys was pressed, otherwise ES_HANDLED. + */ +EventState Scrollbar::UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const +{ + int new_pos = list_position; + switch (keycode) { + case WKC_UP: + /* scroll up by one */ + new_pos--; + break; + + case WKC_DOWN: + /* scroll down by one */ + new_pos++; + break; + + case WKC_PAGEUP: + /* scroll up a page */ + new_pos -= this->GetCapacity(); + break; + + case WKC_PAGEDOWN: + /* scroll down a page */ + new_pos += this->GetCapacity(); + break; + + case WKC_HOME: + /* jump to beginning */ + new_pos = 0; + break; + + case WKC_END: + /* jump to end */ + new_pos = this->GetCount() - 1; + break; + + default: + return ES_NOT_HANDLED; + } + + /* If there are no elements, there is nothing to scroll/update. */ + if (this->GetCount() != 0) { + list_position = Clamp(new_pos, 0, this->GetCount() - 1); + } + return ES_HANDLED; +} + + /** * Set capacity of visible elements from the size and resize properties of a widget. * @param w Window. @@ -2250,6 +2427,22 @@ NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : N assert(tp == NWID_HSCROLLBAR || tp == NWID_VSCROLLBAR); this->sizing_type = NWST_STEP; this->SetIndex(index); + + switch (this->type) { + case NWID_HSCROLLBAR: + this->SetResize(1, 0); + this->SetFill(1, 0); + this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST); + break; + + case NWID_VSCROLLBAR: + this->SetResize(0, 1); + this->SetFill(0, 1); + this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST); + break; + + default: NOT_REACHED(); + } } void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) @@ -2263,17 +2456,11 @@ void NWidgetScrollbar::SetupSmallestSize(Window *w, bool init_array) switch (this->type) { case NWID_HSCROLLBAR: - this->SetMinimalSize(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height); - this->SetResize(1, 0); - this->SetFill(1, 0); - this->SetDataTip(0x0, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST); + this->SetMinimalSizeAbsolute(NWidgetScrollbar::GetHorizontalDimension().width * 3, NWidgetScrollbar::GetHorizontalDimension().height); break; case NWID_VSCROLLBAR: - this->SetMinimalSize(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3); - this->SetResize(0, 1); - this->SetFill(0, 1); - this->SetDataTip(0x0, STR_TOOLTIP_VSCROLL_BAR_SCROLLS_LIST); + this->SetMinimalSizeAbsolute(NWidgetScrollbar::GetVerticalDimension().width, NWidgetScrollbar::GetVerticalDimension().height * 3); break; default: NOT_REACHED(); @@ -2420,6 +2607,11 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, case WWT_EMPTY: break; + case WWT_TEXT: + this->SetFill(0, 0); + this->SetAlignment(SA_LEFT | SA_VERT_CENTER); + break; + case WWT_PUSHBTN: case WWT_IMGBTN: case WWT_PUSHIMGBTN: @@ -2428,7 +2620,6 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, case WWT_PUSHTXTBTN: case WWT_TEXTBTN_2: case WWT_LABEL: - case WWT_TEXT: case WWT_MATRIX: case NWID_BUTTON_DROPDOWN: case NWID_PUSHBUTTON_DROPDOWN: @@ -2444,7 +2635,8 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, case WWT_CAPTION: this->SetFill(1, 0); this->SetResize(1, 0); - //this->min_y = WD_CAPTION_HEIGHT; + //this->SetMinimalSize(0, WD_CAPTION_HEIGHT); + //this->SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, FS_NORMAL); this->SetDataTip(data, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); break; @@ -2456,19 +2648,19 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, case WWT_SHADEBOX: this->SetFill(0, 0); - this->SetMinimalSize(WD_SHADEBOX_TOP, WD_CAPTION_HEIGHT); + this->SetMinimalSize(WD_SHADEBOX_WIDTH, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_SHADE); break; case WWT_DEBUGBOX: this->SetFill(0, 0); - this->SetMinimalSize(WD_DEBUGBOX_TOP, WD_CAPTION_HEIGHT); + this->SetMinimalSize(WD_DEBUGBOX_WIDTH, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_DEBUG); break; case WWT_DEFSIZEBOX: this->SetFill(0, 0); - this->SetMinimalSize(WD_DEFSIZEBOX_TOP, WD_CAPTION_HEIGHT); + this->SetMinimalSize(WD_DEFSIZEBOX_WIDTH, WD_CAPTION_HEIGHT); this->SetDataTip(STR_NULL, STR_TOOLTIP_DEFSIZE); break; @@ -2486,7 +2678,8 @@ NWidgetLeaf::NWidgetLeaf(WidgetType tp, Colours colour, int index, uint32 data, case WWT_DROPDOWN: this->SetFill(0, 0); - //this->min_y = WD_DROPDOWN_HEIGHT; + //this->SetMinimalSize(0, WD_DROPDOWN_HEIGHT); + this->SetAlignment(SA_TOP | SA_LEFT); break; default: @@ -2736,7 +2929,7 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_IMGBTN: case WWT_PUSHIMGBTN: case WWT_IMGBTN_2: - DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data); + DrawImageButtons(r, this->type, this->colour, clicked, this->widget_data, this->align); break; case WWT_TEXTBTN: @@ -2744,7 +2937,7 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_TEXTBTN_2: if (this->index >= 0) w->SetStringParameters(this->index); DrawFrameRect(r.left, r.top, r.right, r.bottom, this->colour, (clicked) ? FR_LOWERED : FR_NONE); - DrawLabel(r, this->type, clicked, this->widget_data); + DrawLabel(r, this->type, clicked, this->text_colour, this->widget_data, this->align); break; case WWT_ARROWBTN: @@ -2757,18 +2950,18 @@ void NWidgetLeaf::Draw(const Window *w) case AWV_RIGHT: sprite = SPR_ARROW_RIGHT; break; default: NOT_REACHED(); } - DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite); + DrawImageButtons(r, WWT_PUSHIMGBTN, this->colour, clicked, sprite, this->align); break; } case WWT_LABEL: if (this->index >= 0) w->SetStringParameters(this->index); - DrawLabel(r, this->type, clicked, this->widget_data); + DrawLabel(r, this->type, clicked, this->text_colour, this->widget_data, this->align); break; case WWT_TEXT: if (this->index >= 0) w->SetStringParameters(this->index); - DrawText(r, (TextColour)this->colour, this->widget_data); + DrawText(r, this->text_colour, this->widget_data, this->align); break; case WWT_MATRIX: @@ -2783,7 +2976,7 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_CAPTION: if (this->index >= 0) w->SetStringParameters(this->index); - DrawCaption(r, this->colour, w->owner, this->widget_data, this, w); + DrawCaption(r, this->colour, w->owner, this->text_colour, this->widget_data, this->align, this, w); break; case WWT_SHADEBOX: @@ -2818,13 +3011,13 @@ void NWidgetLeaf::Draw(const Window *w) case WWT_DROPDOWN: if (this->index >= 0) w->SetStringParameters(this->index); - DrawDropdown(r, this->colour, clicked, this->widget_data); + DrawButtonDropdown(r, this->colour, false, clicked, this->widget_data, this->align); break; case NWID_BUTTON_DROPDOWN: case NWID_PUSHBUTTON_DROPDOWN: if (this->index >= 0) w->SetStringParameters(this->index); - DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data); + DrawButtonDropdown(r, this->colour, clicked, (this->disp_flags & ND_DROPDOWN_ACTIVE) != 0, this->widget_data, this->align); break; default: @@ -2960,7 +3153,7 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != nullptr) { assert(parts->u.xy.x >= 0 && parts->u.xy.y >= 0); - nwrb->SetMinimalSize(ScaleGUITrad(parts->u.xy.x), ScaleGUITrad(parts->u.xy.y)); + nwrb->SetMinimalSize(parts->u.xy.x, parts->u.xy.y); } break; } @@ -2974,6 +3167,22 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, break; } + case WPT_TEXTCOLOUR: { + NWidgetCore *nwc = dynamic_cast(*dest); + if (nwc != nullptr) { + nwc->SetTextColour(parts->u.colour.colour); + } + break; + } + + case WPT_ALIGNMENT: { + NWidgetCore *nwc = dynamic_cast(*dest); + if (nwc != nullptr) { + nwc->SetAlignment(parts->u.align.align); + } + break; + } + case WPT_FILL: { NWidgetResizeBase *nwrb = dynamic_cast(*dest); if (nwrb != nullptr) nwrb->SetFill(parts->u.xy.x, parts->u.xy.y); @@ -2990,15 +3199,15 @@ static int MakeNWidget(const NWidgetPart *parts, int count, NWidgetBase **dest, } case WPT_PADDING: - if (*dest != nullptr) (*dest)->SetPadding(ScaleGUITrad(parts->u.padding.top), ScaleGUITrad(parts->u.padding.right), ScaleGUITrad(parts->u.padding.bottom), ScaleGUITrad(parts->u.padding.left)); + if (*dest != nullptr) (*dest)->SetPadding(parts->u.padding.top, parts->u.padding.right, parts->u.padding.bottom, parts->u.padding.left); break; case WPT_PIPSPACE: { NWidgetPIPContainer *nwc = dynamic_cast(*dest); - if (nwc != nullptr) nwc->SetPIP(ScaleGUITrad(parts->u.pip.pre), ScaleGUITrad(parts->u.pip.inter), ScaleGUITrad(parts->u.pip.post)); + if (nwc != nullptr) nwc->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); NWidgetBackground *nwb = dynamic_cast(*dest); - if (nwb != nullptr) nwb->SetPIP(ScaleGUITrad(parts->u.pip.pre), ScaleGUITrad(parts->u.pip.inter), ScaleGUITrad(parts->u.pip.post)); + if (nwb != nullptr) nwb->SetPIP(parts->u.pip.pre, parts->u.pip.inter, parts->u.pip.post); break; } @@ -3195,7 +3404,7 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid NWidgetHorizontal *hor = nullptr; // Storage for buttons in one row. int hor_length = 0; - Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON); + Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON, nullptr, ZOOM_LVL_OUT_4X); sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT; sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1; // 1 for the 'offset' of being pressed diff --git a/src/widget_type.h b/src/widget_type.h index e4182050f4..508112183f 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -104,6 +104,8 @@ enum WidgetType { WPT_DATATIP, ///< Widget part for specifying data and tooltip. WPT_PADDING, ///< Widget part for specifying a padding. WPT_PIPSPACE, ///< Widget part for specifying pre/inter/post space for containers. + WPT_TEXTCOLOUR, ///< Widget part for specifying text colour. + WPT_ALIGNMENT, ///< Widget part for specifying text/image alignment. WPT_ENDCONTAINER, ///< Widget part to denote end of a container. WPT_FUNCTION, ///< Widget part for calling a user function. WPT_SCROLLBAR, ///< Widget part for attaching a scrollbar. @@ -140,6 +142,7 @@ class NWidgetBase : public ZeroedMemoryAllocator { public: NWidgetBase(WidgetType tp); + virtual void AdjustPaddingForZoom(); virtual void SetupSmallestSize(Window *w, bool init_array) = 0; virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) = 0; @@ -161,10 +164,11 @@ public: */ inline void SetPadding(uint8 top, uint8 right, uint8 bottom, uint8 left) { - this->padding_top = top; - this->padding_right = right; - this->padding_bottom = bottom; - this->padding_left = left; + this->uz_padding_top = top; + this->uz_padding_right = right; + this->uz_padding_bottom = bottom; + this->uz_padding_left = left; + this->AdjustPaddingForZoom(); } inline uint GetHorizontalStepSize(SizingType sizing) const; @@ -173,12 +177,22 @@ public: virtual void Draw(const Window *w) = 0; virtual void SetDirty(const Window *w) const; - WidgetType type; ///< Type of the widget / nested widget. + Rect GetCurrentRect() const + { + Rect r; + r.left = this->pos_x; + r.top = this->pos_y; + r.right = this->pos_x + this->current_x; + r.bottom = this->pos_y + this->current_y; + return r; + } + + WidgetType type; ///< Type of the widget / nested widget. NWidSizingType sizing_type; ///< Type for deciding minimal sizes of the widget. - uint fill_x; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable). - uint fill_y; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable). - uint resize_x; ///< Horizontal resize step (\c 0 means not resizable). - uint resize_y; ///< Vertical resize step (\c 0 means not resizable). + uint fill_x; ///< Horizontal fill stepsize (from initial size, \c 0 means not resizable). + uint fill_y; ///< Vertical fill stepsize (from initial size, \c 0 means not resizable). + uint resize_x; ///< Horizontal resize step (\c 0 means not resizable). + uint resize_y; ///< Vertical resize step (\c 0 means not resizable). /* Size of the widget in the smallest window possible. * Computed by #SetupSmallestSize() followed by #AssignSizePosition(). */ @@ -199,6 +213,11 @@ public: uint8 padding_bottom; ///< Paddings added to the bottom of the widget. Managed by parent container widget. uint8 padding_left; ///< Paddings added to the left of the widget. Managed by parent container widget. (parent container may swap this with padding_right for RTL) + uint8 uz_padding_top; ///< Unscaled top padding, for resize calculation. + uint8 uz_padding_right; ///< Unscaled right padding, for resize calculation. + uint8 uz_padding_bottom; ///< Unscaled bottom padding, for resize calculation. + uint8 uz_padding_left; ///< Unscaled left padding, for resize calculation. + protected: inline void StoreSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height); }; @@ -250,15 +269,25 @@ class NWidgetResizeBase : public NWidgetBase { public: NWidgetResizeBase(WidgetType tp, uint fill_x, uint fill_y); + void AdjustPaddingForZoom() override; void SetMinimalSize(uint min_x, uint min_y); + void SetMinimalSizeAbsolute(uint min_x, uint min_y); void SetMinimalTextLines(uint8 min_lines, uint8 spacing, FontSize size); void SetFill(uint fill_x, uint fill_y); void SetResize(uint resize_x, uint resize_y); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; uint min_x; ///< Minimal horizontal size of only this widget. uint min_y; ///< Minimal vertical size of only this widget. + + bool absolute; ///< Set if minimum size is fixed and should not be resized. + uint uz_min_x; ///< Unscaled Minimal horizontal size of only this widget. + uint uz_min_y; ///< Unscaled Minimal vertical size of only this widget. + + uint8 uz_text_lines; ///< 'Unscaled' text lines, stored for resize calculation. + uint8 uz_text_spacing; ///< 'Unscaled' text padding, stored for resize calculation. + FontSize uz_text_size; ///< 'Unscaled' font size, stored for resize calculation. }; /** Nested widget flags that affect display and interaction with 'real' widgets. */ @@ -302,6 +331,8 @@ public: void SetIndex(int index); void SetDataTip(uint32 widget_data, StringID tool_tip); void SetToolTip(StringID tool_tip); + void SetTextColour(TextColour colour); + void SetAlignment(StringAlignment align); inline void SetLowered(bool lowered); inline bool IsLowered() const; @@ -327,6 +358,8 @@ public: StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips int scrollbar_index; ///< Index of an attached scrollbar. TextColour highlight_colour; ///< Colour of highlight. + TextColour text_colour; ///< Colour of text within widget. + StringAlignment align; ///< Alignment of text/image within widget. }; /** @@ -391,6 +424,7 @@ public: NWidgetContainer(WidgetType tp); ~NWidgetContainer(); + void AdjustPaddingForZoom() override; void Add(NWidgetBase *wid); void FillNestedArray(NWidgetBase **array, uint length) override; @@ -429,6 +463,7 @@ public: void SetIndex(int index); + void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; void FillNestedArray(NWidgetBase **array, uint length) override; @@ -456,6 +491,7 @@ class NWidgetPIPContainer : public NWidgetContainer { public: NWidgetPIPContainer(WidgetType tp, NWidContainerFlags flags = NC_NONE); + void AdjustPaddingForZoom() override; void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); void Draw(const Window *w) override; @@ -466,6 +502,10 @@ protected: uint8 pip_pre; ///< Amount of space before first widget. uint8 pip_inter; ///< Amount of space between widgets. uint8 pip_post; ///< Amount of space after last widget. + + uint8 uz_pip_pre; ///< Unscaled space before first widget. + uint8 uz_pip_inter; ///< Unscaled space between widgets. + uint8 uz_pip_post; ///< Unscaled space after last widget. }; /** @@ -476,8 +516,8 @@ class NWidgetHorizontal : public NWidgetPIPContainer { public: NWidgetHorizontal(NWidContainerFlags flags = NC_NONE); - void SetupSmallestSize(Window *w, bool init_array); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); + void SetupSmallestSize(Window *w, bool init_array) override; + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -488,7 +528,7 @@ class NWidgetHorizontalLTR : public NWidgetHorizontal { public: NWidgetHorizontalLTR(NWidContainerFlags flags = NC_NONE); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -499,8 +539,8 @@ class NWidgetVertical : public NWidgetPIPContainer { public: NWidgetVertical(NWidContainerFlags flags = NC_NONE); - void SetupSmallestSize(Window *w, bool init_array); - void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl); + void SetupSmallestSize(Window *w, bool init_array) override; + void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; }; /** @@ -552,7 +592,7 @@ private: */ class NWidgetSpacer : public NWidgetResizeBase { public: - NWidgetSpacer(int length, int height); + NWidgetSpacer(int width, int height); void SetupSmallestSize(Window *w, bool init_array) override; void FillNestedArray(NWidgetBase **array, uint length) override; @@ -574,6 +614,7 @@ public: void Add(NWidgetBase *nwid); void SetPIP(uint8 pip_pre, uint8 pip_inter, uint8 pip_post); + void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w, bool init_array) override; void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override; @@ -763,7 +804,8 @@ public: } } - int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0, int line_height = -1) const; + int GetScrolledRowFromWidget(int clickpos, const Window * const w, int widget, int padding = 0) const; + EventState UpdateListPositionOnKeyPress(int &list_position, uint16 keycode) const; }; /** @@ -919,6 +961,22 @@ struct NWidgetPartTextLines { FontSize size; ///< Font size of text lines. }; +/** + * Widget part for storing text colour. + * @ingroup NestedWidgetParts + */ +struct NWidgetPartTextColour { + TextColour colour; ///< TextColour for DrawString. +}; + +/** + * Widget part for setting text/image alignment within a widget. + * @ingroup NestedWidgetParts + */ +struct NWidgetPartAlignment { + StringAlignment align; ///< Alignment of text/image. +}; + /** * Pointer to function returning a nested widget. * @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget. @@ -940,6 +998,8 @@ struct NWidgetPart { NWidgetPartPaddings padding; ///< Part with paddings. NWidgetPartPIP pip; ///< Part with pre/inter/post spaces. NWidgetPartTextLines text_lines; ///< Part with text line data. + NWidgetPartTextColour colour; ///< Part with text colour data. + NWidgetPartAlignment align; ///< Part with internal alignment. NWidgetFunctionType *func_ptr; ///< Part with a function call. NWidContainerFlags cont_flags; ///< Part with container flags. NWidSizingType sizing_type; ///< Part with sizing type. @@ -1016,6 +1076,36 @@ static inline NWidgetPart SetMinimalTextLines(uint8 lines, uint8 spacing, FontSi return part; } +/** + * Widget part function for setting the text colour. + * @param colour Colour to draw string within widget. + * @ingroup NestedWidgetParts + */ +static inline NWidgetPart SetTextColour(TextColour colour) +{ + NWidgetPart part; + + part.type = WPT_TEXTCOLOUR; + part.u.colour.colour = colour; + + return part; +} + +/** + * Widget part function for setting the alignment of text/images. + * @param align Alignment of text/image within widget. + * @ingroup NestedWidgetParts + */ +static inline NWidgetPart SetAlignment(StringAlignment align) +{ + NWidgetPart part; + + part.type = WPT_ALIGNMENT; + part.u.align.align = align; + + return part; +} + /** * Widget part function for setting filling. * @param fill_x Horizontal filling step from minimal size. diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt index 18ecd529e8..5586870a3a 100644 --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -44,6 +44,8 @@ add_files( screenshot_widget.h settings_widget.h sign_widget.h + slider.cpp + slider_func.h smallmap_widget.h station_widget.h statusbar_widget.h diff --git a/src/widgets/dropdown.cpp b/src/widgets/dropdown.cpp index 29b473d2d4..fe7bb96a2c 100644 --- a/src/widgets/dropdown.cpp +++ b/src/widgets/dropdown.cpp @@ -72,13 +72,7 @@ StringID DropDownListCharStringItem::String() const DropDownListIconItem::DropDownListIconItem(SpriteID sprite, PaletteID pal, StringID string, int result, bool masked) : DropDownListParamStringItem(string, result, masked), sprite(sprite), pal(pal) { this->dim = GetSpriteSize(sprite); - if (this->dim.height < (uint)FONT_HEIGHT_NORMAL) { - this->sprite_y = (FONT_HEIGHT_NORMAL - dim.height) / 2; - this->text_y = 0; - } else { - this->sprite_y = 0; - this->text_y = (dim.height - FONT_HEIGHT_NORMAL) / 2; - } + this->sprite_y = dim.height; } uint DropDownListIconItem::Height(uint width) const @@ -94,8 +88,8 @@ uint DropDownListIconItem::Width() const void DropDownListIconItem::Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const { bool rtl = _current_text_dir == TD_RTL; - DrawSprite(this->sprite, this->pal, rtl ? right - this->dim.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, Center(top, bottom - top, this->dim.height)); - DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : (this->dim.width + WD_FRAMERECT_LEFT)), right - WD_FRAMERECT_RIGHT - (rtl ? (this->dim.width + WD_FRAMERECT_RIGHT) : 0), Center(top, bottom - top), this->String(), sel ? TC_WHITE : TC_BLACK); + DrawSprite(this->sprite, this->pal, rtl ? right - this->dim.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, CenterBounds(top, bottom, this->sprite_y)); + DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : (this->dim.width + WD_FRAMERECT_LEFT)), right - WD_FRAMERECT_RIGHT - (rtl ? (this->dim.width + WD_FRAMERECT_RIGHT) : 0), CenterBounds(top, bottom, FONT_HEIGHT_NORMAL), this->String(), sel ? TC_WHITE : TC_BLACK); } void DropDownListIconItem::SetDimension(Dimension d) @@ -162,7 +156,7 @@ struct DropdownWindow : Window { uint items_width = size.width - (scroll ? NWidgetScrollbar::GetVerticalDimension().width : 0); NWidgetCore *nwi = this->GetWidget(WID_DM_ITEMS); - nwi->SetMinimalSize(items_width, size.height + 4); + nwi->SetMinimalSizeAbsolute(items_width, size.height + 4); nwi->colour = wi_colour; nwi = this->GetWidget(WID_DM_SCROLL); @@ -564,8 +558,7 @@ void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int butt */ int HideDropDownMenu(Window *pw) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class != WC_DROPDOWN_MENU) continue; DropdownWindow *dw = dynamic_cast(w); diff --git a/src/widgets/dropdown_type.h b/src/widgets/dropdown_type.h index b75347dad8..bc8ebaffa6 100644 --- a/src/widgets/dropdown_type.h +++ b/src/widgets/dropdown_type.h @@ -85,7 +85,6 @@ class DropDownListIconItem : public DropDownListParamStringItem { PaletteID pal; Dimension dim; uint sprite_y; - uint text_y; public: DropDownListIconItem(SpriteID sprite, PaletteID pal, StringID string, int result, bool masked); diff --git a/src/widgets/network_widget.h b/src/widgets/network_widget.h index 8372b6360d..2ed94d2849 100644 --- a/src/widgets/network_widget.h +++ b/src/widgets/network_widget.h @@ -71,9 +71,6 @@ enum NetworkStartServerWidgets { WID_NSS_SPECTATORS_TXT, ///< 'Max spectators' text. WID_NSS_SPECTATORS_BTNU, ///< 'Max spectators' uparrow. - WID_NSS_LANGUAGE_LABEL, ///< Label for 'language spoken'. - WID_NSS_LANGUAGE_BTN, ///< 'Language spoken' droplist button. - WID_NSS_GENERATE_GAME, ///< New game button. WID_NSS_LOAD_GAME, ///< Load game button. WID_NSS_PLAY_SCENARIO, ///< Play scenario button. @@ -99,12 +96,16 @@ enum NetworkLobbyWidgets { /** Widgets of the #NetworkClientListWindow class. */ enum ClientListWidgets { - WID_CL_PANEL, ///< Panel of the window. -}; - -/** Widgets of the #NetworkClientListPopupWindow class. */ -enum ClientListPopupWidgets { - WID_CLP_PANEL, ///< Panel of the window. + WID_CL_PANEL, ///< Panel of the window. + WID_CL_SERVER_SELECTOR, ///< Selector to hide the server frame. + WID_CL_SERVER_NAME, ///< Server name. + WID_CL_SERVER_NAME_EDIT, ///< Edit button for server name. + WID_CL_SERVER_VISIBILITY, ///< Server visibility. + WID_CL_CLIENT_NAME, ///< Client name. + WID_CL_CLIENT_NAME_EDIT, ///< Edit button for client name. + WID_CL_MATRIX, ///< Company/client list. + WID_CL_SCROLLBAR, ///< Scrollbar for company/client list. + WID_CL_COMPANY_JOIN, ///< Used for QueryWindow when a company has a password. }; /** Widgets of the #NetworkJoinStatusWindow class. */ diff --git a/src/widgets/settings_widget.h b/src/widgets/settings_widget.h index 6c02eba38b..263a6b8fa8 100644 --- a/src/widgets/settings_widget.h +++ b/src/widgets/settings_widget.h @@ -33,14 +33,17 @@ enum GameOptionsWidgets { WID_GO_BASE_GRF_TEXTFILE, ///< Open base GRF readme, changelog (+1) or license (+2). WID_GO_BASE_GRF_DESCRIPTION = WID_GO_BASE_GRF_TEXTFILE + TFT_END, ///< Description of selected base GRF. WID_GO_BASE_SFX_DROPDOWN, ///< Use to select a base SFX. + WID_GO_BASE_SFX_VOLUME, ///< Change sound effects volume. WID_GO_BASE_SFX_TEXTFILE, ///< Open base SFX readme, changelog (+1) or license (+2). WID_GO_BASE_SFX_DESCRIPTION = WID_GO_BASE_SFX_TEXTFILE + TFT_END, ///< Description of selected base SFX. WID_GO_BASE_MUSIC_DROPDOWN, ///< Use to select a base music set. + WID_GO_BASE_MUSIC_VOLUME, ///< Change music volume. WID_GO_BASE_MUSIC_STATUS, ///< Info about corrupted files etc. WID_GO_BASE_MUSIC_TEXTFILE, ///< Open base music readme, changelog (+1) or license (+2). WID_GO_BASE_MUSIC_DESCRIPTION = WID_GO_BASE_MUSIC_TEXTFILE + TFT_END, ///< Description of selected base music set. WID_GO_FONT_ZOOM_DROPDOWN, ///< Dropdown for the font zoom level. WID_GO_VIDEO_ACCEL_BUTTON, ///< Toggle for video acceleration. + WID_GO_VIDEO_VSYNC_BUTTON, ///< Toggle for video vsync. WID_GO_REFRESH_RATE_DROPDOWN, ///< Dropdown for all available refresh rates. }; @@ -52,6 +55,7 @@ enum GameSettingsWidgets { WID_GS_HELP_TEXT, ///< Information area to display help text of the selected option. WID_GS_EXPAND_ALL, ///< Expand all button. WID_GS_COLLAPSE_ALL, ///< Collapse all button. + WID_GS_RESET_ALL, ///< Reset all button. WID_GS_RESTRICT_CATEGORY, ///< Label upfront to the category drop-down box to restrict the list of settings to show WID_GS_RESTRICT_TYPE, ///< Label upfront to the type drop-down box to restrict the list of settings to show WID_GS_RESTRICT_DROPDOWN, ///< The drop down box to restrict the list of settings diff --git a/src/widgets/slider.cpp b/src/widgets/slider.cpp new file mode 100644 index 0000000000..6d6d732884 --- /dev/null +++ b/src/widgets/slider.cpp @@ -0,0 +1,70 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file slider.cpp Implementation of the horizontal slider widget. */ + +#include "../stdafx.h" +#include "../window_gui.h" +#include "../window_func.h" +#include "../strings_func.h" +#include "../zoom_func.h" +#include "slider_func.h" + +#include "../safeguards.h" + + +/** + * Draw a volume slider widget with know at given value + * @param r Rectangle to draw the widget in + * @param value Value to put the slider at + */ +void DrawVolumeSliderWidget(Rect r, byte value) +{ + static const int slider_width = 3; + + /* Draw a wedge indicating low to high volume level. */ + const int ha = (r.bottom - r.top) / 5; + int wx1 = r.left, wx2 = r.right; + if (_current_text_dir == TD_RTL) std::swap(wx1, wx2); + const uint shadow = _colour_gradient[COLOUR_GREY][3]; + const uint fill = _colour_gradient[COLOUR_GREY][6]; + const uint light = _colour_gradient[COLOUR_GREY][7]; + const std::vector wedge{ Point{wx1, r.bottom - ha}, Point{wx2, r.top + ha}, Point{wx2, r.bottom - ha} }; + GfxFillPolygon(wedge, fill); + GfxDrawLine(wedge[0].x, wedge[0].y, wedge[2].x, wedge[2].y, light); + GfxDrawLine(wedge[1].x, wedge[1].y, wedge[2].x, wedge[2].y, _current_text_dir == TD_RTL ? shadow : light); + GfxDrawLine(wedge[0].x, wedge[0].y, wedge[1].x, wedge[1].y, shadow); + + /* Draw a slider handle indicating current volume level. */ + const int sw = ScaleGUITrad(slider_width); + if (_current_text_dir == TD_RTL) value = 127 - value; + const int x = r.left + (value * (r.right - r.left - sw) / 127); + DrawFrameRect(x, r.top, x + sw, r.bottom, COLOUR_GREY, FR_NONE); +} + +/** + * Handle click on a volume slider widget to change the value + * @param r Rectangle of the widget + * @param pt Clicked point + * @param value[in,out] Volume value to modify + * @return True if the volume setting was modified + */ +bool ClickVolumeSliderWidget(Rect r, Point pt, byte &value) +{ + byte new_vol = Clamp((pt.x - r.left) * 127 / (r.right - r.left), 0, 127); + if (_current_text_dir == TD_RTL) new_vol = 127 - new_vol; + + /* Clamp to make sure min and max are properly settable */ + if (new_vol > 124) new_vol = 127; + if (new_vol < 3) new_vol = 0; + if (new_vol != value) { + value = new_vol; + return true; + } + + return false; +} diff --git a/src/widgets/slider_func.h b/src/widgets/slider_func.h new file mode 100644 index 0000000000..1aa1fa10c6 --- /dev/null +++ b/src/widgets/slider_func.h @@ -0,0 +1,21 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file slider_type.h Types related to the horizontal slider widget. */ + +#ifndef WIDGETS_SLIDER_TYPE_H +#define WIDGETS_SLIDER_TYPE_H + +#include "../window_type.h" +#include "../gfx_func.h" + + +void DrawVolumeSliderWidget(Rect r, byte value); +bool ClickVolumeSliderWidget(Rect r, Point pt, byte &value); + + +#endif /* WIDGETS_SLIDER_TYPE_H */ diff --git a/src/window.cpp b/src/window.cpp index 34be51f5d8..24f2c70f8b 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -949,8 +949,7 @@ static bool MayBeShown(const Window *w) */ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bottom) { - const Window *v; - FOR_ALL_WINDOWS_FROM_BACK_FROM(v, w->z_front) { + for (const Window *v : Window::IterateFromBack(w->z_front)) { if (MayBeShown(v) && right > v->left && bottom > v->top && @@ -1009,13 +1008,11 @@ static void DrawOverlappedWindow(Window *w, int left, int top, int right, int bo */ void DrawOverlappedWindowForAll(int left, int top, int right, int bottom) { - Window *w; - DrawPixelInfo *old_dpi = _cur_dpi; DrawPixelInfo bk; _cur_dpi = &bk; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (MayBeShown(w) && right > w->left && bottom > w->top && @@ -1108,8 +1105,7 @@ void Window::SetShaded(bool make_shaded) */ static Window *FindChildWindow(const Window *w, WindowClass wc) { - Window *v; - FOR_ALL_WINDOWS_FROM_BACK(v) { + for (Window *v : Window::IterateFromBack()) { if ((wc == WC_INVALID || wc == v->window_class) && v->parent == w) return v; } @@ -1183,8 +1179,7 @@ Window::~Window() */ Window *FindWindowById(WindowClass cls, WindowNumber number) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class == cls && w->window_number == number) return w; } @@ -1199,8 +1194,7 @@ Window *FindWindowById(WindowClass cls, WindowNumber number) */ Window *FindWindowByClass(WindowClass cls) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class == cls) return w; } @@ -1216,8 +1210,7 @@ Window *FindWindowByClass(WindowClass cls) void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) { Window *w = FindWindowById(cls, number); - if (force || w == nullptr || - (w->flags & WF_STICKY) == 0) { + if (w != nullptr && (force || (w->flags & WF_STICKY) == 0)) { delete w; } } @@ -1228,13 +1221,11 @@ void DeleteWindowById(WindowClass cls, WindowNumber number, bool force) */ void DeleteWindowByClass(WindowClass cls) { - Window *w; - restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class == cls) { delete w; goto restart_search; @@ -1250,13 +1241,11 @@ restart_search: */ void DeleteCompanyWindows(CompanyID id) { - Window *w; - restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->owner == id) { delete w; goto restart_search; @@ -1276,8 +1265,7 @@ restart_search: */ void ChangeWindowOwner(Owner old_owner, Owner new_owner) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->owner != old_owner) continue; switch (w->window_class) { @@ -1674,8 +1662,7 @@ static bool IsGoodAutoPlace1(int left, int top, int width, int height, int toolb } /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == WC_MAIN_WINDOW) continue; if (right > w->left && @@ -1720,8 +1707,7 @@ static bool IsGoodAutoPlace2(int left, int top, int width, int height, int toolb if (top < toolbar_y || top > _screen.height - (height >> 2)) return false; /* Make sure it is not obscured by any window. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == WC_MAIN_WINDOW) continue; if (left + width > w->left && @@ -1763,8 +1749,7 @@ static Point GetAutoPlacePosition(int width, int height) * The new window must be entirely on-screen, and not overlap with an existing window. * Eight starting points are tried, two at each corner. */ - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace1(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt; @@ -1781,7 +1766,7 @@ static Point GetAutoPlacePosition(int width, int height) * The new window may be partly off-screen, and must not overlap with an existing window. * Only four starting points are tried. */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == WC_MAIN_WINDOW) continue; if (IsGoodAutoPlace2(w->left + w->width, w->top, width, height, toolbar_y, pt)) return pt; @@ -1802,7 +1787,7 @@ static Point GetAutoPlacePosition(int width, int height) int offset_y = std::max(NWidgetLeaf::closebox_dimension.height, FONT_HEIGHT_NORMAL + WD_CAPTIONTEXT_TOP + WD_CAPTIONTEXT_BOTTOM); restart: - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->left == left && w->top == top) { left += offset_x; top += offset_y; @@ -1983,8 +1968,7 @@ Window::Window(WindowDesc *desc) : window_desc(desc), mouse_capture_widget(-1) */ Window *FindWindowFromPt(int x, int y) { - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if (MayBeShown(w) && IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { return w; } @@ -2036,10 +2020,9 @@ void UnInitWindowSystem() { UnshowCriticalError(); - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) delete w; + for (Window *w : Window::IterateFromFront()) delete w; - for (w = _z_front_window; w != nullptr; /* nothing */) { + for (Window *w = _z_front_window; w != nullptr; /* nothing */) { Window *to_del = w; w = w->z_back; free(to_del); @@ -2066,8 +2049,7 @@ static void DecreaseWindowCounters() if (_scroller_click_timeout != 0) _scroller_click_timeout--; if (hundredth_tick_timeout != 0) hundredth_tick_timeout--; - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if (!_network_dedicated && hundredth_tick_timeout == 0) w->OnHundredthTick(); if (_scroller_click_timeout == 0) { @@ -2093,7 +2075,7 @@ static void DecreaseWindowCounters() w->OnMouseLoop(); } - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if ((w->flags & WF_TIMEOUT) && --w->timeout_timer == 0) { CLRBITS(w->flags, WF_TIMEOUT); @@ -2421,8 +2403,7 @@ static EventState HandleWindowDragging() if (_left_button_down && _cursor.delta.x == 0 && _cursor.delta.y == 0) return ES_HANDLED; /* Otherwise find the window... */ - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->flags & WF_DRAGGING) { /* Stop the dragging if the left mouse button was released */ if (!_left_button_down) { @@ -2441,13 +2422,11 @@ static EventState HandleWindowDragging() int ny = y; if (_settings_client.gui.window_snap_radius != 0) { - const Window *v; - int hsnap = _settings_client.gui.window_snap_radius; int vsnap = _settings_client.gui.window_snap_radius; int delta; - FOR_ALL_WINDOWS_FROM_BACK(v) { + for (const Window *v : Window::IterateFromBack()) { if (v == w) continue; // Don't snap at yourself if (y + w->height > v->top && y < v->top + v->height) { @@ -2670,8 +2649,7 @@ static void HandleScrollbarScrolling(Window *w) */ static EventState HandleActiveWidget() { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->mouse_capture_widget >= 0) { /* Abort if no button is clicked any more. */ if (!_left_button_down) { @@ -2797,8 +2775,7 @@ static bool MaybeBringWindowToFront(Window *w) w_height = w->unshaded_size.height; } - Window *u; - FOR_ALL_WINDOWS_FROM_BACK_FROM(u, w->z_front) { + for (Window *u : Window::IterateFromBack(w->z_front)) { /* A modal child will prevent the activation of the parent window */ if (u->parent == w && (u->window_desc->flags & WDF_MODAL)) { u->SetWhiteBorder(); @@ -2940,8 +2917,7 @@ void HandleKeypress(uint keycode, WChar key) } /* Call the event, start with the uppermost window, but ignore the toolbar. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if (w->window_class == WC_MAIN_TOOLBAR) continue; if (w->window_desc->hotkeys != nullptr) { int hotkey = w->window_desc->hotkeys->CheckMatch(keycode); @@ -2950,7 +2926,7 @@ void HandleKeypress(uint keycode, WChar key) if (w->OnKeyPress(key, keycode) == ES_HANDLED) return; } - w = FindWindowById(WC_MAIN_TOOLBAR, 0); + Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0); /* When there is no toolbar w is null, check for that */ if (w != nullptr) { if (w->window_desc->hotkeys != nullptr) { @@ -2969,8 +2945,7 @@ void HandleKeypress(uint keycode, WChar key) void HandleCtrlChanged() { /* Call the event, start with the uppermost window. */ - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if (w->OnCTRLStateChange() == ES_HANDLED) return; } } @@ -3370,8 +3345,8 @@ static void CheckSoftLimit() for (;;) { uint deletable_count = 0; - Window *w, *last_deletable = nullptr; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + Window *last_deletable = nullptr; + for (Window *w : Window::IterateFromFront()) { if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || (w->flags & WF_STICKY)) continue; last_deletable = w; @@ -3426,8 +3401,7 @@ void InputLoop() */ void CallWindowRealtimeTickEvent(uint delta_ms) { - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { w->OnRealtimeTick(delta_ms); } } @@ -3455,10 +3429,8 @@ void UpdateWindows() NetworkChatMessageLoop(); } - Window *w; - /* Process invalidations before anything else. */ - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { w->ProcessScheduledInvalidations(); w->ProcessHighlightedInvalidations(); } @@ -3491,7 +3463,7 @@ void UpdateWindows() if (window_timer.HasElapsed()) { window_timer.SetInterval(MILLISECONDS_PER_TICK); - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { if ((w->flags & WF_WHITE_BORDER) && --w->white_border_timer == 0) { CLRBITS(w->flags, WF_WHITE_BORDER); w->SetDirty(); @@ -3501,7 +3473,7 @@ void UpdateWindows() DrawDirtyBlocks(); - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { /* Update viewport only if window is not shaded. */ if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w); } @@ -3517,8 +3489,7 @@ void UpdateWindows() */ void SetWindowDirty(WindowClass cls, WindowNumber number) { - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == cls && w->window_number == number) w->SetDirty(); } } @@ -3531,8 +3502,7 @@ void SetWindowDirty(WindowClass cls, WindowNumber number) */ void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index) { - const Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == cls && w->window_number == number) { w->SetWidgetDirty(widget_index); } @@ -3545,8 +3515,7 @@ void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_inde */ void SetWindowClassesDirty(WindowClass cls) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class == cls) w->SetDirty(); } } @@ -3618,8 +3587,7 @@ void Window::ProcessHighlightedInvalidations() */ void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class == cls && w->window_number == number) { w->InvalidateData(data, gui_scope); } @@ -3636,9 +3604,7 @@ void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool g */ void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) { - Window *w; - - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { if (w->window_class == cls) { w->InvalidateData(data, gui_scope); } @@ -3650,8 +3616,7 @@ void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope) */ void CallWindowGameTickEvent() { - Window *w; - FOR_ALL_WINDOWS_FROM_FRONT(w) { + for (Window *w : Window::IterateFromFront()) { w->OnGameTick(); } } @@ -3664,13 +3629,11 @@ void CallWindowGameTickEvent() */ void DeleteNonVitalWindows() { - Window *w; - restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_class != WC_MAIN_WINDOW && w->window_class != WC_SELECT_GAME && w->window_class != WC_MAIN_TOOLBAR && @@ -3694,8 +3657,6 @@ restart_search: */ void DeleteAllNonVitalWindows() { - Window *w; - /* Delete every window except for stickied ones, then sticky ones as well */ DeleteNonVitalWindows(); @@ -3703,7 +3664,7 @@ restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->flags & WF_STICKY) { delete w; goto restart_search; @@ -3728,20 +3689,18 @@ void DeleteAllMessages() */ void DeleteConstructionWindows() { - Window *w; - restart_search: /* When we find the window to delete, we need to restart the search * as deleting this window could cascade in deleting (many) others * anywhere in the z-array */ - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->window_desc->flags & WDF_CONSTRUCTION) { delete w; goto restart_search; } } - FOR_ALL_WINDOWS_FROM_BACK(w) w->SetDirty(); + for (const Window *w : Window::IterateFromBack()) w->SetDirty(); } /** @@ -3775,7 +3734,7 @@ void HideVitalWindows() } /** Re-initialize all windows. */ -void ReInitAllWindows() +void ReInitAllWindows(bool zoom_changed) { NWidgetLeaf::InvalidateDimensionCache(); // Reset cached sizes of several widgets. NWidgetScrollbar::InvalidateDimensionCache(); @@ -3783,8 +3742,8 @@ void ReInitAllWindows() extern void InitDepotWindowBlockSizes(); InitDepotWindowBlockSizes(); - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { + if (zoom_changed) w->nested_root->AdjustPaddingForZoom(); w->ReInit(); } @@ -3874,8 +3833,7 @@ int PositionNetworkChatWindow(Window *w) */ void ChangeVehicleViewports(VehicleID from_index, VehicleID to_index) { - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (const Window *w : Window::IterateFromBack()) { if (w->viewport != nullptr && w->viewport->follow_vehicle == from_index) { w->viewport->follow_vehicle = to_index; w->SetDirty(); @@ -3893,8 +3851,7 @@ void RelocateAllWindows(int neww, int newh) { DeleteWindowById(WC_DROPDOWN_MENU, 0); - Window *w; - FOR_ALL_WINDOWS_FROM_BACK(w) { + for (Window *w : Window::IterateFromBack()) { int left, top; /* XXX - this probably needs something more sane. For example specifying * in a 'backup'-desc that the window should always be centered. */ diff --git a/src/window_func.h b/src/window_func.h index 5393bc6566..7180a3bf1e 100644 --- a/src/window_func.h +++ b/src/window_func.h @@ -45,7 +45,11 @@ void DeleteToolbarLinkedWindows(); void HideVitalWindows(); void ShowVitalWindows(); -void ReInitAllWindows(); +/** + * Re-initialize all windows. + * @param zoom_changed Set if windows are being re-initialized due to a zoom level changed. + */ +void ReInitAllWindows(bool zoom_changed); void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, byte widget_index); void SetWindowDirty(WindowClass cls, WindowNumber number); diff --git a/src/window_gui.h b/src/window_gui.h index 41694153ed..dd725b21c6 100644 --- a/src/window_gui.h +++ b/src/window_gui.h @@ -140,7 +140,7 @@ enum WidgetDrawDistances { /* widget.cpp */ void DrawFrameRect(int left, int top, int right, int bottom, Colours colour, FrameFlags flags); -void DrawCaption(const Rect &r, Colours colour, Owner owner, StringID str, const NWidgetCore *widget, const Window *window); +void DrawCaption(const Rect &r, Colours colour, Owner owner, TextColour text_colour, StringID str, StringAlignment align, const NWidgetCore *widget, const Window *window); /* window.cpp */ extern Window *_z_front_window; @@ -268,6 +268,7 @@ enum TooltipCloseCondition { TCC_RIGHT_CLICK, TCC_HOVER, TCC_NONE, + TCC_EXIT_VIEWPORT, }; /** @@ -813,6 +814,68 @@ public: * @pre this->IsNewGRFInspectable() */ virtual void ShowNewGRFInspectWindow() const { NOT_REACHED(); } + + /** + * Iterator to iterate all valid Windows + * @tparam T Type of the class/struct that is going to be iterated + * @tparam Tfront Wether we iterate from front + */ + template + struct WindowIterator { + typedef T value_type; + typedef T *pointer; + typedef T &reference; + typedef size_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit WindowIterator(T *start) : w(start) + { + this->Validate(); + } + + bool operator==(const WindowIterator &other) const { return this->w == other.w; } + bool operator!=(const WindowIterator &other) const { return !(*this == other); } + T * operator*() const { return this->w; } + WindowIterator & operator++() { this->Next(); this->Validate(); return *this; } + + private: + T *w; + void Validate() { while (this->w != nullptr && this->w->window_class == WC_INVALID) this->Next(); } + void Next() { if (this->w != nullptr) this->w = Tfront ? this->w->z_back : this->w->z_front; } + }; + + /** + * Iterable ensemble of all valid Windows + * @tparam T Type of the class/struct that is going to be iterated + * @tparam Tfront Wether we iterate from front + */ + template + struct Iterate { + Iterate(T *from) : from(from) {} + WindowIterator begin() { return WindowIterator(this->from); } + WindowIterator end() { return WindowIterator(nullptr); } + bool empty() { return this->begin() == this->end(); } + private: + T *from; + }; + + /** + * Returns an iterable ensemble of all valid Window from back to front + * @tparam T Type of the class/struct that is going to be iterated + * @param from index of the first Window to consider + * @return an iterable ensemble of all valid Window + */ + template + static Iterate IterateFromBack(T *from = _z_back_window) { return Iterate(from); } + + /** + * Returns an iterable ensemble of all valid Window from front to back + * @tparam T Type of the class/struct that is going to be iterated + * @param from index of the first Window to consider + * @return an iterable ensemble of all valid Window + */ + template + static Iterate IterateFromFront(T *from = _z_front_window) { return Iterate(from); } }; /** @@ -893,12 +956,6 @@ void GuiShowTooltips(Window *parent, StringID str, uint paramcount = 0, const ui /* widget.cpp */ int GetWidgetFromPos(const Window *w, int x, int y); -/** Iterate over all windows */ -#define FOR_ALL_WINDOWS_FROM_BACK_FROM(w, start) for (w = start; w != nullptr; w = w->z_front) if (w->window_class != WC_INVALID) -#define FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, start) for (w = start; w != nullptr; w = w->z_back) if (w->window_class != WC_INVALID) -#define FOR_ALL_WINDOWS_FROM_BACK(w) FOR_ALL_WINDOWS_FROM_BACK_FROM(w, _z_back_window) -#define FOR_ALL_WINDOWS_FROM_FRONT(w) FOR_ALL_WINDOWS_FROM_FRONT_FROM(w, _z_front_window) - extern Point _cursorpos_drag_start; extern int _scrollbar_start_pos; diff --git a/src/window_type.h b/src/window_type.h index ff2773417b..339baed3c3 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -484,12 +484,6 @@ enum WindowClass { */ WC_CLIENT_LIST, - /** - * Popup for the client list; %Window numbers: - * - #ClientID = #ClientListPopupWidgets - */ - WC_CLIENT_LIST_POPUP, - /** * Network status window; %Window numbers: * - #WN_NETWORK_STATUS_WINDOW_JOIN = #NetworkJoinStatusWidgets @@ -716,9 +710,11 @@ enum WindowClass { /** Data value for #Window::OnInvalidateData() of windows with class #WC_GAME_OPTIONS. */ enum GameOptionsInvalidationData { GOID_DEFAULT = 0, - GOID_NEWGRF_RESCANNED, ///< NewGRFs were just rescanned. - GOID_NEWGRF_LIST_EDITED, ///< List of active NewGRFs is being edited. - GOID_NEWGRF_PRESET_LOADED, ///< A NewGRF preset was picked. + GOID_NEWGRF_RESCANNED, ///< NewGRFs were just rescanned. + GOID_NEWGRF_CURRENT_LOADED, ///< The current list of active NewGRF has been loaded. + GOID_NEWGRF_LIST_EDITED, ///< List of active NewGRFs is being edited. + GOID_NEWGRF_CHANGES_MADE, ///< Changes have been made to a given NewGRF either through the palette or its parameters. + GOID_NEWGRF_CHANGES_APPLIED, ///< The active NewGRF list changes have been applied. }; struct Window;