Update to 1.11.2

This commit is contained in:
dP
2021-05-03 22:10:57 +03:00
parent 5881c752f5
commit ac7d3eba75
103 changed files with 1631 additions and 942 deletions

View File

@@ -1,32 +1,23 @@
1.11.1 (2021-04-18)
1.11.2 (2021-05-03)
------------------------------------------------------------------------
Feature: Toggle to enable/disable vsync (#8997)
Feature: Volume controls in the Game Options window, and better defaults (#8943)
Add: Hotkey to focus object and rail filters (#8908)
Add: Better plural support for Romanian (#8936)
Change: Improve layout and spacing of several windows at different GUI scales (#9041, #9042, #9044, #9050)
Change: [Win32] Use user UI language setting for initial language selection (#8974)
Change: Make effect volume scale more intuitively (#8945, #8950)
Change: Improve padding of Object & Rail station windows (#8929)
Fix #6322: [Script] Crash when script allocates too much memory, now kills script instead (#9047)
Fix #7513: [Script] Crash on garbage collection with misbehaving script (#9040)
Fix #9028: [OpenGL] Crash when changing max sprite zoom level (#9032)
Fix #8874: show a warning when a NewGRF scan is requested multiple times (#9022)
Fix: Desync when GS unlocks railtype with wagon unlock (#9021)
Fix #9015: [Win32] Crash on running "pwd" command in the console (#9016)
Fix #9008: Validate starting year given on the command line (-t) (#9014)
Fix #8878: [Network] Slow DNS queries could block the server and disconnect clients (#9013)
Fix: Improve validation of OpenGL video driver to avoid crashes (#9007)
Fix: Credits scrolled too slowly with larger font sizes (#8994)
Fix #8977: Crash when altering max sprite resolution (#8993)
Fix #8956: Industry disaster news messages showed the wrong location (#8992)
Fix: [Win32] Font glyphs of certain widths had broken rendering (#8990)
Fix #8930: [Win32] Duplicate text input issue for systems using IME (#8976)
Fix: [Network] Potential stale client entries in client list (#8959)
Fix: Graphical issues when dragging measurement tooltips (#8951)
Fix: [Fluidsynth] Use provided default soundfont if available (#8948, #8953)
Fix #8935: [macOS] Crash on save (#8944)
Fix #8922: Crash when selling shared vehicles with shared vehicle window open (#8926)
Fix: Compiling on armhf (Raspberry Pi) (#8924)
Change: [Win32] Limit hardware accelerated video driver to OpenGL 3.2 or higher (#9077)
Change: More improvements to the GUI at different scales (#9075, #9102, #9107, #9133, #9174, #9183)
Fix: Query windows could be partially drawn (#9184)
Fix #9113: Crash when removing an airport that exists in an aircraft's orders (#9182)
Fix #9117: [Fluidsynth] Hang when changing song (#9181)
Fix: String validation could leave invalid UTF-8 encoded strings (#9096)
Fix: [Network] Out-of-bounds memory access with modified servers sending too short password salts (#9176)
Fix: Crash when extra viewport with zero height has sign in view (#9175)
Fix #9147: Crash when taking screenshots (#9169)
Fix #6598: [Network] Prevent crashes when (re)joining network game by falling back to main menu first (#9163)
Fix #9152: Screenshot success popup window was treated as an error (#9159)
Fix: Fast-forward stuttering when vsync is enabled (#9140)
Fix: [Network, Win32] Network errors were handled badly (#9116)
Fix: [Network] Savegame transfer could stall in rare cases (#9106)
Fix #9097: [NewGRF] Cargo initial payment variable was being truncated (#9098)
Fix: [NewGRF] Industry variable 66 and object variable 46 erroneously truncated the distance (#9088)
Fix: [NewGRF] Industry variables 65 and 66 ignored the parameter, and always used the north tile (#9088)
Fix: Do not include regression test AI in bundle (#9068, #9164)
Fix #9062: [Win32] Version in executable was not set to current release version (#9066, #9154)

View File

@@ -143,7 +143,7 @@ jobs:
- name: Test
run: |
cd build
ctest -j $(nproc)
ctest -j $(nproc) --timeout 120
macos:
name: Mac OS
@@ -224,7 +224,7 @@ jobs:
- name: Test
run: |
cd build
ctest -j $(sysctl -n hw.logicalcpu)
ctest -j $(sysctl -n hw.logicalcpu) --timeout 120
windows:
name: Windows
@@ -314,4 +314,4 @@ jobs:
shell: bash
run: |
cd ${GITHUB_WORKSPACE}/build
ctest
ctest --timeout 120

View File

@@ -1 +1 @@
1.11.1 20210418 0 0be22efffc3c14db08baf5e58c448b5d074f4427 1 1 2021
1.11.2 20210503 0 672f285218c6817784d86f737987b75db4bc78fc 1 1 2021

View File

@@ -1 +1 @@
2021-04-18 21:11 UTC
2021-05-03 18:41 UTC

View File

@@ -1 +1 @@
1.11.1
1.11.2

View File

@@ -4,7 +4,9 @@ if(NOT BINARY_NAME)
set(BINARY_NAME openttd)
endif()
project(${BINARY_NAME})
project(${BINARY_NAME}
VERSION 1.11.2
)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
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.")
@@ -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}
-P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
BYPRODUCTS ${GENERATED_SOURCE_FILES}

View File

@@ -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

View File

@@ -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.

View File

@@ -1,3 +1,26 @@
1.11.2 (2021-05-03)
------------------------------------------------------------------------
Change: [Win32] Limit hardware accelerated video driver to OpenGL 3.2 or higher (#9077)
Change: More improvements to the GUI at different scales (#9075, #9102, #9107, #9133, #9174, #9183)
Fix: Query windows could be partially drawn (#9184)
Fix #9113: Crash when removing an airport that exists in an aircraft's orders (#9182)
Fix #9117: [Fluidsynth] Hang when changing song (#9181)
Fix: String validation could leave invalid UTF-8 encoded strings (#9096)
Fix: [Network] Out-of-bounds memory access with modified servers sending too short password salts (#9176)
Fix: Crash when extra viewport with zero height has sign in view (#9175)
Fix #9147: Crash when taking screenshots (#9169)
Fix #6598: [Network] Prevent crashes when (re)joining network game by falling back to main menu first (#9163)
Fix #9152: Screenshot success popup window was treated as an error (#9159)
Fix: Fast-forward stuttering when vsync is enabled (#9140)
Fix: [Network, Win32] Network errors were handled badly (#9116)
Fix: [Network] Savegame transfer could stall in rare cases (#9106)
Fix #9097: [NewGRF] Cargo initial payment variable was being truncated (#9098)
Fix: [NewGRF] Industry variable 66 and object variable 46 erroneously truncated the distance (#9088)
Fix: [NewGRF] Industry variables 65 and 66 ignored the parameter, and always used the north tile (#9088)
Fix: Do not include regression test AI in bundle (#9068, #9164)
Fix #9062: [Win32] Version in executable was not set to current release version (#9066, #9154)
1.11.1 (2021-04-18)
------------------------------------------------------------------------
Feature: Toggle to enable/disable vsync (#8997)

View File

@@ -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"
)

View File

@@ -30,7 +30,9 @@ install(DIRECTORY
${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

View File

@@ -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})

View File

@@ -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.
#

View File

@@ -7,6 +7,7 @@ class Regression extends AIInfo {
function GetAPIVersion() { return "1.11"; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; }
function UseAsRandomAI() { return false; }
}
RegisterAI(Regression());

View File

@@ -7,6 +7,7 @@ class StationList extends AIInfo {
function GetAPIVersion() { return "1.11"; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "StationList"; }
function UseAsRandomAI() { return false; }
}
RegisterAI(StationList());

View File

@@ -81,7 +81,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.
@@ -229,7 +229,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];
@@ -274,7 +274,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: {
@@ -475,7 +475,7 @@ public:
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(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.

View File

@@ -274,7 +274,7 @@ template <class Tbase_set>
return p;
}
#include "network/network_content.h"
#include "network/core/tcp_content_type.h"
template <class Tbase_set> const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const Tbase_set *s)
{

View File

@@ -1055,7 +1055,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.
@@ -1115,7 +1115,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);
@@ -1553,7 +1553,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: {
@@ -1620,12 +1620,12 @@ struct BuildVehicleWindow : Window {
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(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;
}
}

View File

@@ -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).

View File

@@ -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"
@@ -893,7 +894,7 @@ DEF_CONSOLE_CMD(ConNetworkReconnect)
/* 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);
NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), playas);
NetworkClientConnectGame(_settings_client.network.last_host, _settings_client.network.last_port, playas);
return true;
}
@@ -907,7 +908,6 @@ 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;
@@ -935,7 +935,7 @@ DEF_CONSOLE_CMD(ConNetworkConnect)
IConsolePrintF(CC_DEFAULT, " port: %s", port);
}
NetworkClientConnectGame(NetworkAddress(ip, rport), join_as);
NetworkClientConnectGame(ip, rport, join_as);
return true;
}
@@ -1439,7 +1439,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) {

View File

@@ -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. */

View File

@@ -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();
}
/**
* 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;
}

View File

@@ -1006,6 +1006,8 @@ 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
@@ -2040,10 +2042,10 @@ 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

View File

@@ -4467,7 +4467,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
@@ -4500,7 +4500,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...

View File

@@ -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,7 @@ 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}インターフェイス上の単位サイズを指定します
@@ -992,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}使用するグラフィックセットを選択します
@@ -1096,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 :寛容
@@ -1177,11 +1196,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}
@@ -1319,6 +1341,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 :特になだらか
@@ -1357,6 +1381,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}
@@ -1427,7 +1452,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 :ステータスバーにニュースが流れたとき効果音を鳴らすかどうかを設定します
@@ -1476,6 +1503,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 :次の点検が必要と判断される条件を設定します。無効の場合は、前の点検から指定の期間が経過した際に点検が必要と判断されます。有効にすると、輸送機器の最大信頼度が指定の値より落ち込んだ場合に次の点検が必要と判断されます
@@ -1535,7 +1564,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年経過していない場合は取引できません
@@ -1586,6 +1617,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 :画面上のメインツールバーの位置を決めます
@@ -1603,6 +1635,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倍
@@ -1746,6 +1779,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}
@@ -1953,6 +1987,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}サーバーを追加
@@ -2137,6 +2172,7 @@ 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}パスワード入力時間切れです
@@ -2178,6 +2214,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 :クライアントに接続中
@@ -2195,6 +2232,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}コンテンツをダウンロード中
@@ -2270,6 +2308,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}透過表示設定
@@ -2289,6 +2329,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}未使用(運送過多)
@@ -2415,7 +2456,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
@@ -2504,7 +2547,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)
@@ -2564,6 +2609,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}に関わる産業チェーン
@@ -2710,22 +2756,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
@@ -2751,8 +2814,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}保存名を入力
@@ -2764,6 +2829,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}地形種類:
@@ -2790,6 +2863,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
@@ -2864,6 +2940,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 :なし
@@ -3044,6 +3121,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}可能な活動:
@@ -3072,6 +3150,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}
@@ -3274,6 +3353,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}社長の顔を変更します
@@ -3291,6 +3371,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}を一括代済し、この会社を吸収合併しますか?
@@ -3299,6 +3380,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}停留施設数:
@@ -3309,8 +3391,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 :なし
@@ -3323,6 +3408,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}
@@ -3393,6 +3479,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 :新規機関車(非電化)
@@ -3401,6 +3488,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 :新規列車
@@ -3409,6 +3497,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}
@@ -3432,6 +3521,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+クリックでその車両種の表示/非表示を切り替えます
@@ -3443,12 +3533,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}名称を変更
@@ -3564,6 +3657,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 :船舶
@@ -3611,6 +3705,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}
@@ -3620,6 +3715,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+クリックすると点検後、再出庫します
@@ -3651,6 +3747,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}現在の航空機のアクション-クリックして航空機を停止/開始します
@@ -3693,6 +3791,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}
@@ -3878,6 +3978,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 :(自動)
@@ -4056,7 +4157,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} パラメータ
@@ -4116,6 +4221,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}このゲームは路面電車に対応していないバージョンで保存されましたので、すべての路面電車が削除されました。
@@ -4196,6 +4302,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%購入できません
@@ -4323,6 +4430,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}不可能な線路の組み合わせです
@@ -4331,6 +4439,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}ここから線路を撤去できません
@@ -4351,6 +4460,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}ここには運河を建設できません
@@ -4902,6 +5014,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}中継駅

View File

@@ -1262,7 +1262,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 :이 설정을 켜면. 회사의 재정 상태를 확인하기 쉽도록 매년 말에 재정 창이 자동으로 뜹니다.
@@ -1529,7 +1529,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 :게임 스크립트가 한 단계에서 계산할 수 있는 최대 계산 횟수를 설정합니다.
@@ -1804,8 +1804,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 시스템
@@ -2112,7 +2112,7 @@ STR_NETWORK_LANG_LATVIAN :라트비아어
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}
@@ -2178,11 +2178,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}회사 비밀번호 설정
@@ -2274,7 +2274,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}서버가 재시작되고 있습니다...{}기다려주세요...
@@ -3128,7 +3128,7 @@ 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_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에 의한 문제로 보입니다. 게임이 비동기화 또는 충돌을 일으킬 수 있습니다.

View File

@@ -2039,7 +2039,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

View File

@@ -390,7 +390,7 @@ STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :{BLACK}Если
STR_BUTTON_DEFAULT :{BLACK}По умолчанию
STR_BUTTON_CANCEL :{BLACK}Отмена
STR_BUTTON_OK :{BLACK}OK
STR_WARNING_PASSWORD_SECURITY :{YELLOW}Внимание: администраторы сервера могут увидеть ваш пароль.
STR_WARNING_PASSWORD_SECURITY :{YELLOW}Внимание: администраторы сервера могут увидеть текст, введённый в это поле.
# On screen keyboard window
STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ .
@@ -924,7 +924,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_PAUSED_LINK_GRAPH :{ORANGE}* * ПАУЗА (ожидает обновления графа распределения) * *
STR_STATUSBAR_AUTOSAVE :{RED}АВТОСОХРАНЕНИЕ
STR_STATUSBAR_SAVING_GAME :{RED}* * СОХРАНЕНИЕ ИГРЫ * *
@@ -1148,11 +1148,11 @@ 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_VIDEO_VSYNC_TOOLTIP :{BLACK}Включить/выключить вертикальную синхронизацию. После этого игру потребуется перезапустить. Работает только при включённом аппаратном ускорении.
STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}Размер элементов интерфейса
STR_GAME_OPTIONS_GUI_ZOOM_DROPDOWN_TOOLTIP :{BLACK}Выберите размер элементов интерфейса
@@ -2155,7 +2155,7 @@ STR_NETWORK_SERVER_LIST_DATE_CAPTION :{BLACK}Дата
STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP :{BLACK}Текущая дата
STR_NETWORK_SERVER_LIST_YEARS_CAPTION :{BLACK}Года
STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP :{BLACK}Количество лет{}в игре
STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Язык, версия сервера и т.п.
STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP :{BLACK}Язык, версия сервера и{NBSP}т.{NBSP}п.
STR_NETWORK_SERVER_LIST_CLICK_GAME_TO_SELECT :{BLACK}Выберите игру из списка
STR_NETWORK_SERVER_LIST_LAST_JOINED_SERVER :{BLACK}Последний сервер, к которому вы подключались:
@@ -2170,20 +2170,20 @@ STR_NETWORK_SERVER_LIST_SERVER_VERSION :{SILVER}Вер
STR_NETWORK_SERVER_LIST_SERVER_ADDRESS :{SILVER}Адрес сервера: {WHITE}{STRING}
STR_NETWORK_SERVER_LIST_START_DATE :{SILVER}Дата начала: {WHITE}{DATE_SHORT}
STR_NETWORK_SERVER_LIST_CURRENT_DATE :{SILVER}Текущая дата: {WHITE}{DATE_SHORT}
STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Защищено паролем!
STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}СЕРВЕР ОТКЛЮЧЕН
STR_NETWORK_SERVER_LIST_PASSWORD :{SILVER}Защищён паролем!
STR_NETWORK_SERVER_LIST_SERVER_OFFLINE :{SILVER}СЕРВЕР ОТКЛЮЧЁН
STR_NETWORK_SERVER_LIST_SERVER_FULL :{SILVER}СЕРВЕР ЗАПОЛНЕН
STR_NETWORK_SERVER_LIST_VERSION_MISMATCH :{SILVER}ВЕРСИЯ НЕ ПОДХОДИТ
STR_NETWORK_SERVER_LIST_GRF_MISMATCH :{SILVER}НЕ СОВПАДАЕТ НАБОР NEWGRF
STR_NETWORK_SERVER_LIST_JOIN_GAME :{BLACK}Присоединиться
STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Обновить сервер
STR_NETWORK_SERVER_LIST_REFRESH :{BLACK}Обновить информацию
STR_NETWORK_SERVER_LIST_REFRESH_TOOLTIP :{BLACK}Обновить информацию о сервере
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET :{BLACK}Искать в интернете
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK} Искать в Интернете общедоступные серверы
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Искать LAN
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK} Поиск серверов в локальной сети
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_INTERNET_TOOLTIP :{BLACK}Поиск общедоступных серверов в интернете
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN :{BLACK}Искать в ЛВС
STR_NETWORK_SERVER_LIST_SEARCH_SERVER_LAN_TOOLTIP :{BLACK}Поиск серверов в локальной сети
STR_NETWORK_SERVER_LIST_ADD_SERVER :{BLACK}Добавить сервер
STR_NETWORK_SERVER_LIST_ADD_SERVER_TOOLTIP :{BLACK}Добавить сервер в список, который будет автоматически проверяться на идущие игры
STR_NETWORK_SERVER_LIST_START_SERVER :{BLACK}Запуск сервера
@@ -2206,13 +2206,13 @@ 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}Выбор максимального числа клиентов. Не все места должны быть заняты
STR_NETWORK_START_SERVER_NUMBER_OF_CLIENTS_TOOLTIP :{BLACK}Выбор максимального числа клиентов. Не все места обязательно должны быть заняты.
STR_NETWORK_START_SERVER_COMPANIES_SELECT :{BLACK}{NUM} компани{P я и й}
STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES :{BLACK}Макс. количество компаний:
STR_NETWORK_START_SERVER_NUMBER_OF_COMPANIES_TOOLTIP :{BLACK}Ограничить максимальное количество компаний на сервере
STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} наблюдател{P ь я ей}
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Макс. количество наблюдателей:
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ограничить максимальное количество наблюдателей на сервере
STR_NETWORK_START_SERVER_SPECTATORS_SELECT :{BLACK}{NUM} зрител{P ь я ей}
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS :{BLACK}Макс. количество зрителей:
STR_NETWORK_START_SERVER_NUMBER_OF_SPECTATORS_TOOLTIP :{BLACK}Ограничить максимальное количество зрителей на сервере
STR_NETWORK_START_SERVER_LANGUAGE_SPOKEN :{BLACK}Язык общения:
STR_NETWORK_START_SERVER_LANGUAGE_TOOLTIP :{BLACK}Другие игроки будут знать, на каком языке общаются на сервере
@@ -2262,7 +2262,7 @@ STR_NETWORK_LANG_LATVIAN :Латвийс
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}
@@ -2321,7 +2321,7 @@ STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT :Личное с
STR_NETWORK_SERVER :Сервер
STR_NETWORK_CLIENT :Клиент
STR_NETWORK_SPECTATORS :Наблюдатели
STR_NETWORK_SPECTATORS :Зрители
# Network set password
STR_COMPANY_PASSWORD_CANCEL :{BLACK}Не сохранять пароль
@@ -2365,8 +2365,8 @@ STR_NETWORK_ERROR_SERVER_ERROR :{WHITE}Прои
STR_NETWORK_ERROR_WRONG_REVISION :{WHITE}Версия этого клиента не совместима с версией сервера
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_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}Вы посылали на сервер слишком много команд
@@ -2415,13 +2415,13 @@ STR_NETWORK_SERVER_MESSAGE_GAME_REASON_NOT_ENOUGH_PLAYERS :количес
STR_NETWORK_SERVER_MESSAGE_GAME_REASON_CONNECTING_CLIENTS :подключение клиентов
STR_NETWORK_SERVER_MESSAGE_GAME_REASON_MANUAL :вручную
STR_NETWORK_SERVER_MESSAGE_GAME_REASON_GAME_SCRIPT :игровой скрипт
STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :ожидает обновления графы ссылок
STR_NETWORK_SERVER_MESSAGE_GAME_REASON_LINK_GRAPH :ожидает обновления графа распределения
############ End of leave-in-this-order
STR_NETWORK_MESSAGE_CLIENT_LEAVING :покинул
STR_NETWORK_MESSAGE_CLIENT_LEAVING :отключение
STR_NETWORK_MESSAGE_CLIENT_JOINED :*** {STRING} подключился к игре
STR_NETWORK_MESSAGE_CLIENT_JOINED_ID :*** {STRING} подключился к игре (клиент #{2:NUM})
STR_NETWORK_MESSAGE_CLIENT_COMPANY_JOIN :*** {STRING} подключился к компании #{2:NUM}
STR_NETWORK_MESSAGE_CLIENT_COMPANY_SPECTATE :*** {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}
@@ -3305,7 +3305,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}» после постройки отличается от сведений в списке покупки, что может помешать функции автообновления/автозамены корректно произвести переоборудование.
@@ -5372,7 +5372,7 @@ STR_DEFAULT_SIGN_NAME :Табличк
STR_COMPANY_SOMEONE :кто-то
STR_SAVEGAME_NAME_DEFAULT :{COMPANY}, {STRING}
STR_SAVEGAME_NAME_SPECTATOR :Наблюдатель, {1:STRING}
STR_SAVEGAME_NAME_SPECTATOR :Зритель, {1:STRING}
# Viewport strings
STR_VIEWPORT_TOWN_POP :{WHITE}{TOWN} ({COMMA})

View File

@@ -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,8 @@ 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}选择使用的界面元素大小
@@ -1026,6 +1029,8 @@ 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}基础图形组
@@ -1206,8 +1211,10 @@ STR_CONFIG_SETTING_CITY_APPROVAL :地区政府对
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_TOO_HIGH_MOUNTAIN :{WHITE}您不能把最高地面高度设为这个值,因为地图上至少有一座山丘的高度比这个值还大
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}
@@ -1352,6 +1359,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}
@@ -1471,9 +1479,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_FAST_FORWARD_SPEED_LIMIT_ZERO :无限制(在您计算机允许的范围内)
STR_CONFIG_SETTING_SOUND_TICKER :产业新闻: {STRING}
STR_CONFIG_SETTING_SOUND_TICKER_HELPTEXT :每月初产业新闻音效
@@ -1643,7 +1653,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 :主工具栏在屏幕上方的位置
@@ -1661,6 +1674,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 :普通
@@ -1713,6 +1728,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 :在界面上以所选择的单位表示运输工具的功率
@@ -2578,8 +2594,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}生成土地
@@ -2630,7 +2650,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}你确定要生成大量随机工业吗?
@@ -2662,6 +2682,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}
@@ -2886,8 +2907,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% 沙漠覆盖率
@@ -2918,6 +2942,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}改变游戏开始的日期
@@ -3136,6 +3161,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}前往上个标记
@@ -3196,13 +3222,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
@@ -3220,10 +3246,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 :取消
@@ -3432,6 +3458,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}) 吗?
@@ -3831,7 +3858,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}装载/卸货
@@ -4059,6 +4088,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 :(自动)
@@ -4303,6 +4333,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}游戏已保存为无电车版。所有电车已被去除。
@@ -4330,6 +4361,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}屏幕截图失败!
@@ -4510,6 +4542,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}不可能的轨道组合

View File

@@ -4476,14 +4476,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ť...
@@ -4506,10 +4506,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
@@ -4525,13 +4525,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á
@@ -4579,8 +4579,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...
@@ -4620,7 +4620,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á...
@@ -4632,7 +4632,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ť...
@@ -4646,15 +4646,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š postav na vode
STR_ERROR_CAN_T_BUILD_ON_SEA :{WHITE}... nemôžeš postav 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
@@ -4662,7 +4662,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
@@ -4780,7 +4780,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

View File

@@ -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
@@ -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
@@ -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
@@ -1904,7 +1904,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
@@ -2359,15 +2359,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
@@ -3069,7 +3069,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)
@@ -3173,7 +3173,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
@@ -3191,7 +3191,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
@@ -3280,7 +3280,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}
@@ -3296,7 +3296,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}
@@ -3358,7 +3358,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
@@ -3373,7 +3373,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
@@ -3826,15 +3826,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
@@ -3846,10 +3846,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
@@ -3919,8 +3919,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

View File

@@ -1007,6 +1007,8 @@ 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

View File

@@ -1006,6 +1006,8 @@ 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
@@ -3884,7 +3886,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

View File

@@ -1163,12 +1163,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()
@@ -1176,6 +1173,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) {

View File

@@ -163,14 +163,21 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
void MusicDriver_FluidSynth::StopSong()
{
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
{
std::lock_guard<std::mutex> 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<std::mutex> lock{ _midi.synth_mutex };
delete_fluid_player(_midi.player);
fluid_synth_system_reset(_midi.synth);
fluid_synth_all_sounds_off(_midi.synth, -1);

View File

@@ -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

View File

@@ -316,7 +316,7 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
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;
}
@@ -326,12 +326,12 @@ static SOCKET ConnectLoopProc(addrinfo *runp)
#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)
if (err != 0 && !NetworkError::GetLast().IsConnectInProgress())
#else
if (err != 0)
#endif
{
DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, strerror(errno));
DEBUG(net, 1, "[%s] could not connect %s socket: %s", type, family, NetworkError::GetLast().AsString());
closesocket(sock);
return INVALID_SOCKET;
}
@@ -369,7 +369,7 @@ static SOCKET ListenLoopProc(addrinfo *runp)
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, NetworkError::GetLast().AsString());
return INVALID_SOCKET;
}
@@ -380,24 +380,24 @@ static SOCKET ListenLoopProc(addrinfo *runp)
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, 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, 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, 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, NetworkError::GetLast().AsString());
closesocket(sock);
return INVALID_SOCKET;
}

View File

@@ -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();
}
}

View File

@@ -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);
};

View File

@@ -0,0 +1,326 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* @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;
}
/**
* 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.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));
}
/**
* 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 (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 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));
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;
}
}
/**
* 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();
}
}

View File

@@ -0,0 +1,107 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* @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 {
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
};
extern NetworkServerGameInfo _network_game_info;
const char *GetNetworkRevisionString();
bool IsNetworkCompatibleVersion(const char *other);
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 */

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
/**
* @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 <mutex>
#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<std::mutex> 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);
}

View File

@@ -14,6 +14,28 @@
#ifndef NETWORK_CORE_OS_ABSTRACTION_H
#define NETWORK_CORE_OS_ABSTRACTION_H
#include <string>
/**
* 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 +45,6 @@
#include <ws2tcpip.h>
#include <windows.h>
#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 +68,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 +116,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 <types.h>
@@ -173,41 +188,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.

View File

@@ -105,11 +105,11 @@ SendPacketsState NetworkTCPSocketHandler::SendPackets(bool closing_down)
while (p != nullptr) {
res = send(this->sock, (const char*)p->buffer + p->pos, p->size - p->pos, 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;
@@ -160,10 +160,10 @@ Packet *NetworkTCPSocketHandler::ReceivePacket()
/* Read the size of the packet */
res = recv(this->sock, (char*)p->buffer + p->pos, sizeof(PacketSize) - p->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());
this->CloseConnection();
return nullptr;
}
@@ -191,10 +191,10 @@ Packet *NetworkTCPSocketHandler::ReceivePacket()
while (p->pos < p->size) {
res = recv(this->sock, (char*)p->buffer + p->pos, p->size - p->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());
this->CloseConnection();
return nullptr;
}

View File

@@ -16,81 +16,7 @@
#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 {

View File

@@ -0,0 +1,90 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/**
* @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;
#ifndef OPENTTD_MSU
const char *GetTextfile(TextfileType type) const;
#endif /* OPENTTD_MSU */
};
#endif /* NETWORK_CORE_TCP_CONTENT_TYPE_H */

View File

@@ -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); }

View File

@@ -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.

View File

@@ -13,6 +13,7 @@
#include "../../debug.h"
#include "../../rev.h"
#include "../network_func.h"
#include "game_info.h"
#include "tcp_http.h"
@@ -230,10 +231,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 */

View File

@@ -64,7 +64,7 @@ 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());
DEBUG(net, 0, "send failed with error %s", NetworkError::GetLast().AsString());
}
closesocket(s);
break;
@@ -81,7 +81,7 @@ public:
p.PrepareToSend();
if (send(s, (const char*)p.buffer, p.size, 0) < 0) {
DEBUG(net, 0, "send failed with error %d", GET_LAST_ERROR());
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;
}

View File

@@ -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,7 +95,7 @@ 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());
}
}
@@ -103,7 +104,7 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a
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;
}
@@ -149,143 +150,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

View File

@@ -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 */

View File

@@ -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.
@@ -177,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;
@@ -278,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);
@@ -572,9 +574,10 @@ public:
}
};
/* 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 */
/**
* Query a server to fetch his game-info.
* @param address the address to query.
*/
void NetworkTCPQueryServer(NetworkAddress address)
{
if (!_network_available) return;
@@ -644,7 +647,7 @@ public:
void OnFailure() override
{
NetworkError(STR_NETWORK_ERROR_NOCONNECTION);
ShowNetworkError(STR_NETWORK_ERROR_NOCONNECTION);
}
void OnConnect(SOCKET s) override
@@ -658,25 +661,45 @@ public:
/* 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)
void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, const char *join_server_password, const char *join_company_password)
{
if (!_network_available) return;
if (address.GetPort() == 0) return;
if (port == 0) return;
strecpy(_settings_client.network.last_host, address.GetHostname(), lastof(_settings_client.network.last_host));
_settings_client.network.last_port = address.GetPort();
strecpy(_settings_client.network.last_host, hostname, lastof(_settings_client.network.last_host));
_settings_client.network.last_port = port;
_network_join_as = 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;
}
}
/**
* 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();
_network_join_status = NETWORK_JOIN_STATUS_CONNECTING;
ShowJoinStatusWindow();
new TCPClientConnecter(address);
new TCPClientConnecter(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port));
}
static void NetworkInitGameInfo()
@@ -1027,12 +1050,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 char *hostname, uint16 port)
{
extern SOCKET _debug_socket; // Comes from debug.c
DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", address.GetHostname(), address.GetPort());
DEBUG(net, 0, "Redirecting DEBUG() to %s:%d", hostname, port);
NetworkAddress address(hostname, port);
SOCKET s = address.Connect();
if (s == INVALID_SOCKET) {
DEBUG(net, 0, "Failed to open socket for redirection DEBUG()");
@@ -1077,79 +1101,6 @@ 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" {

View File

@@ -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"

View File

@@ -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<NetworkClientInfo, ClientIndex, 8, MAX_CLIENT_SLOTS, PT_NCLIENT> NetworkClientInfoPool;

View File

@@ -23,6 +23,7 @@
#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"
@@ -280,7 +281,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);
@@ -723,7 +724,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);

View File

@@ -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;
@@ -44,12 +43,13 @@ 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 NetworkStartDebugLog(const char *hostname, uint16 port);
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);
void NetworkClientConnectGame(const char *hostname, uint16 port, CompanyID join_as, 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);

View File

@@ -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) */

View File

@@ -1536,15 +1536,15 @@ 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(_settings_client.network.last_host, _settings_client.network.last_port, 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(_settings_client.network.last_host, _settings_client.network.last_port, 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(_settings_client.network.last_host, _settings_client.network.last_port, COMPANY_SPECTATOR);
break;
case WID_NL_REFRESH: // Refresh

View File

@@ -11,6 +11,7 @@
#define NETWORK_GUI_H
#include "../company_type.h"
#include "../date_type.h"
#include "../economy_type.h"
#include "../window_type.h"
#include "network_type.h"

View File

@@ -135,8 +135,6 @@ void NetworkAddServer(const char *b);
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.
@@ -155,7 +153,7 @@ 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);

View File

@@ -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"
@@ -363,6 +364,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()
{
@@ -488,7 +503,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);
@@ -605,7 +620,7 @@ 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
static uint16 sent_packets; // How many packets we did send successfully last time
if (this->status < STATUS_AUTHORIZED) {
/* Illegal call, return error and ignore the packet */
@@ -665,8 +680,10 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
return NETWORK_RECV_STATUS_CONN_LOST;
case SPS_ALL_SENT:
/* All are sent, increase the sent_packets */
if (has_packets) sent_packets *= 2;
/* All are sent, increase the sent_packets but do not overflow! */
if (has_packets && sent_packets < std::numeric_limits<decltype(sent_packets)>::max() / 2) {
sent_packets *= 2;
}
break;
case SPS_PARTLY_SENT:
@@ -875,6 +892,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();

View File

@@ -24,6 +24,7 @@ extern NetworkClientSocketPool _networkclientsocket_pool;
class ServerNetworkGameSocketHandler : public NetworkClientSocketPool::PoolItem<&_networkclientsocket_pool>, public NetworkGameSocketHandler, public TCPListenHandler<ServerNetworkGameSocketHandler, PACKET_SERVER_FULL, PACKET_SERVER_BANNED> {
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();

View File

@@ -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;

View File

@@ -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"
@@ -171,31 +172,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);
@@ -286,7 +266,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);
@@ -313,7 +293,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);
}
@@ -328,7 +308,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() {}
};
@@ -346,7 +325,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd
item = NetworkGameListAddItem(*client_addr);
ClearGRFConfigList(&item->info.grfconfig);
this->ReceiveNetworkGameInfo(p, &item->info);
DeserializeNetworkGameInfo(p, &item->info);
item->info.compatible = true;
{
@@ -375,7 +354,7 @@ 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);
@@ -449,7 +428,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
@@ -466,25 +445,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)
{

View File

@@ -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"

View File

@@ -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 */

View File

@@ -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;

View File

@@ -32,6 +32,7 @@
#include "screenshot.h"
#include "network/network.h"
#include "network/network_func.h"
#include "network/core/game_info.h"
#include "ai/ai.hpp"
#include "ai/ai_config.hpp"
#include "settings_func.h"
@@ -495,7 +496,7 @@ struct AfterNewGRFScan : NewGRFScanCallback {
LoadIntroGame();
_switch_mode = SM_NONE;
NetworkClientConnectGame(NetworkAddress(network_conn, rport), join_as, join_server_password, join_company_password);
NetworkClientConnectGame(network_conn, rport, join_as, join_server_password, join_company_password);
}
/* After the scan we're not used anymore. */
@@ -783,7 +784,7 @@ int openttd_main(int argc, char *argv[])
ParseConnectionString(&not_used, &port, debuglog_conn);
if (port != nullptr) rport = atoi(port);
NetworkStartDebugLog(NetworkAddress(debuglog_conn, rport));
NetworkStartDebugLog(debuglog_conn, rport);
}
if (!HandleBootstrap()) {
@@ -1108,6 +1109,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()) {
@@ -1504,7 +1510,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_host, _settings_client.network.last_port, COMPANY_SPECTATOR);
}
/* Singleplayer */
StateGameLoop();

View File

@@ -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 */

View File

@@ -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

View File

@@ -5,5 +5,4 @@ add_files(
follow_track.hpp
pathfinder_func.h
pathfinder_type.h
pf_performance_timer.hpp
)

View File

@@ -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()) {

View File

@@ -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"

View File

@@ -12,12 +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"

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -83,7 +83,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;
}
@@ -169,7 +168,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);
@@ -272,8 +270,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 +319,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. */
@@ -481,7 +477,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);

View File

@@ -34,8 +34,6 @@ template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
fclose(f2);
}
int _total_pf_time_us = 0;
template <class Types>
class CYapfReserveTrack
{

View File

@@ -35,7 +35,7 @@ bool IsReleasedVersion()
*
* <modified> shows a "M", if the binary is made from modified source code.
*/
const char _openttd_revision[] = "1.11.1";
const char _openttd_revision[] = "1.11.2";
/**
* The text version of OpenTTD's build date.
@@ -48,7 +48,7 @@ const char _openttd_build_date[] = __DATE__ " " __TIME__;
/**
* The git revision hash of this version.
*/
const char _openttd_revision_hash[] = "0be22efffc3c14db08baf5e58c448b5d074f4427";
const char _openttd_revision_hash[] = "672f285218c6817784d86f737987b75db4bc78fc";
/**
* The year of this version.
@@ -85,4 +85,4 @@ const byte _openttd_revision_tagged = 1;
* 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 | 11 << 24 | 0 << 20 | 1 << 19 | 28004;
const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 2 << 20 | 1 << 19 | 28004;

View File

@@ -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 */

View File

@@ -219,6 +219,7 @@ void UpdateAllVirtCoords()
UpdateAllStationVirtCoords();
UpdateAllSignVirtCoords();
UpdateAllTownVirtCoords();
UpdateAllTextEffectVirtCoords();
RebuildViewportKdtree();
}

View File

@@ -864,7 +864,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, {});
}
/**
@@ -890,24 +890,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
@@ -918,7 +914,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) {
@@ -957,7 +953,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);
@@ -969,6 +965,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".

View File

@@ -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];

View File

@@ -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);

View File

@@ -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<uint>(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<uint>(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<const Station*> GUIStationList;
@@ -214,6 +212,7 @@ protected:
GUIStationList stations;
Scrollbar *vscroll;
uint rating_width;
/**
* (Re)Build station list
@@ -392,16 +391,17 @@ public:
}
case WID_STL_LIST:
resize->height = FONT_HEIGHT_NORMAL;
resize->height = std::max(FONT_HEIGHT_NORMAL, FONT_HEIGHT_SMALL + ScaleFontTrad(3));
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<uint>(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:
@@ -445,6 +445,12 @@ public:
bool rtl = _current_text_dir == TD_RTL;
int max = std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->stations.size());
int y = r.top + WD_FRAMERECT_TOP;
uint line_height = this->GetWidget<NWidgetBase>(widget)->resize_y;
/* 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);
@@ -455,8 +461,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++) {
@@ -467,17 +473,17 @@ 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 += FONT_HEIGHT_NORMAL;
y += line_height;
}
if (this->vscroll->GetCount() == 0) { // company has no stations
@@ -488,30 +494,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;
}
@@ -720,7 +726,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);
@@ -739,16 +746,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),

View File

@@ -137,6 +137,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

View File

@@ -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. */
}
/**

View File

@@ -30,25 +30,25 @@
#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);
/**
* Check if a string buffer is empty.

View File

@@ -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)

View File

@@ -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);

View File

@@ -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.
@@ -1406,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;
@@ -1438,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)) {
@@ -1550,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()) {
@@ -1572,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);

View File

@@ -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;

View File

@@ -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()

View File

@@ -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);
}
/**
@@ -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);
@@ -1141,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) {

View File

@@ -74,7 +74,7 @@ private:
OpenGLBackend();
~OpenGLBackend();
const char *Init();
const char *Init(const Dimension &screen_res);
bool InitShaders();
void InternalClearCursorCache();
@@ -87,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();

View File

@@ -74,6 +74,8 @@ const char *VideoDriver_SDL_OpenGL::Start(const StringList &param)
this->Stop();
return "Can't get pointer to screen buffer";
}
/* Main loop expects to start with the buffer unmapped. */
this->ReleaseVideoPointer();
return nullptr;
}
@@ -117,7 +119,7 @@ const char *VideoDriver_SDL_OpenGL::AllocateContext()
ToggleVsync(_video_vsync);
return OpenGLBackend::Create(&GetOGLProcAddressCallback);
return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
}
void VideoDriver_SDL_OpenGL::PopulateSystemSprites()

View File

@@ -97,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) {
@@ -152,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<std::mutex> lock_wait(this->game_thread_wait_mutex);
std::lock_guard<std::mutex> 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();

View File

@@ -22,6 +22,7 @@
#include <mutex>
#include <thread>
#include <vector>
#include <functional>
extern std::string _ini_videodriver;
extern std::vector<Dimension> _resolutions;
@@ -36,7 +37,7 @@ class VideoDriver : public Driver {
const uint DEFAULT_WINDOW_HEIGHT = 480u; ///< Default window height.
public:
VideoDriver() : fast_forward_key_pressed(false), fast_forward_via_key(false), 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.
@@ -178,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<void()> &&func)
{
this->change_blitter = new_blitter;
std::lock_guard<std::mutex> lock(this->cmd_queue_mutex);
this->cmd_queue.emplace_back(std::forward<std::function<void()>>(func));
}
void GameLoopPause();
@@ -328,11 +333,29 @@ protected:
static void GameThreadThunk(VideoDriver *drv);
private:
std::mutex cmd_queue_mutex;
std::vector<std::function<void()>> cmd_queue;
/** Execute all queued commands. */
void DrainCommandQueue()
{
std::vector<std::function<void()>> 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<std::mutex> 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 */

View File

@@ -1311,6 +1311,8 @@ const char *VideoDriver_Win32OpenGL::Start(const StringList &param)
_cur_resolution = old_res;
return "Can't get pointer to screen buffer";
}
/* Main loop expects to start with the buffer unmapped. */
this->ReleaseVideoPointer();
MarkWholeScreenDirty();
@@ -1360,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) {
@@ -1380,7 +1390,7 @@ const char *VideoDriver_Win32OpenGL::AllocateContext()
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)

Some files were not shown because too many files have changed in this diff Show More