Merge branch 'master' into jgrpp

# Conflicts:
#	src/lang/korean.txt
#	src/saveload/afterload.cpp
#	src/saveload/ai_sl.cpp
#	src/saveload/game_sl.cpp
#	src/script/script_instance.cpp
pull/474/head
Jonathan G Rennison 1 year ago
commit a1f6aaa58f

@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-20.04
container:
# If you change this version, change the number in the cache step too.
image: emscripten/emsdk:2.0.31
image: emscripten/emsdk:3.1.28
steps:
- name: Checkout
@ -38,7 +38,7 @@ jobs:
uses: actions/cache@v3
with:
path: /emsdk/upstream/emscripten/cache
key: 2.0.31-${{ runner.os }}
key: 3.1.28-${{ runner.os }}
- name: Patch Emscripten to support LZMA
run: |

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-20.04
container:
# If you change this version, change the number in the cache step too.
image: emscripten/emsdk:2.0.31
image: emscripten/emsdk:3.1.28
steps:
- name: Update deployment status to in progress
@ -44,7 +44,7 @@ jobs:
uses: actions/cache@v3
with:
path: /emsdk/upstream/emscripten/cache
key: 2.0.31-${{ runner.os }}
key: 3.1.28-${{ runner.os }}
- name: Patch Emscripten to support LZMA
run: |

@ -61,7 +61,7 @@ macro(compile_flags)
if(MSVC)
add_compile_options(/W3)
if(MSVC_VERSION GREATER 1929)
if(MSVC_VERSION GREATER 1929 AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# Starting with version 19.30, there is an optimisation bug, see #9966 for details
# This flag disables the broken optimisation to work around the bug
add_compile_options(/d2ssa-rse-)

@ -1,4 +1,4 @@
FROM emscripten/emsdk:2.0.34
FROM emscripten/emsdk:3.1.28
COPY emsdk-liblzma.patch /
RUN cd /emsdk/upstream/emscripten && patch -p1 < /emsdk-liblzma.patch

@ -1,40 +1,38 @@
## How to build with Emscripten
Building with Emscripten works with emsdk 2.0.31 and above.
Please use docker with the supplied `Dockerfile` to build for emscripten.
It takes care of a few things:
- Use a version of emscripten we know works
- Patch in LibLZMA support (as this is not supported by upstream)
Currently there is no LibLZMA support upstream; for this we suggest to apply
the provided patch in this folder to your emsdk installation.
For convenience, a Dockerfile is supplied that does this patches for you
against upstream emsdk docker. Best way to use it:
Build the docker image:
First, build the docker image by navigating in the folder this `README.md` is in, and executing:
```
docker build -t emsdk-lzma .
```
Build the host tools first:
Next, navigate back to the root folder of this project.
Now we build the host tools first:
```
mkdir build-host
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma cmake .. -DOPTION_TOOLS_ONLY=ON
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma make -j5 tools
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build-host emsdk-lzma make -j$(nproc) tools
```
Next, build the game with emscripten:
Finally, we build the actual game:
```
mkdir build
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emcmake cmake .. -DHOST_BINARY_DIR=../build-host -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_ASSERTS=OFF
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emmake make -j5
docker run -it --rm -v $(pwd):$(pwd) -u $(id -u):$(id -g) --workdir $(pwd)/build emsdk-lzma emmake make -j$(nproc)
```
And now you have in your build folder files like "openttd.html".
In the `build` folder you will now see `openttd.html`.
To run it locally, you would have to start a local webserver, like:
To run it locally, you would have to start a local webserver; something like:
```
cd build
python3 -m http.server
````
Now you can play the game via http://127.0.0.1:8000/openttd.html .
You can now play the game via http://127.0.0.1:8000/openttd.html .

@ -13,7 +13,7 @@ of emsdk.
diff --git a/tools/settings.py b/tools/settings.py
--- a/tools/settings.py
+++ b/tools/settings.py
@@ -38,6 +38,7 @@
@@ -40,6 +40,7 @@ PORTS_SETTINGS = {
'USE_SDL_NET',
'USE_SDL_GFX',
'USE_LIBJPEG',
@ -24,24 +24,23 @@ diff --git a/tools/settings.py b/tools/settings.py
diff --git a/src/settings.js b/src/settings.js
--- a/src/settings.js
+++ b/src/settings.js
@@ -1382,8 +1382,12 @@ var USE_BZIP2 = 0;
// 1 = use libjpeg from emscripten-ports
// [link]
var USE_LIBJPEG = 0;
@@ -1450,6 +1450,10 @@ var USE_GIFLIB = false;
// [compile+link]
var USE_LIBJPEG = false;
+// 1 = use liblzma from emscripten-ports
+// [link]
+var USE_LIBLZMA = 0;
+// [compile+link]
+var USE_LIBLZMA = false;
+
// 1 = use libpng from emscripten-ports
// [link]
var USE_LIBPNG = 0;
// [compile+link]
var USE_LIBPNG = false;
diff --git a/tools/ports/liblzma.py b/tools/ports/liblzma.py
new file mode 100644
--- /dev/null
+++ b/tools/ports/liblzma.py
@@ -0,0 +1,160 @@
@@ -0,0 +1,151 @@
+# Copyright 2020 The Emscripten Authors. All rights reserved.
+# Emscripten is available under two separate licenses, the MIT license and the
+# University of Illinois/NCSA Open Source License. Both these licenses can be
@ -52,8 +51,8 @@ new file mode 100644
+import logging
+from pathlib import Path
+
+VERSION = '5.2.5'
+HASH = '7443674247deda2935220fbc4dfc7665e5bb5a260be8ad858c8bd7d7b9f0f868f04ea45e62eb17c0a5e6a2de7c7500ad2d201e2d668c48ca29bd9eea5a73a3ce'
+VERSION = '5.4.0'
+HASH = '29b2cd25bb5b234b329ffe9547692d2c29be393db9d8d4ce70a66dfdaebd54433e79a89d80c57e58cd4559c3c68b9845507d5fedf3eec1c528a81e3d9ddbd811'
+
+
+def needed(settings):
@ -61,40 +60,31 @@ new file mode 100644
+
+
+def get(ports, settings, shared):
+ ports.fetch_project('liblzma', 'https://tukaani.org/xz/xz-' + VERSION + '.tar.gz', 'xz-' + VERSION, sha512hash=HASH)
+ ports.fetch_project('liblzma', f'https://tukaani.org/xz/xz-{VERSION}.tar.gz', sha512hash=HASH)
+
+ def create(final):
+ logging.info('building port: liblzma')
+
+ ports.clear_project_build('liblzma')
+
+ source_path = os.path.join(ports.get_dir(), 'liblzma', 'xz-' + VERSION)
+ dest_path = os.path.join(ports.get_build_dir(), 'liblzma')
+
+ shared.try_delete(dest_path)
+ os.makedirs(dest_path)
+ shutil.rmtree(dest_path, ignore_errors=True)
+ shutil.copytree(source_path, dest_path)
+ source_path = os.path.join(ports.get_dir(), 'liblzma', f'xz-{VERSION}', 'src', 'liblzma')
+ ports.write_file(os.path.join(source_path, 'config.h'), config_h)
+ ports.install_headers(os.path.join(source_path, 'api'), pattern='lzma.h')
+ ports.install_headers(os.path.join(source_path, 'api', 'lzma'), pattern='*.h', target='lzma')
+
+ build_flags = ['-DHAVE_CONFIG_H', '-DTUKLIB_SYMBOL_PREFIX=lzma_', '-fvisibility=hidden']
+ exclude_dirs = ['xzdec', 'xz', 'lzmainfo']
+ exclude_files = ['crc32_small.c', 'crc64_small.c', 'crc32_tablegen.c', 'crc64_tablegen.c', 'price_tablegen.c', 'fastpos_tablegen.c'
+ exclude_files = ['crc32_small.c', 'crc64_small.c', 'crc32_tablegen.c', 'crc64_tablegen.c', 'price_tablegen.c', 'fastpos_tablegen.c',
+ 'tuklib_exit.c', 'tuklib_mbstr_fw.c', 'tuklib_mbstr_width.c', 'tuklib_open_stdxxx.c', 'tuklib_progname.c']
+ include_dirs_rel = ['../common', 'api', 'common', 'check', 'lz', 'rangecoder', 'lzma', 'delta', 'simple']
+
+ Path(dest_path, os.path.join('src', 'config.h')).write_text(config_h)
+
+ include_dirs = [os.path.join(dest_path, 'src', 'liblzma', p) for p in include_dirs_rel]
+ ports.build_port(os.path.join(dest_path, 'src'), final, flags=build_flags, exclude_dirs=exclude_dirs, exclude_files=exclude_files, includes=include_dirs)
+ include_dirs_rel = ['../common', 'api', 'check', 'common', 'delta', 'lz', 'lzma', 'rangecoder', 'simple']
+
+ ports.install_headers(os.path.join(dest_path, 'src', 'liblzma', 'api'), 'lzma.h')
+ ports.install_headers(os.path.join(dest_path, 'src', 'liblzma', 'api', 'lzma'), '*.h', 'lzma')
+ include_dirs = [os.path.join(source_path, p) for p in include_dirs_rel]
+ ports.build_port(source_path, final, 'liblzma', flags=build_flags, exclude_files=exclude_files, includes=include_dirs)
+
+ return [shared.Cache.get_lib('liblzma.a', create, what='port')]
+ return [shared.cache.get_lib('liblzma.a', create, what='port')]
+
+
+def clear(ports, settings, shared):
+ shared.Cache.erase_lib('liblzma.a')
+ shared.cache.erase_lib('liblzma.a')
+
+
+def process_args(ports):
@ -105,7 +95,7 @@ new file mode 100644
+ return 'liblzma (USE_LIBLZMA=1; public domain)'
+
+
+config_h = r'''
+config_h = '''
+#define ASSUME_RAM 128
+#define ENABLE_NLS 1
+#define HAVE_CHECK_CRC32 1
@ -177,9 +167,9 @@ new file mode 100644
+#define PACKAGE "xz"
+#define PACKAGE_BUGREPORT "lasse.collin@tukaani.org"
+#define PACKAGE_NAME "XZ Utils"
+#define PACKAGE_STRING "XZ Utils 5.2.5"
+#define PACKAGE_STRING "XZ Utils 5.4.0"
+#define PACKAGE_TARNAME "xz"
+#define PACKAGE_VERSION "5.2.5"
+#define PACKAGE_VERSION "5.4.0"
+#define SIZEOF_SIZE_T 4
+#define STDC_HEADERS 1
+#define TUKLIB_CPUCORES_SYSCONF 1
@ -200,5 +190,5 @@ new file mode 100644
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+#define VERSION "5.2.5"
+#define VERSION "5.4.0"
+'''

@ -450,7 +450,7 @@ void RefTable::Resize(SQUnsignedInteger size)
SQUnsignedInteger oldnumofslots = _numofslots;
AllocNodes(size);
//rehash
SQUnsignedInteger nfound = 0;
[[maybe_unused]] SQUnsignedInteger nfound = 0;
for(SQUnsignedInteger n = 0; n < oldnumofslots; n++) {
if(type(t->obj) != OT_NULL) {
//add back;

@ -128,11 +128,6 @@ public:
*/
static void Save(CompanyID company);
/**
* Load data for an AI from a savegame.
*/
static void Load(CompanyID company, int version);
/**
* Get the number of days before the next AI should start.
*/

@ -59,6 +59,8 @@
assert(c->ai_instance == nullptr);
c->ai_instance = new AIInstance();
c->ai_instance->Initialize(info);
c->ai_instance->LoadOnStack(config->GetToLoadData());
config->SetToLoadData(nullptr);
cur_company.Restore();
@ -287,21 +289,6 @@
}
}
/* static */ void AI::Load(CompanyID company, int version)
{
if (!_networking || _network_server) {
Company *c = Company::GetIfValid(company);
assert(c != nullptr && c->ai_instance != nullptr);
Backup<CompanyID> cur_company(_current_company, company, FILE_LINE);
c->ai_instance->Load(version);
cur_company.Restore();
} else {
/* Read, but ignore, the load data */
AIInstance::LoadEmpty();
}
}
/* static */ int AI::GetStartNextTime()
{
/* Find the first company which doesn't exist yet */

@ -1757,7 +1757,7 @@ struct BuildVehicleWindow : BuildVehicleWindowBase {
for (const auto &variant : variants) {
if (std::find(this->eng_list.begin(), this->eng_list.end(), variant) == this->eng_list.end()) {
const Engine *e = Engine::Get(variant);
list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0);
this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0);
}
}

@ -559,7 +559,7 @@ void SetupEngines()
_engine_pool.CleanPool();
assert(_engine_mngr.size() >= _engine_mngr.NUM_DEFAULT_ENGINES);
uint index = 0;
[[maybe_unused]] uint index = 0;
for (const EngineIDMapping &eid : _engine_mngr) {
/* Assert is safe; there won't be more than 256 original vehicles
* in any case, and we just cleaned the pool. */

@ -87,11 +87,6 @@ public:
*/
static void Save();
/**
* Load data for a GameScript from a savegame.
*/
static void Load(int version);
/** Wrapper function for GameScanner::GetConsoleList */
static std::string GetConsoleList(bool newest_only = false);
/** Wrapper function for GameScanner::GetConsoleLibraryList */

@ -88,6 +88,8 @@
Game::info = info;
Game::instance = new GameInstance();
Game::instance->Initialize(info);
Game::instance->LoadOnStack(config->GetToLoadData());
config->SetToLoadData(nullptr);
cur_company.Restore();
@ -211,18 +213,6 @@
}
}
/* static */ void Game::Load(int version)
{
if (Game::instance != nullptr && (!_networking || _network_server)) {
Backup<CompanyID> cur_company(_current_company, OWNER_DEITY, FILE_LINE);
Game::instance->Load(version);
cur_company.Restore();
} else {
/* Read, but ignore, the load data */
GameInstance::LoadEmpty();
}
}
/* static */ std::string Game::GetConsoleList(bool newest_only)
{
return Game::scanner_info->GetConsoleList(newest_only);

@ -2864,6 +2864,7 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Cidade A
STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Constrói cidade num local aleatório
STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Várias cidades aleatórias
STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cobrir o mapa com cidades colocadas aleatoriamente
STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Fazer com que todas as cidades cresçam ligeiramente
STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Nome da cidade:
STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Coloque o nome da cidade
@ -4535,7 +4536,7 @@ STR_TIMETABLE_CLEAR_TIME :{BLACK}Limpar H
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Limpar a quantidade de tempo para a ordem destacada
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Alterar Limite de Vel.
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Altera a velocidade máxima de viagem para a ordem selecionada
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Altera a velocidade máxima de viagem para a ordem selecionada. Ctrl+Clique define a velocidade para todas as ordens
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Limpa Limite de Vel.
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Limpar a velocidade máxima de viagem para a ordem selecionada

@ -3346,6 +3346,7 @@ STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Represen
STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}Desplaça l'sprite un píxel en el sentit indicat. Amb Ctrl+Clic el desplaça 8 píxels.
###length 2
STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}Sprite centrat
STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Restableix relatius

@ -2890,6 +2890,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random T
STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location
STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns
STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns
STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Expand all towns
STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Make all towns grow slightly
STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name:
STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name
@ -4555,22 +4557,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Start da
STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click distributes all vehicles sharing this order evenly from the given date based on their relative order, if the order is completely timetabled
STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take. Ctrl+Click sets the time for all orders
STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order. Ctrl+Click clears the time for all orders
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order. Ctrl+Click sets the speed for all orders
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order. Ctrl+Click clears the speed for all orders
STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time
STR_TIMETABLE_AUTOFILL :{BLACK}Autofill
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times)
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey. Ctrl+Click to try to keep waiting times
STR_TIMETABLE_EXPECTED :{BLACK}Expected
STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled
@ -4826,6 +4828,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Can't prospect industry...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town
@ -4840,6 +4843,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... fore
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}The funding failed to prospect due to bad luck; try again
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}There were no suitable places to prospect for this industry
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}There were no suitable places for '{STRING}' industries
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Change the map generation parameters to get a better map

@ -2891,6 +2891,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Random T
STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Found town in random location
STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Many random towns
STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cover the map with randomly placed towns
STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Expand all towns
STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Make all towns grow slightly
STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Town name:
STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Enter town name
@ -4556,22 +4558,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Start Da
STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Select a date as starting point of this timetable. Ctrl+Click distributes all vehicles sharing this order evenly from the given date based on their relative order, if the order is completely timetabled
STR_TIMETABLE_CHANGE_TIME :{BLACK}Change Time
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Change the amount of time that the highlighted order should take. Ctrl+Click sets the time for all orders
STR_TIMETABLE_CLEAR_TIME :{BLACK}Clear Time
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Clear the amount of time for the highlighted order. Ctrl+Click clears the time for all orders
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Change Speed Limit
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Change the maximum travel speed of the highlighted order. Ctrl+Click sets the speed for all orders
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Clear Speed Limit
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Clear the maximum travel speed of the highlighted order. Ctrl+Click clears the speed for all orders
STR_TIMETABLE_RESET_LATENESS :{BLACK}Reset Late Counter
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Reset the lateness counter, so the vehicle will be on time
STR_TIMETABLE_AUTOFILL :{BLACK}Autofill
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey (Ctrl+Click to try to keep waiting times)
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Fill the timetable automatically with the values from the next journey. Ctrl+Click to try to keep waiting times
STR_TIMETABLE_EXPECTED :{BLACK}Expected
STR_TIMETABLE_SCHEDULED :{BLACK}Scheduled
@ -4827,6 +4829,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... too
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Can't generate industries...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Can't build {STRING} here...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Can't construct this industry type here...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Can't prospect industry...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... too close to another industry
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... must found town first
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... only one allowed per town
@ -4841,6 +4844,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... fore
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... can only be built above the snow-line
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... can only be built below the snow-line
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}The funding failed to prospect due to bad luck; try again
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}There were no suitable places to prospect for this industry
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}There were no suitable places for '{STRING}' industries
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Change the map generation parameters to get a better map

@ -4801,6 +4801,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... liik
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Teollisuuslaitoksia ei voi luoda...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}{STRING}: tähän ei voi rakentaa...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Teollisuustyyppiä ei voi rakentaa tähän...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Ei voida koekaivaa…
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... liian lähellä toista teollisuuslaitosta
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... kunta pitää perustaa ensin
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... vain yksi on sallittu kuntaa kohden
@ -4815,6 +4816,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... mets
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... voidaan rakentaa vain lumirajan yläpuolelle
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... voidaan rakentaa vain lumirajan alapuolelle
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}Rahoittamasi koekaivaus epäonnistui; yritä uudelleen
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}Ei ollut sopivia paikkoja tämän teollisuuslaitoksen koekaivauksille
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Ei ollut sopivia paikkoja ”{STRING}”-teollisuuslaitoksille
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Muuta kartan parametreja saadaksesi paremman kartan

@ -4843,6 +4843,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... trop
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Impossibile generare industrie...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Impossibile costruire {STRING} qui...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Impossibile costruire l'industria qui...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Non si può eseguire la prospezione...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... troppo vicina ad un'altra industria
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... bisogna fondare una città prima
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... ne è ammessa solo una per città
@ -4857,6 +4858,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... una
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... può essere costruita solo al di sopra della linea delle nevi perenni
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... può essere costruita solo al di sotto della linea delle nevi perenni
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}Nonostante il finanziamento la prospezione è fallita per sfortunate circostanze; riprova
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}Non c'erano luoghi adatti per la prospezione di questa industria
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nessun luogo adatto per le industrie '{STRING}'
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Modificare i parametri di generazione delle mappa in modo da ottenerne una migliore

@ -3815,6 +3815,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}무작
STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}무작위 위치에 도시를 건설합니다
STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}무작위로 여러 도시 건설
STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}무작위로 도시를 건설합니다
STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}모든 도시 확장
STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}모든 도시를 조금씩 확장시킵니다
STR_FOUND_TOWN_NAME_TITLE :{YELLOW}도시 이름:
STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}도시 이름 입력
@ -4345,8 +4347,8 @@ STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}현재
STR_SPRITE_ALIGNER_MOVE_TOOLTIP :{BLACK}X축이나 Y축 방향으로 스프라이트를 이동시킵니다. CTRL+클릭하면 한 번에 8씩 이동시킬 수 있습니다
###length 2
STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}오프셋 가운데
STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}스프라이트 가운데
STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}오프셋 가운데 정렬
STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}스프라이트 가운데 정렬
STR_SPRITE_ALIGNER_CROSSHAIR :{BLACK}십자선
@ -5908,22 +5910,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}시작
STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}이 시간표의 시작 날짜를 선택하세요. CTRL+클릭하면, 시간표가 모두 작성되어 있다는 가정 하에, 주어진 경로를 기반으로 설정한 날짜부터 이 경로를 공유하는 모든 차량을 균등하게 출발시킵니다
STR_TIMETABLE_CHANGE_TIME :{BLACK}시간값 변경
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}선택한 경로에서 소요되는 시간 값을 변경합니다 (CTRL+클릭하면 모든 경로의 시간을 설정합니다)
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}선택한 경로에서 소요되는 시간 값을 변경합니다. CTRL+클릭하면 모든 경로에 그 시간 값을 설정합니다
STR_TIMETABLE_CLEAR_TIME :{BLACK}시간값 초기화
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}선택한 경로에서 소요되는 시간 값을 초기화합니다 (CTRL+클릭하면 모든 경로의 시간을 초기화합니다)
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}선택한 경로에서 소요되는 시간 값을 초기화합니다. CTRL+클릭하면 모든 경로의 시간을 초기화합니다
STR_TIMETABLE_CHANGE_SPEED :{BLACK}속력 제한
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}선택한 경로의 최대 여행 속력을 제한합니다 (CTRL+클릭하면 모든 경로의 속력을 설정합니다)
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}선택한 경로의 최대 여행 속력을 제한합니다. CTRL+클릭하면 모든 경로에 그 속력 값을 설정합니다
STR_TIMETABLE_CLEAR_SPEED :{BLACK}속력 제한값 초기화
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}선택한 경로의 최대 여행 속력 제한값을 초기화합니다 (CTRL+클릭하면 모든 경로의 속력을 초기화합니다)
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}선택한 경로의 최대 여행 속력 제한값을 초기화합니다. CTRL+클릭하면 모든 경로의 속력을 초기화합니다
STR_TIMETABLE_RESET_LATENESS :{BLACK}지연 시간 초기화
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}이 차량의 지연 시간값을 초기화하여, 정시운행 상태로 바꿉니다
STR_TIMETABLE_AUTOFILL :{BLACK}자동 시간 설정
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}다음 운행시 자동으로 값을 얻어 시간표를 완성합니다 (역에 머무르는 시간값을 유지하려면 CTRL+클릭하십시오)
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}다음 운행시 자동으로 값을 얻어 시간표를 완성합니다. 역에 머무르는 시간값을 유지하려면 CTRL+클릭하세요
STR_TIMETABLE_AUTOMATE :{BLACK}자동
STR_TIMETABLE_AUTOMATE_TOOLTIP :{BLACK}각 운행마다 자동으로 값을 얻어 시간표를 만듭니다.
@ -6289,6 +6291,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... 산
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}산업시설을 생성할 수 없습니다...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}여기에 {STRING}{G 0 "을" "를"} 건설할 수 없습니다...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}여기에 산업시설을 건설할 수 없습니다...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}산업시설에 투자할 수 없습니다...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... 다른 산업시설과 너무 가깝습니다
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... 도시를 먼저 만들어야 합니다
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... 한 도시에 하나만 지을 수 있습니다
@ -6303,6 +6306,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... 숲
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... 만년설 고도 위에만 지을 수 있습니다
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... 만년설 고도 아래에만 지을 수 있습니다
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}운이 나빠 투자에 실패했습니다. 다시 시도해주세요.
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}이 산업시설을 투자하기에 적합한 장소가 없습니다
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}적당한 장소가 없어 '{STRING}'{G 0 "이" "가"} 지어지지 않았습니다
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}더 나은 지도가 생성되도록 설정 값을 변경해보십시오

@ -1315,11 +1315,11 @@ STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH :Tamanho máximo
STR_CONFIG_SETTING_MAX_TUNNEL_LENGTH_HELPTEXT :Tamanho máximo para construção de túneis
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD :Método de financiamento de indústrias primárias: {STRING}
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Método de financiar uma indústria primária. 'nenhum' significa que não é possível financiar nenhuma, 'prospecção' significa que é possível financiar, mas a construção é feita num local arbitrário no mapa e até pode falhar, 'como as outras' significa que as indústrias de matérias primas podem ser construídas em qualquer sítio pelas empresas, como se fossem indústrias de processamento
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_HELPTEXT :Método de financiar uma indústria primária. 'nenhum' significa que não é possível financiar nenhuma; 'em prospeção' significa que é possível financiar, mas a construção é feita num local aleatório no mapa e pode até falhar; 'como as outras' significa que as indústrias de matérias primas podem ser construídas em qualquer local escolhido pelas empresas, como se fossem indústrias de processamento
###length 3
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NONE :Nenhum
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_NORMAL :Como as outras
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Prospecção
STR_CONFIG_SETTING_RAW_INDUSTRY_CONSTRUCTION_METHOD_PROSPECTING :Em prospeção
STR_CONFIG_SETTING_INDUSTRY_PLATFORM :Área plana à volta das industrias: {STRING}
STR_CONFIG_SETTING_INDUSTRY_PLATFORM_HELPTEXT :Quantidade de terreno plano á volta de uma industria. Isto garante que terreno vazio esteja disponível para construir linhas, etc
@ -2900,7 +2900,7 @@ STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_TOOLTIP :{BLACK}Cobrir o
STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_CAPTION :{WHITE}Criar indústrias aleatórias
STR_FUND_INDUSTRY_MANY_RANDOM_INDUSTRIES_QUERY :{YELLOW}Tem a certeza que deseja criar muitas indústrias aleatórias?
STR_FUND_INDUSTRY_INDUSTRY_BUILD_COST :{BLACK}Custo: {YELLOW}{CURRENCY_LONG}
STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospectar
STR_FUND_INDUSTRY_PROSPECT_NEW_INDUSTRY :{BLACK}Prospetar
STR_FUND_INDUSTRY_BUILD_NEW_INDUSTRY :{BLACK}Construir
STR_FUND_INDUSTRY_FUND_NEW_INDUSTRY :{BLACK}Criar
STR_FUND_INDUSTRY_REMOVE_ALL_INDUSTRIES :{BLACK}Remover todas as indústrias
@ -4804,6 +4804,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... dema
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Não é possível gerar indústrias...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Não é possível construir {STRING} aqui...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Não é possível construir este tipo de indústria aqui...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Não é possível prospetar indústria...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... muito perto de outra indústria
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... é necessário construir uma localidade primeiro
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... só é permitido uma por localidade
@ -4818,6 +4819,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... a fl
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... só se pode construir acima da linha da neve
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... só se pode construir abaixo da linha da neve
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}O financiamento falhou em prospetar devido ao azar; tente novamente
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}Não havia locais adequados para prospetar esta indústria
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Não foram encontrados locais adequados para '{STRING}' indústrias
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Altera os parâmetros de geração do mapa para obter um mapa melhor

@ -4800,6 +4800,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... prea
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Nu pot genera industrii...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Nu se poate construi {STRING} aici...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Acest tip de industrie nu se poate construi aici...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Nu pot prospecta industria...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... prea aproape de altă industrie
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... mai întâi trebuie creat un oraş
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... un singur obiectiv de acest tip este permis per oraş
@ -4814,6 +4815,7 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... păd
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... poate fi construit doar deasupra liniei zăpezii
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... poate fi construit doar sub linia zăpezii
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}Nu există locuri potrivite de prospectat pentru această industrie
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Nu s-au găsit locuri potrivite pentru industriile '{STRING}'
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Modifică parametrii generatorului ca să obții o hartă mai bună

@ -5010,6 +5010,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... сл
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}Невозможно создать предприятия...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}Здесь нельзя создать {STRING}...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}Построить это предприятие невозможно...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}Не удалось разведать месторождение...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... слишком близко к другому предприятию
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... сначала постройте город
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... такой объект уже есть в городе
@ -5024,6 +5025,8 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... ле
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... можно строить только выше снеговой линии
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... можно строить только ниже снеговой линии
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}Геологоразведка не принесла результатов; попробуйте снова.
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}Нет подходящего места для геологоразведки.
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}Нет подходящего места для {STRING.gen}
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Измените настройки создания карты для получения более подходящей карты

@ -2807,7 +2807,7 @@ STR_LANDSCAPING_TOOLBAR :{WHITE}景观
STR_LANDSCAPING_TOOLTIP_LOWER_A_CORNER_OF_LAND :{BLACK}降低地块的一角
STR_LANDSCAPING_TOOLTIP_RAISE_A_CORNER_OF_LAND :{BLACK}升高地块的一角
STR_LANDSCAPING_LEVEL_LAND_TOOLTIP :{BLACK}拉平地面
STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}购买土地以备将来使用,按住 Shift 键操作可以显示所需资金
STR_LANDSCAPING_TOOLTIP_PURCHASE_LAND :{BLACK}购买土地以备将来使用。按 Ctrl 键可选择对角线区域。按 Shift 键可以预览所需资金。
# Object construction window
STR_OBJECT_BUILD_CAPTION :{WHITE}物体选单

@ -2083,7 +2083,7 @@ STR_INTRO_CONFIG_SETTINGS_TREE :{BLACK}Configur
STR_INTRO_NEWGRF_SETTINGS :{BLACK}Configuración NewGRF
STR_INTRO_ONLINE_CONTENT :{BLACK}Contenido Online
STR_INTRO_AI_SETTINGS :{BLACK}Configuración de IA
STR_INTRO_GAMESCRIPT_SETTINGS :{BLACK}Scripts de juego
STR_INTRO_GAMESCRIPT_SETTINGS :{BLACK}Scripts de Juego
STR_INTRO_QUIT :{BLACK}Salir
STR_INTRO_TOOLTIP_NEW_GAME :{BLACK}Comeenza una partida nueva. Ctrl+clic omite la configuración del escenario
@ -2866,6 +2866,8 @@ STR_FOUND_TOWN_RANDOM_TOWN_BUTTON :{BLACK}Municipi
STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP :{BLACK}Funda un municipio en un lugar aleatorio
STR_FOUND_TOWN_MANY_RANDOM_TOWNS :{BLACK}Varios municipios al azar
STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP :{BLACK}Cubre el mapa con municipios colocados al azar
STR_FOUND_TOWN_EXPAND_ALL_TOWNS :{BLACK}Expandir todos los municipios
STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP :{BLACK}Expande levemente todos los municipios
STR_FOUND_TOWN_NAME_TITLE :{YELLOW}Nombre del municipio:
STR_FOUND_TOWN_NAME_EDITOR_TITLE :{BLACK}Introducir nombre de municipio
@ -3346,7 +3348,10 @@ STR_SPRITE_ALIGNER_SPRITE_TOOLTIP :{BLACK}Represen
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
###length 2
STR_SPRITE_ALIGNER_CENTRE_OFFSET :{BLACK}Desviación (offset) centrada
STR_SPRITE_ALIGNER_CENTRE_SPRITE :{BLACK}Sprite centrado
STR_SPRITE_ALIGNER_CROSSHAIR :{BLACK}Punto de mira
STR_SPRITE_ALIGNER_RESET_BUTTON :{BLACK}Reiniciar coordenadas relativas
STR_SPRITE_ALIGNER_RESET_TOOLTIP :{BLACK}Reinicia las coordenadas relativas actuales
@ -4528,22 +4533,22 @@ STR_TIMETABLE_STARTING_DATE :{BLACK}Fecha de
STR_TIMETABLE_STARTING_DATE_TOOLTIP :{BLACK}Selecciona la fecha de inicio del horario. Ctrl+click distribuye uniformemente todos los vehículos que compartan este horario a partir de la fecha proporcionada, basados en su orden relativo, siempre que el horario esté completamente rellenado
STR_TIMETABLE_CHANGE_TIME :{BLACK}Modificar duración
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Modifica la duración de la orden seleccionada
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Modifica la duración de la orden seleccionada. Ctrl+clic establece la duración para todas las órdenes
STR_TIMETABLE_CLEAR_TIME :{BLACK}Borrar duración
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Borra la duración de la orden resaltada
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Borra la duración de la orden resaltada.Ctrl+clic elimina la duración de todas las órdenes
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Modificar límite de velocidad
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambia el límite de velocidad de la orden resaltada
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Cambia el límite de velocidad de la orden resaltada. Ctrl+clic establece el límite para todas las órdenes
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Borrar límite de velocidad
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Borra el límite de velocidad de la orden resaltada
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Borra el límite de velocidad de la orden resaltada. Ctrl+clic elimina el límite de todas las órdenes
STR_TIMETABLE_RESET_LATENESS :{BLACK}Reiniciar retraso
STR_TIMETABLE_RESET_LATENESS_TOOLTIP :{BLACK}Establece en cero el retraso acumulado del vehículo para que sea puntual
STR_TIMETABLE_AUTOFILL :{BLACK}Rellenar automáticamente
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Rellena el horario automáticamente con los valores del siguiente recorrido (Ctrl+clic para intentar mantener los tiempos de permanencia en estación)
STR_TIMETABLE_AUTOFILL_TOOLTIP :{BLACK}Rellena el horario automáticamente con los valores del siguiente recorrido. Ctrl+clic para intentar mantener los tiempos de permanencia en estación
STR_TIMETABLE_EXPECTED :{BLACK}Previsto
STR_TIMETABLE_SCHEDULED :{BLACK}Programado
@ -4579,7 +4584,7 @@ STR_AI_DEBUG_MATCH_CASE_TOOLTIP :{BLACK}Activa/d
STR_AI_DEBUG_CONTINUE :{BLACK}Continuar
STR_AI_DEBUG_CONTINUE_TOOLTIP :{BLACK}Quita la pausa y hace que la IA continúe
STR_AI_DEBUG_SELECT_AI_TOOLTIP :{BLACK}Mostrar salida de depuración de esta IA
STR_AI_GAME_SCRIPT :{BLACK}Script de juego
STR_AI_GAME_SCRIPT :{BLACK}Script de Juego
STR_AI_GAME_SCRIPT_TOOLTIP :{BLACK}Analizar el registro del script de juego
STR_ERROR_AI_NO_AI_FOUND :No se encontró ninguna IA apropiada para cargar.{}Ésta es una IA por defecto que no realiza acción alguna.{}Puedes descargar nuevas IA mediante el sistema de 'Contenido Online'
@ -4799,6 +4804,7 @@ STR_ERROR_TOO_MANY_INDUSTRIES :{WHITE}... dema
STR_ERROR_CAN_T_GENERATE_INDUSTRIES :{WHITE}No se pueden crear industrias...
STR_ERROR_CAN_T_BUILD_HERE :{WHITE}No puede construirse {STRING} aquí...
STR_ERROR_CAN_T_CONSTRUCT_THIS_INDUSTRY :{WHITE}No se puede construir este tipo de industria aquí...
STR_ERROR_CAN_T_PROSPECT_INDUSTRY :{WHITE}No se puede realizar prospección para la industria...
STR_ERROR_INDUSTRY_TOO_CLOSE :{WHITE}... demasiado cerca de otra industria
STR_ERROR_MUST_FOUND_TOWN_FIRST :{WHITE}... debe construirse un municipio primero
STR_ERROR_ONLY_ONE_ALLOWED_PER_TOWN :{WHITE}... solo se permite uno por municipio
@ -4813,7 +4819,9 @@ STR_ERROR_FOREST_CAN_ONLY_BE_PLANTED :{WHITE}... solo
STR_ERROR_CAN_ONLY_BE_BUILT_ABOVE_SNOW_LINE :{WHITE}... solo puede construirse por encima de la cota de nieve
STR_ERROR_CAN_ONLY_BE_BUILT_BELOW_SNOW_LINE :{WHITE}... solo puede construirse por debajo de la cota de nieve
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}No había sitios apropiados disponibles para industrias '{STRING}'
STR_ERROR_PROSPECTING_WAS_UNLUCKY :{WHITE}La fundación ha fallado debido a una prospeccion desafortunada; intentar de nuevo
STR_ERROR_NO_SUITABLE_PLACES_FOR_PROSPECTING :{WHITE}No había lugares apropiados para realizar prospecciones para esta industria
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES :{WHITE}No había lugares apropiados para industrias '{STRING}'
STR_ERROR_NO_SUITABLE_PLACES_FOR_INDUSTRIES_EXPLANATION :{WHITE}Cambia los parámetros de generación del mapa para obtener un mapa mejor
# Station construction related errors

@ -42,6 +42,7 @@
#include "../road_cmd.h"
#include "../ai/ai.hpp"
#include "../ai/ai_gui.hpp"
#include "../game/game.hpp"
#include "../town.h"
#include "../economy_base.h"
#include "../animated_tile_func.h"
@ -317,7 +318,6 @@ static void InitializeWindowsAndCaches()
CheckTrainsLengths();
ShowNewGRFError();
ShowAIDebugWindowIfAIError();
/* Rebuild the smallmap list of owners. */
BuildOwnerLegend();
@ -613,6 +613,22 @@ TileIndex GetOtherTunnelBridgeEndOld(TileIndex tile)
}
/**
* Start the scripts.
*/
static void StartScripts()
{
/* Start the GameScript. */
Game::StartNew();
/* Start the AIs. */
for (const Company *c : Company::Iterate()) {
if (Company::IsValidAiID(c->index)) AI::StartNew(c->index, false);
}
ShowAIDebugWindowIfAIError();
}
/**
* Perform a (large) amount of savegame conversion *magic* in order to
* load older savegames and to fill the caches for various purposes.
@ -966,13 +982,6 @@ bool AfterLoadGame()
/* Update template vehicles */
AfterLoadTemplateVehicles();
/* Make sure there is an AI attached to an AI company */
{
for (const Company *c : Company::Iterate()) {
if (c->is_ai && c->ai_instance == nullptr) AI::StartNew(c->index);
}
}
/* make sure there is a town in the game */
if (_game_mode == GM_NORMAL && Town::GetNumItems() == 0) {
SetSaveLoadError(STR_ERROR_NO_TOWN_IN_SCENARIO);
@ -4191,6 +4200,9 @@ bool AfterLoadGame()
_game_load_tick_skip_counter = _tick_skip_counter;
_game_load_time = time(nullptr);
/* Start the scripts. This MUST happen after everything else. */
StartScripts();
return true;
}

@ -104,11 +104,8 @@ static void Load_AIPL()
config->StringToSettings(_ai_saveload_settings);
/* Start the AI directly if it was active in the savegame */
if (Company::IsValidAiID(index)) {
AI::StartNew(index, false);
AI::Load(index, _ai_saveload_version);
}
/* Load the AI saved data */
if (Company::IsValidAiID(index)) config->SetToLoadData(AIInstance::Load(_ai_saveload_version));
}
}

@ -95,9 +95,8 @@ static void Load_GSDT()
config->StringToSettings(_game_saveload_settings);
/* Start the GameScript directly if it was active in the savegame */
Game::StartNew();
Game::Load(_game_saveload_version);
/* Load the GameScript saved data */
config->SetToLoadData(GameInstance::Load(_game_saveload_version));
if ((CompanyID)SlIterateArray() != (CompanyID)-1) SlErrorCorrupt("Too many GameScript configs");
}

@ -114,11 +114,8 @@ struct AIPLChunkHandler : ChunkHandler {
config->StringToSettings(_ai_saveload_settings);
/* Start the AI directly if it was active in the savegame */
if (Company::IsValidAiID(index)) {
AI::StartNew(index, false);
AI::Load(index, _ai_saveload_version);
}
/* Load the AI saved data */
if (Company::IsValidAiID(index)) config->SetToLoadData(AIInstance::Load(_ai_saveload_version));
}
}

@ -106,9 +106,8 @@ struct GSDTChunkHandler : ChunkHandler {
config->StringToSettings(_game_saveload_settings);
/* Start the GameScript directly if it was active in the savegame */
Game::StartNew();
Game::Load(_game_saveload_version);
/* Load the GameScript saved data */
config->SetToLoadData(GameInstance::Load(_game_saveload_version));
if (SlIterateArray() != -1) SlErrorCorrupt("Too many GameScript configs");
}

@ -26,6 +26,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match,
if (this->config_list != nullptr) delete this->config_list;
this->config_list = (info == nullptr) ? nullptr : new ScriptConfigItemList();
if (this->config_list != nullptr) this->PushExtraConfigList();
this->to_load_data.reset();
this->ClearConfigList();
@ -49,6 +50,7 @@ ScriptConfig::ScriptConfig(const ScriptConfig *config)
this->version = config->version;
this->config_list = nullptr;
this->is_random = config->is_random;
this->to_load_data.reset();
for (const auto &item : config->settings) {
this->settings[stredup(item.first)] = item.second;
@ -63,6 +65,7 @@ ScriptConfig::~ScriptConfig()
free(this->name);
this->ResetSettings();
if (this->config_list != nullptr) delete this->config_list;
this->to_load_data.reset();
}
ScriptInfo *ScriptConfig::GetInfo() const
@ -238,3 +241,14 @@ const char *ScriptConfig::GetTextfile(TextfileType type, CompanyID slot) const
return ::GetTextfile(type, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR, this->GetInfo()->GetMainScript());
}
void ScriptConfig::SetToLoadData(ScriptInstance::ScriptData *data)
{
this->to_load_data.reset(data);
}
ScriptInstance::ScriptData *ScriptConfig::GetToLoadData()
{
return this->to_load_data.get();
}

@ -16,6 +16,7 @@
#include "../core/string_compare_type.hpp"
#include "../company_type.h"
#include "../textfile_gui.h"
#include "script_instance.hpp"
/** Bitmask of flags for Script settings. */
enum ScriptConfigFlags {
@ -63,7 +64,8 @@ public:
version(-1),
info(nullptr),
config_list(nullptr),
is_random(false)
is_random(false),
to_load_data(nullptr)
{}
/**
@ -185,13 +187,17 @@ public:
*/
const char *GetTextfile(TextfileType type, CompanyID slot) const;
void SetToLoadData(ScriptInstance::ScriptData *data);
ScriptInstance::ScriptData *GetToLoadData();
protected:
const char *name; ///< Name of the Script
int version; ///< Version of the Script
class ScriptInfo *info; ///< ScriptInfo object for related to this Script version
SettingValueList settings; ///< List with all setting=>value pairs that are configure for this Script
ScriptConfigItemList *config_list; ///< List with all settings defined by this Script
bool is_random; ///< True if the AI in this slot was randomly chosen.
const char *name; ///< Name of the Script
int version; ///< Version of the Script
class ScriptInfo *info; ///< ScriptInfo object for related to this Script version
SettingValueList settings; ///< List with all setting=>value pairs that are configure for this Script
ScriptConfigItemList *config_list; ///< List with all settings defined by this Script
bool is_random; ///< True if the AI in this slot was randomly chosen.
std::unique_ptr<ScriptInstance::ScriptData> to_load_data; ///< Data to load after the Script start.
/**
* In case you have mandatory non-Script-definable config entries in your

@ -366,17 +366,6 @@ void *ScriptInstance::GetLogPointer()
* - null: No data.
*/
/** The type of the data that follows in the savegame. */
enum SQSaveLoadType {
SQSL_INT = 0x00, ///< The following data is an integer.
SQSL_STRING = 0x01, ///< The following data is an string.
SQSL_ARRAY = 0x02, ///< The following data is an array.
SQSL_TABLE = 0x03, ///< The following data is an table.
SQSL_BOOL = 0x04, ///< The following data is a boolean.
SQSL_NULL = 0x05, ///< A null variable.
SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
};
static byte _script_sl_byte; ///< Used as source/target by the script saveload code to store/load a single byte.
/** SaveLoad array that saves/loads exactly one byte. */
@ -595,14 +584,14 @@ bool ScriptInstance::IsPaused()
return this->is_paused;
}
/* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm)
/* static */ bool ScriptInstance::LoadObjects(ScriptData *data)
{
SlObject(nullptr, _script_byte);
switch (_script_sl_byte) {
case SQSL_INT: {
int64 value;
SlArray(&value, 1, (IsSavegameVersionBefore(SLV_SCRIPT_INT64) && SlXvIsFeatureMissing(XSLFI_SCRIPT_INT64)) ? SLE_FILE_I32 | SLE_VAR_I64 : SLE_INT64);
if (vm != nullptr) sq_pushinteger(vm, (SQInteger)value);
if (data != nullptr) data->push_back((SQInteger)value);
return true;
}
@ -611,37 +600,79 @@ bool ScriptInstance::IsPaused()
static char buf[std::numeric_limits<decltype(_script_sl_byte)>::max()];
SlArray(buf, _script_sl_byte, SLE_CHAR);
StrMakeValidInPlace(buf, buf + _script_sl_byte);
if (vm != nullptr) sq_pushstring(vm, buf, -1);
if (data != nullptr) data->push_back(std::string(buf));
return true;
}
case SQSL_ARRAY:
case SQSL_TABLE: {
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
while (LoadObjects(data));
return true;
}
case SQSL_BOOL: {
SlObject(nullptr, _script_byte);
if (data != nullptr) data->push_back((SQBool)(_script_sl_byte != 0));
return true;
}
case SQSL_NULL: {
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
return true;
}
case SQSL_ARRAY_TABLE_END: {
if (data != nullptr) data->push_back((SQSaveLoadType)_script_sl_byte);
return false;
}
default: SlErrorCorrupt("Invalid script data type");
}
}
/* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm, ScriptData *data)
{
ScriptDataVariant value = data->front();
data->pop_front();
if (std::holds_alternative<SQInteger>(value)) {
sq_pushinteger(vm, std::get<SQInteger>(value));
return true;
}
if (std::holds_alternative<std::string>(value)) {
sq_pushstring(vm, std::get<std::string>(value).c_str(), -1);
return true;
}
if (std::holds_alternative<SQBool>(value)) {
sq_pushbool(vm, std::get<SQBool>(value));
return true;
}
switch (std::get<SQSaveLoadType>(value)) {
case SQSL_ARRAY: {
if (vm != nullptr) sq_newarray(vm, 0);
while (LoadObjects(vm)) {
if (vm != nullptr) sq_arrayappend(vm, -2);
sq_newarray(vm, 0);
while (LoadObjects(vm, data)) {
sq_arrayappend(vm, -2);
/* The value is popped from the stack by squirrel. */
}
return true;
}
case SQSL_TABLE: {
if (vm != nullptr) sq_newtable(vm);
while (LoadObjects(vm)) {
LoadObjects(vm);
if (vm != nullptr) sq_rawset(vm, -3);
sq_newtable(vm);
while (LoadObjects(vm, data)) {
LoadObjects(vm, data);
sq_rawset(vm, -3);
/* The key (-2) and value (-1) are popped from the stack by squirrel. */
}
return true;
}
case SQSL_BOOL: {
SlObject(nullptr, _script_byte);
if (vm != nullptr) sq_pushbool(vm, (SQBool)(_script_sl_byte != 0));
return true;
}
case SQSL_NULL: {
if (vm != nullptr) sq_pushnull(vm);
sq_pushnull(vm);
return true;
}
@ -662,22 +693,35 @@ bool ScriptInstance::IsPaused()
LoadObjects(nullptr);
}
void ScriptInstance::Load(int version)
/* static */ ScriptInstance::ScriptData *ScriptInstance::Load(int version)
{
ScriptObject::ActiveInstance active(this);
if (this->engine == nullptr || version == -1) {
if (version == -1) {
LoadEmpty();
return;
return nullptr;
}
HSQUIRRELVM vm = this->engine->GetVM();
SlObject(nullptr, _script_byte);
/* Check if there was anything saved at all. */
if (_script_sl_byte == 0) return;
if (_script_sl_byte == 0) return nullptr;
ScriptData *data = new ScriptData();
data->push_back((SQInteger)version);
LoadObjects(data);
return data;
}
void ScriptInstance::LoadOnStack(ScriptData *data)
{
ScriptObject::ActiveInstance active(this);
if (data == nullptr) return;
HSQUIRRELVM vm = this->engine->GetVM();
sq_pushinteger(vm, version);
LoadObjects(vm);
ScriptDataVariant version = data->front();
data->pop_front();
sq_pushinteger(vm, std::get<SQInteger>(version));
LoadObjects(vm, data);
this->is_save_data_on_stack = true;
}

@ -10,6 +10,8 @@
#ifndef SCRIPT_INSTANCE_HPP
#define SCRIPT_INSTANCE_HPP
#include <variant>
#include <list>
#include <squirrel.h>
#include "script_suspend.hpp"
@ -21,10 +23,25 @@ static const uint SQUIRREL_MAX_DEPTH = 25; ///< The maximum recursive depth for
/** Runtime information about a script like a pointer to the squirrel vm and the current state. */
class ScriptInstance {
private:
/** The type of the data that follows in the savegame. */
enum SQSaveLoadType {
SQSL_INT = 0x00, ///< The following data is an integer.
SQSL_STRING = 0x01, ///< The following data is an string.
SQSL_ARRAY = 0x02, ///< The following data is an array.
SQSL_TABLE = 0x03, ///< The following data is an table.
SQSL_BOOL = 0x04, ///< The following data is a boolean.
SQSL_NULL = 0x05, ///< A null variable.
SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
};
public:
friend class ScriptObject;
friend class ScriptController;
typedef std::variant<SQInteger, std::string, SQBool, SQSaveLoadType> ScriptDataVariant;
typedef std::list<ScriptDataVariant> ScriptData;
/**
* Create a new script.
*/
@ -146,11 +163,18 @@ public:
static void SaveEmpty();
/**
* Load data from a savegame and store it on the stack.
* Load data from a savegame.
* @param version The version of the script when saving, or -1 if this was
* not the original script saving the game.
* @return a pointer to loaded data.
*/
void Load(int version);
static ScriptData *Load(int version);
/**
* Store loaded data on the stack.
* @param data The loaded data to store on the stack.
*/
void LoadOnStack(ScriptData *data);
/**
* Load and discard data from a savegame.
@ -295,7 +319,9 @@ private:
* Load all objects from a savegame.
* @return True if the loading was successful.
*/
static bool LoadObjects(HSQUIRRELVM vm);
static bool LoadObjects(ScriptData *data);
static bool LoadObjects(HSQUIRRELVM vm, ScriptData *data);
};
#endif /* SCRIPT_INSTANCE_HPP */

@ -167,9 +167,9 @@ void TextfileWindow::SetupScrollbars(bool force_reflow)
int y_offset = (line.top - pos) * line_height;
if (IsWidgetLowered(WID_TF_WRAPTEXT)) {
DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, line.text, TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO);
DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, line.text, TC_BLACK, SA_TOP | SA_LEFT, false, FS_MONO);
} else {
DrawString(-this->hscroll->GetPosition(), fr.right, y_offset, line.text, TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO);
DrawString(-this->hscroll->GetPosition(), fr.right, y_offset, line.text, TC_BLACK, SA_TOP | SA_LEFT, false, FS_MONO);
}
}

Loading…
Cancel
Save