Merge branch 'master' into jgrpp

# Conflicts:
#	src/network/network_server.h
#	src/pathfinder/yapf/yapf_road.cpp
#	src/viewport.cpp
This commit is contained in:
Jonathan G Rennison
2020-02-09 15:43:47 +00:00
43 changed files with 240 additions and 81 deletions

View File

@@ -4,3 +4,5 @@
* 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. * 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/>. * 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/>.
*/ */
AILog.Info("1.10 API compatibility in effect.");

6
bin/ai/compat_1.11.nut Normal file
View File

@@ -0,0 +1,6 @@
/*
* 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/>.
*/

View File

@@ -4,7 +4,7 @@ class Regression extends AIInfo {
function GetShortName() { return "REGR"; } function GetShortName() { return "REGR"; }
function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; } function GetDescription() { return "This runs regression-tests on some commands. On the same map the result should always be the same."; }
function GetVersion() { return 1; } function GetVersion() { return 1; }
function GetAPIVersion() { return "1.10"; } function GetAPIVersion() { return "1.11"; }
function GetDate() { return "2007-03-18"; } function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; } function CreateInstance() { return "Regression"; }
} }

View File

@@ -4,3 +4,5 @@
* 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. * 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/>. * 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/>.
*/ */
GSLog.Info("1.10 API compatibility in effect.");

6
bin/game/compat_1.11.nut Normal file
View File

@@ -0,0 +1,6 @@
/*
* 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/>.
*/

View File

@@ -1,6 +1,6 @@
@echo off @echo off
set OPENTTD_VERSION=1.10.0 set OPENTTD_VERSION=1.11.0
set OPENSFX_VERSION=0.8.0 set OPENSFX_VERSION=0.8.0
set NOSOUND_VERSION=0.8.0 set NOSOUND_VERSION=0.8.0
set OPENGFX_VERSION=1.2.0 set OPENGFX_VERSION=1.2.0

View File

@@ -17,9 +17,9 @@
# #
Name: openttd Name: openttd
Version: 1.10.beta2 Version: 1.11.beta1
Release: 0 Release: 0
%define srcver 1.10.0-beta2 %define srcver 1.11.0-beta1
Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe Summary: An open source reimplementation of Chris Sawyer's Transport Tycoon Deluxe
License: GPL-2.0 License: GPL-2.0
Group: Amusements/Games/Strategy/Other Group: Amusements/Games/Strategy/Other

View File

@@ -1,9 +1,9 @@
# Version numbers to update # Version numbers to update
!define APPV_MAJOR 1 !define APPV_MAJOR 1
!define APPV_MINOR 10 !define APPV_MINOR 11
!define APPV_MAINT 0 !define APPV_MAINT 0
!define APPV_BUILD 1 !define APPV_BUILD 0
!define APPV_EXTRA "-beta2" !define APPV_EXTRA "-beta1"
!define APPNAME "OpenTTD" ; Define application name !define APPNAME "OpenTTD" ; Define application name
!define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version !define APPVERSION "${APPV_MAJOR}.${APPV_MINOR}.${APPV_MAINT}${APPV_EXTRA}" ; Define application version

View File

@@ -38,7 +38,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
src = si.source; src = si.source;
} }
} }
pf(v,"*FUNCTION [%s()] %s line [%d]\n",fn,src,si.line); pf(v,"*FUNCTION [%s()] %s line [" OTTD_PRINTF64 "]\n",fn,src,si.line);
level++; level++;
} }
level=0; level=0;
@@ -56,7 +56,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
break; break;
case OT_INTEGER: case OT_INTEGER:
sq_getinteger(v,-1,&i); sq_getinteger(v,-1,&i);
pf(v,"[%s] %d\n",name,i); pf(v,"[%s] " OTTD_PRINTF64 "\n",name,i);
break; break;
case OT_FLOAT: case OT_FLOAT:
sq_getfloat(v,-1,&f); sq_getfloat(v,-1,&f);
@@ -134,7 +134,7 @@ void _sqstd_compiler_error(HSQUIRRELVM v,const SQChar *sErr,const SQChar *sSourc
{ {
SQPRINTFUNCTION pf = sq_getprintfunc(v); SQPRINTFUNCTION pf = sq_getprintfunc(v);
if(pf) { if(pf) {
pf(v,"%s line = (%d) column = (%d) : error %s\n",sSource,line,column,sErr); pf(v,"%s line = (" OTTD_PRINTF64 ") column = (" OTTD_PRINTF64 ") : error %s\n",sSource,line,column,sErr);
} }
} }

View File

@@ -219,7 +219,7 @@ static SQInteger base_array(HSQUIRRELVM v)
SQInteger nInitialSize = tointeger(stack_get(v,2)); SQInteger nInitialSize = tointeger(stack_get(v,2));
SQInteger ret = 1; SQInteger ret = 1;
if (nInitialSize < 0) { if (nInitialSize < 0) {
v->Raise_Error("can't create/resize array with/to size %d", nInitialSize); v->Raise_Error("can't create/resize array with/to size " OTTD_PRINTF64, nInitialSize);
nInitialSize = 0; nInitialSize = 0;
ret = -1; ret = -1;
} }

View File

@@ -122,5 +122,5 @@ void SQVM::Raise_ParamTypeError(SQInteger nparam,SQInteger typemask,SQInteger ty
StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes); StringCat(exptypes,SQString::Create(_ss(this), IdType2Name((SQObjectType)mask), -1), exptypes);
} }
} }
Raise_Error("parameter %d has an invalid type '%s' ; expected: '%s'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes)); Raise_Error("parameter " OTTD_PRINTF64 " has an invalid type '%s' ; expected: '%s'", nparam, IdType2Name((SQObjectType)type), _stringval(exptypes));
} }

View File

@@ -179,6 +179,7 @@ struct AIListWindow : public Window {
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI); InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI);
InvalidateWindowClassesData(WC_AI_SETTINGS); InvalidateWindowClassesData(WC_AI_SETTINGS);
DeleteWindowByClass(WC_QUERY_STRING); DeleteWindowByClass(WC_QUERY_STRING);
InvalidateWindowClassesData(WC_TEXTFILE);
} }
void OnClick(Point pt, int widget, int click_count) override void OnClick(Point pt, int widget, int click_count) override
@@ -640,15 +641,24 @@ struct ScriptTextfileWindow : public TextfileWindow {
ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot) ScriptTextfileWindow(TextfileType file_type, CompanyID slot) : TextfileWindow(file_type), slot(slot)
{ {
const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot); this->OnInvalidateData();
this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
} }
void SetStringParameters(int widget) const override void SetStringParameters(int widget) const override
{ {
if (widget == WID_TF_CAPTION) { if (widget == WID_TF_CAPTION) {
SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI); SetDParam(0, (slot == OWNER_DEITY) ? STR_CONTENT_TYPE_GAME_SCRIPT : STR_CONTENT_TYPE_AI);
SetDParamStr(1, GetConfig(slot)->GetName()); SetDParamStr(1, GetConfig(slot)->GetInfo()->GetName());
}
}
void OnInvalidateData(int data = 0, bool gui_scope = true) override
{
const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot);
if (textfile == nullptr) {
delete this;
} else {
this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
} }
} }
}; };

View File

@@ -27,7 +27,8 @@ static bool CheckAPIVersion(const char *api_version)
return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 || return strcmp(api_version, "0.7") == 0 || strcmp(api_version, "1.0") == 0 || strcmp(api_version, "1.1") == 0 ||
strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 || strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 ||
strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 || strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 ||
strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0; strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0 ||
strcmp(api_version, "1.11") == 0;
} }
#if defined(_WIN32) #if defined(_WIN32)

View File

@@ -21,6 +21,7 @@
#include "safeguards.h" #include "safeguards.h"
static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in one command static const uint ICON_TOKEN_COUNT = 20; ///< Maximum number of tokens in one command
static const uint ICON_MAX_RECURSE = 10; ///< Maximum number of recursion
/* console parser */ /* console parser */
IConsoleCmd *_iconsole_cmds; ///< list of registered commands IConsoleCmd *_iconsole_cmds; ///< list of registered commands
@@ -317,13 +318,18 @@ IConsoleAlias *IConsoleAliasGet(const char *name)
* @param tokencount the number of parameters passed * @param tokencount the number of parameters passed
* @param *tokens are the parameters given to the original command (0 is the first param) * @param *tokens are the parameters given to the original command (0 is the first param)
*/ */
static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT]) static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char *tokens[ICON_TOKEN_COUNT], const uint recurse_count)
{ {
char alias_buffer[ICON_MAX_STREAMSIZE] = { '\0' }; char alias_buffer[ICON_MAX_STREAMSIZE] = { '\0' };
char *alias_stream = alias_buffer; char *alias_stream = alias_buffer;
DEBUG(console, 6, "Requested command is an alias; parsing..."); DEBUG(console, 6, "Requested command is an alias; parsing...");
if (recurse_count > ICON_MAX_RECURSE) {
IConsoleError("Too many alias expansions, recursion limit reached. Aborting");
return;
}
for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) { for (const char *cmdptr = alias->cmdline; *cmdptr != '\0'; cmdptr++) {
switch (*cmdptr) { switch (*cmdptr) {
case '\'': // ' will double for "" case '\'': // ' will double for ""
@@ -331,7 +337,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
break; break;
case ';': // Cmd separator; execute previous and start new command case ';': // Cmd separator; execute previous and start new command
IConsoleCmdExec(alias_buffer); IConsoleCmdExec(alias_buffer, recurse_count);
alias_stream = alias_buffer; alias_stream = alias_buffer;
*alias_stream = '\0'; // Make sure the new command is terminated. *alias_stream = '\0'; // Make sure the new command is terminated.
@@ -391,7 +397,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
} }
} }
IConsoleCmdExec(alias_buffer); IConsoleCmdExec(alias_buffer, recurse_count);
} }
/** /**
@@ -399,7 +405,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
* individual tokens (separated by spaces), then execute it if possible * individual tokens (separated by spaces), then execute it if possible
* @param cmdstr string to be parsed and executed * @param cmdstr string to be parsed and executed
*/ */
void IConsoleCmdExec(const char *cmdstr) void IConsoleCmdExec(const char *cmdstr, const uint recurse_count)
{ {
const char *cmdptr; const char *cmdptr;
char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE]; char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
@@ -505,7 +511,7 @@ void IConsoleCmdExec(const char *cmdstr)
t_index--; t_index--;
IConsoleAlias *alias = IConsoleAliasGet(tokens[0]); IConsoleAlias *alias = IConsoleAliasGet(tokens[0]);
if (alias != nullptr) { if (alias != nullptr) {
IConsoleAliasExec(alias, t_index, &tokens[1]); IConsoleAliasExec(alias, t_index, &tokens[1], recurse_count + 1);
return; return;
} }

View File

@@ -526,7 +526,7 @@ DEF_CONSOLE_CMD(ConClearBuffer)
* Network Core Console Commands * Network Core Console Commands
**********************************/ **********************************/
static bool ConKickOrBan(const char *argv, bool ban) static bool ConKickOrBan(const char *argv, bool ban, const char *reason)
{ {
uint n; uint n;
@@ -550,14 +550,14 @@ static bool ConKickOrBan(const char *argv, bool ban)
if (!ban) { if (!ban) {
/* Kick only this client, not all clients with that IP */ /* Kick only this client, not all clients with that IP */
NetworkServerKickClient(client_id); NetworkServerKickClient(client_id, reason);
return true; return true;
} }
/* When banning, kick+ban all clients with that IP */ /* When banning, kick+ban all clients with that IP */
n = NetworkServerKickOrBanIP(client_id, ban); n = NetworkServerKickOrBanIP(client_id, ban, reason);
} else { } else {
n = NetworkServerKickOrBanIP(argv, ban); n = NetworkServerKickOrBanIP(argv, ban, reason);
} }
if (n == 0) { if (n == 0) {
@@ -572,28 +572,48 @@ static bool ConKickOrBan(const char *argv, bool ban)
DEF_CONSOLE_CMD(ConKick) DEF_CONSOLE_CMD(ConKick)
{ {
if (argc == 0) { if (argc == 0) {
IConsoleHelp("Kick a client from a network game. Usage: 'kick <ip | client-id>'"); IConsoleHelp("Kick a client from a network game. Usage: 'kick <ip | client-id> [<kick-reason>]'");
IConsoleHelp("For client-id's, see the command 'clients'"); IConsoleHelp("For client-id's, see the command 'clients'");
return true; return true;
} }
if (argc != 2) return false; if (argc != 2 && argc != 3) return false;
return ConKickOrBan(argv[1], false); /* No reason supplied for kicking */
if (argc == 2) return ConKickOrBan(argv[1], false, nullptr);
/* Reason for kicking supplied */
size_t kick_message_length = strlen(argv[2]);
if (kick_message_length >= 255) {
IConsolePrintF(CC_ERROR, "ERROR: Maximum kick message length is 254 characters. You entered %d characters.", kick_message_length);
return false;
} else {
return ConKickOrBan(argv[1], false, argv[2]);
}
} }
DEF_CONSOLE_CMD(ConBan) DEF_CONSOLE_CMD(ConBan)
{ {
if (argc == 0) { if (argc == 0) {
IConsoleHelp("Ban a client from a network game. Usage: 'ban <ip | client-id>'"); IConsoleHelp("Ban a client from a network game. Usage: 'ban <ip | client-id> [<ban-reason>]'");
IConsoleHelp("For client-id's, see the command 'clients'"); IConsoleHelp("For client-id's, see the command 'clients'");
IConsoleHelp("If the client is no longer online, you can still ban his/her IP"); IConsoleHelp("If the client is no longer online, you can still ban his/her IP");
return true; return true;
} }
if (argc != 2) return false; if (argc != 2 && argc != 3) return false;
return ConKickOrBan(argv[1], true); /* No reason supplied for kicking */
if (argc == 2) return ConKickOrBan(argv[1], true, nullptr);
/* Reason for kicking supplied */
size_t kick_message_length = strlen(argv[2]);
if (kick_message_length >= 255) {
IConsolePrintF(CC_ERROR, "ERROR: Maximum kick message length is 254 characters. You entered %d characters.", kick_message_length);
return false;
} else {
return ConKickOrBan(argv[1], true, argv[2]);
}
} }
DEF_CONSOLE_CMD(ConUnBan) DEF_CONSOLE_CMD(ConUnBan)

View File

@@ -28,7 +28,7 @@ void IConsoleWarning(const char *string);
void IConsoleError(const char *string); void IConsoleError(const char *string);
/* Parser */ /* Parser */
void IConsoleCmdExec(const char *cmdstr); void IConsoleCmdExec(const char *cmdstr, const uint recurse_count = 0);
bool IsValidConsoleColour(TextColour c); bool IsValidConsoleColour(TextColour c);

View File

@@ -28,6 +28,8 @@ INSTANTIATE_POOL_METHODS(Depot)
*/ */
Depot::~Depot() Depot::~Depot()
{ {
free(this->name);
if (CleaningPool()) return; if (CleaningPool()) return;
if (!IsDepotTile(this->xy) || GetDepotIndex(this->xy) != this->index) { if (!IsDepotTile(this->xy) || GetDepotIndex(this->xy) != this->index) {

View File

@@ -24,7 +24,8 @@ static bool CheckAPIVersion(const char *api_version)
{ {
return strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 || return strcmp(api_version, "1.2") == 0 || strcmp(api_version, "1.3") == 0 || strcmp(api_version, "1.4") == 0 ||
strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 || strcmp(api_version, "1.5") == 0 || strcmp(api_version, "1.6") == 0 || strcmp(api_version, "1.7") == 0 ||
strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0; strcmp(api_version, "1.8") == 0 || strcmp(api_version, "1.9") == 0 || strcmp(api_version, "1.10") == 0 ||
strcmp(api_version, "1.11") == 0;
} }
#if defined(_WIN32) #if defined(_WIN32)

View File

@@ -1102,6 +1102,7 @@ public:
} }
this->groups.ForceRebuild(); this->groups.ForceRebuild();
this->BuildGroupList(this->owner); this->BuildGroupList(this->owner);
this->group_sb->SetCount((uint)this->groups.size());
id_g = find_index(this->groups, g); id_g = find_index(this->groups, g);
} }
this->group_sb->ScrollTowards(id_g); this->group_sb->ScrollTowards(id_g);

View File

@@ -1395,6 +1395,8 @@ STR_CONFIG_SETTING_POPULATION_IN_LABEL :Zobrazovat popu
STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Zobrazovat městskou populaci u názvu města na mapě STR_CONFIG_SETTING_POPULATION_IN_LABEL_HELPTEXT :Zobrazovat městskou populaci u názvu města na mapě
STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Tloušťky čar v grafech: {STRING} STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS :Tloušťky čar v grafech: {STRING}
STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Tloušťka čáry v grafech. Tenká čára se čte přesněji, silnější je lépe viditelná a barva je snadněji rozpoznatelná. STR_CONFIG_SETTING_GRAPH_LINE_THICKNESS_HELPTEXT :Tloušťka čáry v grafech. Tenká čára se čte přesněji, silnější je lépe viditelná a barva je snadněji rozpoznatelná.
STR_CONFIG_SETTING_SHOW_NEWGRF_NAME :Zobrazovat název NewGRF v okně nákupu vozidel: {STRING}
STR_CONFIG_SETTING_SHOW_NEWGRF_NAME_HELPTEXT :Přidá řádek do okna nákupu vozidel informující, ze které NewGRF vybrané vozidlo pochází.
STR_CONFIG_SETTING_LANDSCAPE :Klima: {STRING} STR_CONFIG_SETTING_LANDSCAPE :Klima: {STRING}
STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Klima určuje základy herního scénáře s rozdílnými druhy nákladu a požadavky na růst měst. Nové GRaFiky a Herní Skripty umožní ještě jemnější kontrolu STR_CONFIG_SETTING_LANDSCAPE_HELPTEXT :Klima určuje základy herního scénáře s rozdílnými druhy nákladu a požadavky na růst měst. Nové GRaFiky a Herní Skripty umožní ještě jemnější kontrolu
@@ -1632,6 +1634,10 @@ STR_CONFIG_SETTING_NEWS_MESSAGES_FULL :Plná
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Barevné noviny se objeví v roce: {STRING} STR_CONFIG_SETTING_COLOURED_NEWS_YEAR :Barevné noviny se objeví v roce: {STRING}
STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Rok od kterého budou novinová oznámeni zobrazena v barvách. Před tímto rokem jsou černobílá. STR_CONFIG_SETTING_COLOURED_NEWS_YEAR_HELPTEXT :Rok od kterého budou novinová oznámeni zobrazena v barvách. Před tímto rokem jsou černobílá.
STR_CONFIG_SETTING_STARTING_YEAR :Počáteční datum: {STRING} STR_CONFIG_SETTING_STARTING_YEAR :Počáteční datum: {STRING}
STR_CONFIG_SETTING_ENDING_YEAR :Rok vyhodnocení: {STRING}
STR_CONFIG_SETTING_ENDING_YEAR_HELPTEXT :Rok, kdy je ve hře uzavřeno hodnocení společností. Na konci tohoto roku je zaznamenáno skóre společností a je zobrazena tabulka nejlepších společností, ale ve hře je možné pokračovat i dál.{}Pokud je nastaven rok před rokem počátku hry, tabulka s hodnocením nebude zobrazena nikdy.
STR_CONFIG_SETTING_ENDING_YEAR_VALUE :{NUM}
STR_CONFIG_SETTING_ENDING_YEAR_ZERO :Nikdy
STR_CONFIG_SETTING_SMOOTH_ECONOMY :Plynulé změny ekonomiky (více menších změn): {STRING} STR_CONFIG_SETTING_SMOOTH_ECONOMY :Plynulé změny ekonomiky (více menších změn): {STRING}
STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Pokud je zapnuto, produkce průmyslu se mění častěji ale změny jsou menší. Toto nastavení většinou nemá vliv na průmysl, který je přidaný novou grafikou STR_CONFIG_SETTING_SMOOTH_ECONOMY_HELPTEXT :Pokud je zapnuto, produkce průmyslu se mění častěji ale změny jsou menší. Toto nastavení většinou nemá vliv na průmysl, který je přidaný novou grafikou
STR_CONFIG_SETTING_ALLOW_SHARES :Povolit kupování podílu z ostatních společností: {STRING} STR_CONFIG_SETTING_ALLOW_SHARES :Povolit kupování podílu z ostatních společností: {STRING}
@@ -3477,8 +3483,17 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENC
# Industry directory # Industry directory
STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Průmysl STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Průmysl
STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Nic - STR_INDUSTRY_DIRECTORY_NONE :{ORANGE}- Nic -
STR_INDUSTRY_DIRECTORY_ITEM_INFO :{BLACK}{CARGO_LONG}{STRING}{YELLOW} ({COMMA}% přepraveno){BLACK}
STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY} STR_INDUSTRY_DIRECTORY_ITEM_NOPROD :{ORANGE}{INDUSTRY}
STR_INDUSTRY_DIRECTORY_ITEM_PROD1 :{ORANGE}{INDUSTRY} {STRING}
STR_INDUSTRY_DIRECTORY_ITEM_PROD2 :{ORANGE}{INDUSTRY} {STRING}, {STRING}
STR_INDUSTRY_DIRECTORY_ITEM_PROD3 :{ORANGE}{INDUSTRY} {STRING}, {STRING}, {STRING}
STR_INDUSTRY_DIRECTORY_ITEM_PRODMORE :{ORANGE}{INDUSTRY} {STRING}, {STRING}, {STRING} a {NUM} další...
STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Název průmyslu - pohled na něj zaměříš kliknutím na jeho jméno. Při stisknutém Ctrl otevřeš nový pohled STR_INDUSTRY_DIRECTORY_LIST_CAPTION :{BLACK}Název průmyslu - pohled na něj zaměříš kliknutím na jeho jméno. Při stisknutém Ctrl otevřeš nový pohled
STR_INDUSTRY_DIRECTORY_ACCEPTED_CARGO_FILTER :{BLACK}Přijímá náklad: {SILVER}{STRING}
STR_INDUSTRY_DIRECTORY_PRODUCED_CARGO_FILTER :{BLACK}Produkuje náklad: {SILVER}{STRING}
STR_INDUSTRY_DIRECTORY_FILTER_ALL_TYPES :Všechny druhy nákladu
STR_INDUSTRY_DIRECTORY_FILTER_NONE :Žádný
# Industry view # Industry view
STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY} STR_INDUSTRY_VIEW_CAPTION :{WHITE}{INDUSTRY}
@@ -4256,6 +4271,13 @@ STR_AI_LIST_ACCEPT_TOOLTIP :{BLACK}Vybrat o
STR_AI_LIST_CANCEL :{BLACK}Zrušit STR_AI_LIST_CANCEL :{BLACK}Zrušit
STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Neměňte skript STR_AI_LIST_CANCEL_TOOLTIP :{BLACK}Neměňte skript
STR_SCREENSHOT_CAPTION :{WHITE}Pořídit snímek obrazovky
STR_SCREENSHOT_SCREENSHOT :{BLACK}Běžný snímek obrazovky
STR_SCREENSHOT_ZOOMIN_SCREENSHOT :{BLACK}Snímek obrazovky v úplném přiblížení
STR_SCREENSHOT_DEFAULTZOOM_SCREENSHOT :{BLACK}Snímek obrazovky ve výchozím přiblížení
STR_SCREENSHOT_WORLD_SCREENSHOT :{BLACK}Snímek celé mapy
STR_SCREENSHOT_HEIGHTMAP_SCREENSHOT :{BLACK}Snímek výškové mapy
STR_SCREENSHOT_MINIMAP_SCREENSHOT :{BLACK}Snímek (náhledové) mapy světa
# AI Parameters # AI Parameters
STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametry STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametry

View File

@@ -2402,6 +2402,7 @@ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Wrong pa
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full STR_NETWORK_ERROR_SERVER_FULL :{WHITE}The server is full
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}You are banned from this server
STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game STR_NETWORK_ERROR_KICKED :{WHITE}You were kicked out of the game
STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Reason: {RAW_STRING}
STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server STR_NETWORK_ERROR_CHEATER :{WHITE}Cheating is not allowed on this server
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}You were sending too many commands to the server
STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}You took too long to enter the password
@@ -2465,6 +2466,7 @@ STR_NETWORK_MESSAGE_MONEY_GIVEN :*** {RAW_STRING
STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION :{RAW_STRING} ({COMPANY}) STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION :{RAW_STRING} ({COMPANY})
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}The server closed the session
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait... STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}The server is restarting...{}Please wait...
STR_NETWORK_MESSAGE_KICKED :*** {RAW_STRING} was kicked. Reason: ({RAW_STRING})
# Content downloading window # Content downloading window
STR_CONTENT_TITLE :{WHITE}Content downloading STR_CONTENT_TITLE :{WHITE}Content downloading

View File

@@ -799,8 +799,8 @@ STR_NEWS_FIRST_SHIP_ARRIVAL :{BIG_FONT}{BLAC
STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}시민들이 축하하고 있습니다 . . .{}{STATION}에 처음으로 항공기가 도착했습니다! STR_NEWS_FIRST_AIRCRAFT_ARRIVAL :{BIG_FONT}{BLACK}시민들이 축하하고 있습니다 . . .{}{STATION}에 처음으로 항공기가 도착했습니다!
STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}열차 충돌 사고!{}충돌로 인한 폭발로 {COMMA}명의 사망자가 발생하였습니다! STR_NEWS_TRAIN_CRASH :{BIG_FONT}{BLACK}열차 충돌 사고!{}충돌로 인한 폭발로 {COMMA}명의 사망자가 발생하였습니다!
STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}차량 충돌!{}열차와의 충돌로 인해 운전자가 사망했습니다! STR_NEWS_ROAD_VEHICLE_CRASH_DRIVER :{BIG_FONT}{BLACK}차량 충돌!{}열차 충돌로 운전자가 사망했습니다!
STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}차량 충돌!{}열차와의 충돌로 {COMMA}명이 사망했습니다! STR_NEWS_ROAD_VEHICLE_CRASH :{BIG_FONT}{BLACK}차량 충돌!{}열차 충돌로 {COMMA}명이 사망했습니다!
STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}항공기 충돌사고 발생!{}{COMMA}명이 {STATION}공항에서 사망하였습니다! STR_NEWS_AIRCRAFT_CRASH :{BIG_FONT}{BLACK}항공기 충돌사고 발생!{}{COMMA}명이 {STATION}공항에서 사망하였습니다!
STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}항공기 추락사고 발생!{}연료 부족으로 인하여 {COMMA}명이 사망하였습니다! STR_NEWS_PLANE_CRASH_OUT_OF_FUEL :{BIG_FONT}{BLACK}항공기 추락사고 발생!{}연료 부족으로 인하여 {COMMA}명이 사망하였습니다!
@@ -1739,7 +1739,7 @@ STR_CONFIG_SETTING_TOWN_LAYOUT_BETTER_ROADS :개선된 도
STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 칸 STR_CONFIG_SETTING_TOWN_LAYOUT_2X2_GRID :2x2 칸
STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 칸 STR_CONFIG_SETTING_TOWN_LAYOUT_3X3_GRID :3x3 칸
STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :무작위 STR_CONFIG_SETTING_TOWN_LAYOUT_RANDOM :무작위
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :도시 스스로 도로 건설 허용: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_ROADS :도시 스스로 도로 건설하는 것을 허용: {STRING}
STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :도시가 성장하기 위해 도로를 건설할 수 있도록 허용합니다. 도시 당국이 스스로 도로를 만들지 못하도록 하려면 이 설정을 끄십시오. STR_CONFIG_SETTING_ALLOW_TOWN_ROADS_HELPTEXT :도시가 성장하기 위해 도로를 건설할 수 있도록 허용합니다. 도시 당국이 스스로 도로를 만들지 못하도록 하려면 이 설정을 끄십시오.
STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :도시가 회사 소유의 선로에 건널목을 만드는 것을 허용: {STRING} STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS :도시가 회사 소유의 선로에 건널목을 만드는 것을 허용: {STRING}
STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :도시가 회사 소유의 선로에 건널목을 건설할 수 있도록 허용합니다. STR_CONFIG_SETTING_ALLOW_TOWN_LEVEL_CROSSINGS_HELPTEXT :도시가 회사 소유의 선로에 건널목을 건설할 수 있도록 허용합니다.
@@ -2369,7 +2369,7 @@ STR_COMPANY_PASSWORD_MAKE_DEFAULT_TOOLTIP :{BLACK}이 회
STR_COMPANY_VIEW_JOIN :{BLACK}참여 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 :{BLACK}암호
STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}다른 참가자가 이 회사로의 플레이하지 못하도록 암호로 보호합니다 STR_COMPANY_VIEW_PASSWORD_TOOLTIP :{BLACK}다른 참가자가 이 회사에 참여하여 플레이하지 못 하도록 암호로 보호합니다
STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}회사 암호 설정 STR_COMPANY_VIEW_SET_PASSWORD :{BLACK}회사 암호 설정
# Network chat # Network chat
@@ -2402,6 +2402,7 @@ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}잘못
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}서버에 인원이 가득 찼습니다 STR_NETWORK_ERROR_SERVER_FULL :{WHITE}서버에 인원이 가득 찼습니다
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}서버 관리자에 의해 접속이 차단되었습니다 STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}서버 관리자에 의해 접속이 차단되었습니다
STR_NETWORK_ERROR_KICKED :{WHITE}서버에서 강제로 추방되었습니다 STR_NETWORK_ERROR_KICKED :{WHITE}서버에서 강제로 추방되었습니다
STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}사유: {STRING}
STR_NETWORK_ERROR_CHEATER :{WHITE}이 서버에서 치트를 사용할 수 없습니다 STR_NETWORK_ERROR_CHEATER :{WHITE}이 서버에서 치트를 사용할 수 없습니다
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}서버에 너무 많은 명령을 보냈습니다 STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}서버에 너무 많은 명령을 보냈습니다
STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}비밀번호 입력 시간을 초과하였습니다 STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}비밀번호 입력 시간을 초과하였습니다
@@ -2465,6 +2466,7 @@ STR_NETWORK_MESSAGE_MONEY_GIVEN :*** {STRING}
STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION :{STRING} ({COMPANY}) STR_NETWORK_MESSAGE_MONEY_GIVE_SRC_DESCRIPTION :{STRING} ({COMPANY})
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}서버가 게임을 종료하였습니다 STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}서버가 게임을 종료하였습니다
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}서버가 재시작되고 있습니다...{}기다려주세요... STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}서버가 재시작되고 있습니다...{}기다려주세요...
STR_NETWORK_MESSAGE_KICKED :*** {STRING} - 서버에서 강제로 추방되었습니다. 사유: ({STRING})
# Content downloading window # Content downloading window
STR_CONTENT_TITLE :{WHITE}콘텐츠 다운로드 STR_CONTENT_TITLE :{WHITE}콘텐츠 다운로드

View File

@@ -2320,6 +2320,7 @@ STR_NETWORK_ERROR_WRONG_PASSWORD :{WHITE}Неве
STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Сервер переполнен STR_NETWORK_ERROR_SERVER_FULL :{WHITE}Сервер переполнен
STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Вас забанили на этом сервере STR_NETWORK_ERROR_SERVER_BANNED :{WHITE}Вас забанили на этом сервере
STR_NETWORK_ERROR_KICKED :{WHITE}Вас выкинули из игры STR_NETWORK_ERROR_KICKED :{WHITE}Вас выкинули из игры
STR_NETWORK_ERROR_KICK_MESSAGE :{WHITE}Причина: {STRING}
STR_NETWORK_ERROR_CHEATER :{WHITE}Чит-коды не разрешены на этом сервере STR_NETWORK_ERROR_CHEATER :{WHITE}Чит-коды не разрешены на этом сервере
STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Вы посылали на сервер слишком много команд STR_NETWORK_ERROR_TOO_MANY_COMMANDS :{WHITE}Вы посылали на сервер слишком много команд
STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Вы не успели ввести пароль STR_NETWORK_ERROR_TIMEOUT_PASSWORD :{WHITE}Вы не успели ввести пароль
@@ -2379,6 +2380,7 @@ STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} п
STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Вы передали {1:STRING} {2:CURRENCY_LONG} STR_NETWORK_MESSAGE_GAVE_MONEY_AWAY :*** Вы передали {1:STRING} {2:CURRENCY_LONG}
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Сервер закрыл сессию STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Сервер закрыл сессию
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Сервер перезапускается...{}Пожалуйста, подождите... STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Сервер перезапускается...{}Пожалуйста, подождите...
STR_NETWORK_MESSAGE_KICKED :*** {STRING} был исключён из игры. Причина: ({STRING})
# Content downloading window # Content downloading window
STR_CONTENT_TITLE :{WHITE}Загрузка контента STR_CONTENT_TITLE :{WHITE}Загрузка контента

View File

@@ -15,11 +15,13 @@
#include "midifile.hpp" #include "midifile.hpp"
#include <fluidsynth.h> #include <fluidsynth.h>
#include "../mixer.h" #include "../mixer.h"
#include <mutex>
static struct { static struct {
fluid_settings_t* settings; ///< FluidSynth settings handle fluid_settings_t* settings; ///< FluidSynth settings handle
fluid_synth_t* synth; ///< FluidSynth synthesizer handle fluid_synth_t* synth; ///< FluidSynth synthesizer handle
fluid_player_t* player; ///< FluidSynth MIDI player handle fluid_player_t* player; ///< FluidSynth MIDI player handle
std::mutex synth_mutex; ///< Guard mutex for synth access
} _midi; ///< Metadata about the midi we're playing. } _midi; ///< Metadata about the midi we're playing.
/** Factory for the FluidSynth driver. */ /** Factory for the FluidSynth driver. */
@@ -42,12 +44,16 @@ static const char *default_sf[] = {
static void RenderMusicStream(int16 *buffer, size_t samples) static void RenderMusicStream(int16 *buffer, size_t samples)
{ {
if (!_midi.synth || !_midi.player) return; std::unique_lock<std::mutex> lock{ _midi.synth_mutex, std::try_to_lock };
if (!lock.owns_lock() || !_midi.synth || !_midi.player) return;
fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2); fluid_synth_write_s16(_midi.synth, samples, buffer, 0, 2, buffer, 1, 2);
} }
const char *MusicDriver_FluidSynth::Start(const char * const *param) const char *MusicDriver_FluidSynth::Start(const char * const *param)
{ {
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
const char *sfont_name = GetDriverParam(param, "soundfont"); const char *sfont_name = GetDriverParam(param, "soundfont");
int sfont_id; int sfont_id;
@@ -59,6 +65,11 @@ const char *MusicDriver_FluidSynth::Start(const char * const *param)
/* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */ /* Don't try to lock sample data in memory, OTTD usually does not run with privileges allowing that */
fluid_settings_setint(_midi.settings, "synth.lock-memory", 0); fluid_settings_setint(_midi.settings, "synth.lock-memory", 0);
/* Install the music render routine and set up the samplerate */
uint32 samplerate = MxSetMusicSource(RenderMusicStream);
fluid_settings_setnum(_midi.settings, "synth.sample-rate", samplerate);
DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate);
/* Create the synthesizer. */ /* Create the synthesizer. */
_midi.synth = new_fluid_synth(_midi.settings); _midi.synth = new_fluid_synth(_midi.settings);
if (!_midi.synth) return "Could not open synth"; if (!_midi.synth) return "Could not open synth";
@@ -81,19 +92,23 @@ const char *MusicDriver_FluidSynth::Start(const char * const *param)
_midi.player = nullptr; _midi.player = nullptr;
uint32 samplerate = MxSetMusicSource(RenderMusicStream);
fluid_synth_set_sample_rate(_midi.synth, samplerate);
DEBUG(driver, 1, "Fluidsynth: samplerate %.0f", (float)samplerate);
return nullptr; return nullptr;
} }
void MusicDriver_FluidSynth::Stop() void MusicDriver_FluidSynth::Stop()
{ {
MxSetMusicSource(nullptr); MxSetMusicSource(nullptr);
this->StopSong();
delete_fluid_synth(_midi.synth); std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
delete_fluid_settings(_midi.settings);
if (_midi.player != nullptr) delete_fluid_player(_midi.player);
_midi.player = nullptr;
if (_midi.synth != nullptr) delete_fluid_synth(_midi.synth);
_midi.synth = nullptr;
if (_midi.settings != nullptr) delete_fluid_settings(_midi.settings);
_midi.settings = nullptr;
} }
void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song) void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
@@ -106,6 +121,8 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
return; return;
} }
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
_midi.player = new_fluid_player(_midi.synth); _midi.player = new_fluid_player(_midi.synth);
if (!_midi.player) { if (!_midi.player) {
DEBUG(driver, 0, "Could not create midi player"); DEBUG(driver, 0, "Could not create midi player");
@@ -128,6 +145,8 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
void MusicDriver_FluidSynth::StopSong() void MusicDriver_FluidSynth::StopSong()
{ {
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);
@@ -142,6 +161,7 @@ void MusicDriver_FluidSynth::StopSong()
bool MusicDriver_FluidSynth::IsSongPlaying() bool MusicDriver_FluidSynth::IsSongPlaying()
{ {
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
if (!_midi.player) return false; if (!_midi.player) return false;
return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING; return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING;
@@ -149,6 +169,9 @@ bool MusicDriver_FluidSynth::IsSongPlaying()
void MusicDriver_FluidSynth::SetVolume(byte vol) void MusicDriver_FluidSynth::SetVolume(byte vol)
{ {
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
if (_midi.settings == nullptr) return;
/* Allowed range of synth.gain is 0.0 to 10.0 */ /* Allowed range of synth.gain is 0.0 to 10.0 */
/* fluidsynth's default gain is 0.2, so use this as "full /* fluidsynth's default gain is 0.2, so use this as "full
* volume". Set gain using OpenTTD's volume, as a number between 0 * volume". Set gain using OpenTTD's volume, as a number between 0

View File

@@ -267,6 +267,7 @@ void NetworkTextMessage(NetworkAction action, TextColour colour, bool self_send,
case NETWORK_ACTION_CHAT_COMPANY: strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break; case NETWORK_ACTION_CHAT_COMPANY: strid = self_send ? STR_NETWORK_CHAT_TO_COMPANY : STR_NETWORK_CHAT_COMPANY; break;
case NETWORK_ACTION_CHAT_CLIENT: strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT; break; case NETWORK_ACTION_CHAT_CLIENT: strid = self_send ? STR_NETWORK_CHAT_TO_CLIENT : STR_NETWORK_CHAT_CLIENT; break;
case NETWORK_ACTION_KICKED: strid = STR_NETWORK_MESSAGE_KICKED; break;
default: strid = STR_NETWORK_CHAT_ALL; break; default: strid = STR_NETWORK_CHAT_ALL; break;
} }

View File

@@ -776,8 +776,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
StringID err = STR_NETWORK_ERROR_LOSTCONNECTION; StringID err = STR_NETWORK_ERROR_LOSTCONNECTION;
if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error]; if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
/* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL); if (error == NETWORK_ERROR_KICKED && p->CanReadFromPacket(1)) {
char kick_msg[255];
p->Recv_string(kick_msg, sizeof(kick_msg));
SetDParamStr(0, kick_msg);
ShowErrorMessage(err, STR_NETWORK_ERROR_KICK_MESSAGE, WL_CRITICAL);
} else {
ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL);
}
/* Perform an emergency save if we had already entered the game */ /* Perform an emergency save if we had already entered the game */
if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave(); if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave();

View File

@@ -76,9 +76,9 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string); void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const char *string);
void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, ClientID from_id, NetworkTextMessageData data = NetworkTextMessageData(), bool from_admin = false); void NetworkServerSendChat(NetworkAction action, DestType type, int dest, const char *msg, ClientID from_id, NetworkTextMessageData data = NetworkTextMessageData(), bool from_admin = false);
void NetworkServerKickClient(ClientID client_id); void NetworkServerKickClient(ClientID client_id, const char *reason);
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban); uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const char *reason);
uint NetworkServerKickOrBanIP(const char *ip, bool ban); uint NetworkServerKickOrBanIP(const char *ip, bool ban, const char *reason);
void NetworkInitChatMessage(); void NetworkInitChatMessage();
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) WARN_FORMAT(3, 4); void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) WARN_FORMAT(3, 4);

View File

@@ -1688,12 +1688,12 @@ static WindowDesc _client_list_popup_desc(
/* Here we start to define the options out of the menu */ /* Here we start to define the options out of the menu */
static void ClientList_Kick(const NetworkClientInfo *ci) static void ClientList_Kick(const NetworkClientInfo *ci)
{ {
NetworkServerKickClient(ci->client_id); NetworkServerKickClient(ci->client_id, nullptr);
} }
static void ClientList_Ban(const NetworkClientInfo *ci) static void ClientList_Ban(const NetworkClientInfo *ci)
{ {
NetworkServerKickOrBanIP(ci->client_id, true); NetworkServerKickOrBanIP(ci->client_id, true, nullptr);
} }
static void ClientList_SpeakToClient(const NetworkClientInfo *ci) static void ClientList_SpeakToClient(const NetworkClientInfo *ci)

View File

@@ -422,13 +422,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
/** /**
* Send an error to the client, and close its connection. * Send an error to the client, and close its connection.
* @param error The error to disconnect for. * @param error The error to disconnect for.
* @param reason In case of kicking a client, specifies the reason for kicking the client.
*/ */
NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error) NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode error, const char *reason)
{ {
char str[100]; char str[100];
Packet *p = new Packet(PACKET_SERVER_ERROR); Packet *p = new Packet(PACKET_SERVER_ERROR);
p->Send_uint8(error); p->Send_uint8(error);
if (reason != nullptr) p->Send_string(reason);
this->SendPacket(p); this->SendPacket(p);
StringID strid = GetNetworkErrorMsg(error); StringID strid = GetNetworkErrorMsg(error);
@@ -442,7 +444,11 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendError(NetworkErrorCode err
DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str); DEBUG(net, 1, "'%s' made an error and has been disconnected. Reason: '%s'", client_name, str);
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid); if (error == NETWORK_ERROR_KICKED && reason != nullptr) {
NetworkTextMessage(NETWORK_ACTION_KICKED, CC_DEFAULT, false, client_name, reason, strid);
} else {
NetworkTextMessage(NETWORK_ACTION_LEAVE, CC_DEFAULT, false, client_name, nullptr, strid);
}
for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) { for (NetworkClientSocket *new_cs : NetworkClientSocket::Iterate()) {
if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) { if (new_cs->status > STATUS_AUTHORIZED && new_cs != this) {
@@ -2139,29 +2145,32 @@ void NetworkServerSendRcon(ClientID client_id, TextColour colour_code, const cha
/** /**
* Kick a single client. * Kick a single client.
* @param client_id The client to kick. * @param client_id The client to kick.
* @param reason In case of kicking a client, specifies the reason for kicking the client.
*/ */
void NetworkServerKickClient(ClientID client_id) void NetworkServerKickClient(ClientID client_id, const char *reason)
{ {
if (client_id == CLIENT_ID_SERVER) return; if (client_id == CLIENT_ID_SERVER) return;
NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED); NetworkClientSocket::GetByClientID(client_id)->SendError(NETWORK_ERROR_KICKED, reason);
} }
/** /**
* Ban, or kick, everyone joined from the given client's IP. * Ban, or kick, everyone joined from the given client's IP.
* @param client_id The client to check for. * @param client_id The client to check for.
* @param ban Whether to ban or kick. * @param ban Whether to ban or kick.
* @param reason In case of kicking a client, specifies the reason for kicking the client.
*/ */
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban) uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const char *reason)
{ {
return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban); return NetworkServerKickOrBanIP(NetworkClientSocket::GetByClientID(client_id)->GetClientIP(), ban, reason);
} }
/** /**
* Kick or ban someone based on an IP address. * Kick or ban someone based on an IP address.
* @param ip The IP address/range to ban/kick. * @param ip The IP address/range to ban/kick.
* @param ban Whether to ban or just kick. * @param ban Whether to ban or just kick.
* @param reason In case of kicking a client, specifies the reason for kicking the client.
*/ */
uint NetworkServerKickOrBanIP(const char *ip, bool ban) uint NetworkServerKickOrBanIP(const char *ip, bool ban, const char *reason)
{ {
/* Add address to ban-list */ /* Add address to ban-list */
if (ban) { if (ban) {
@@ -2177,11 +2186,16 @@ uint NetworkServerKickOrBanIP(const char *ip, bool ban)
uint n = 0; uint n = 0;
/* There can be multiple clients with the same IP, kick them all */ /* There can be multiple clients with the same IP, kick them all but don't kill the server,
* or the client doing the rcon. The latter can't be kicked because kicking frees closes
* and subsequently free the connection related instances, which we would be reading from
* and writing to after returning. So we would read or write data from freed memory up till
* the segfault triggers. */
for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) { for (NetworkClientSocket *cs : NetworkClientSocket::Iterate()) {
if (cs->client_id == CLIENT_ID_SERVER) continue; if (cs->client_id == CLIENT_ID_SERVER) continue;
if (cs->client_id == _redirect_console_to_client) continue;
if (cs->client_address.IsInNetmask(ip)) { if (cs->client_address.IsInNetmask(ip)) {
NetworkServerKickClient(cs->client_id); NetworkServerKickClient(cs->client_id, reason);
n++; n++;
} }
} }

View File

@@ -98,7 +98,7 @@ public:
NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id); NetworkRecvStatus SendMove(ClientID client_id, CompanyID company_id);
NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci); NetworkRecvStatus SendClientInfo(NetworkClientInfo *ci);
NetworkRecvStatus SendError(NetworkErrorCode error); NetworkRecvStatus SendError(NetworkErrorCode error, const char *reason = nullptr);
NetworkRecvStatus SendDesyncLog(const std::string &log); NetworkRecvStatus SendDesyncLog(const std::string &log);
NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, NetworkTextMessageData data); NetworkRecvStatus SendChat(NetworkAction action, ClientID client_id, bool self_send, const char *msg, NetworkTextMessageData data);
NetworkRecvStatus SendJoin(ClientID client_id); NetworkRecvStatus SendJoin(ClientID client_id);

View File

@@ -86,6 +86,7 @@ enum DestType {
enum NetworkAction { enum NetworkAction {
NETWORK_ACTION_JOIN, NETWORK_ACTION_JOIN,
NETWORK_ACTION_LEAVE, NETWORK_ACTION_LEAVE,
NETWORK_ACTION_KICKED,
NETWORK_ACTION_SERVER_MESSAGE, NETWORK_ACTION_SERVER_MESSAGE,
NETWORK_ACTION_CHAT, NETWORK_ACTION_CHAT,
NETWORK_ACTION_CHAT_COMPANY, NETWORK_ACTION_CHAT_COMPANY,

View File

@@ -368,6 +368,16 @@ TownScopeResolver *StationResolverObject::GetTown()
return res; return res;
} }
case 0x6A: { // GRFID of nearby station tiles
TileIndex nearby_tile = GetNearbyTile(parameter, this->tile);
if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF;
if (!IsCustomStationSpecIndex(nearby_tile)) return 0;
const StationSpecList ssl = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)];
return ssl.grfid;
}
/* General station variables */ /* General station variables */
case 0x82: return 50; case 0x82: return 50;
case 0x84: return this->st->string_id; case 0x84: return this->st->string_id;

View File

@@ -77,8 +77,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,10,0,!!ISODATE!! FILEVERSION 1,11,0,!!ISODATE!!
PRODUCTVERSION 1,10,0,!!ISODATE!! PRODUCTVERSION 1,11,0,!!ISODATE!!
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L

View File

@@ -44,6 +44,9 @@ static const int YAPF_SHIP_PATH_CACHE_LENGTH = 32;
/** Maximum segments of road vehicle path cache */ /** Maximum segments of road vehicle path cache */
static const int YAPF_ROADVEH_PATH_CACHE_SEGMENTS = 16; static const int YAPF_ROADVEH_PATH_CACHE_SEGMENTS = 16;
/** Distance from destination road stops to not cache any further */
static const int YAPF_ROADVEH_PATH_CACHE_DESTINATION_LIMIT = 8;
/** /**
* Helper container to find a depot * Helper container to find a depot
*/ */

View File

@@ -429,9 +429,9 @@ public:
const RoadStop *stop = st->GetPrimaryRoadStop(v); const RoadStop *stop = st->GetPrimaryRoadStop(v);
if (stop != nullptr && (IsDriveThroughStopTile(stop->xy) || stop->GetNextRoadStop(v) != nullptr)) { if (stop != nullptr && (IsDriveThroughStopTile(stop->xy) || stop->GetNextRoadStop(v) != nullptr)) {
/* Destination station has at least 2 usable road stops, or first is a drive-through stop, /* Destination station has at least 2 usable road stops, or first is a drive-through stop,
* trim end of path cache within 8 tiles of road stop tile area */ * trim end of path cache within a number of tiles of road stop tile area */
TileArea non_cached_area = v->IsBus() ? st->bus_station : st->truck_station; TileArea non_cached_area = v->IsBus() ? st->bus_station : st->truck_station;
non_cached_area.Expand(8); non_cached_area.Expand(YAPF_ROADVEH_PATH_CACHE_DESTINATION_LIMIT);
while (!path_cache.empty() && non_cached_area.Contains(path_cache.tile.back())) { while (!path_cache.empty() && non_cached_area.Contains(path_cache.tile.back())) {
path_cache.td.pop_back(); path_cache.td.pop_back();
path_cache.tile.pop_back(); path_cache.tile.pop_back();

View File

@@ -91,4 +91,4 @@ const byte _openttd_revision_tagged = !!ISTAG!!;
* final release will always have a lower version number than the released * final release will always have a lower version number than the released
* version, thus making comparisons on specific revisions easy. * version, thus making comparisons on specific revisions easy.
*/ */
const uint32 _openttd_newgrf_version = 1 << 28 | 10 << 24 | 0 << 20 | !!ISSTABLETAG!! << 19 | 28004; const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 0 << 20 | !!ISSTABLETAG!! << 19 | 28004;

View File

@@ -305,7 +305,7 @@ enum SaveLoadVersion : uint16 {
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption. SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station. SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age. SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age.
SLV_ENDING_YEAR, ///< 218 PR#7747 Configurable ending year. SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year.
SL_MAX_VERSION, ///< Highest possible saveload version SL_MAX_VERSION, ///< Highest possible saveload version
@@ -506,7 +506,8 @@ enum VarTypes {
SLF_NO_NETWORK_SYNC = 1 << 10, ///< do not synchronize over network (but it is saved if SLF_NOT_IN_SAVE is not set) SLF_NO_NETWORK_SYNC = 1 << 10, ///< do not synchronize over network (but it is saved if SLF_NOT_IN_SAVE is not set)
SLF_ALLOW_CONTROL = 1 << 11, ///< allow control codes in the strings SLF_ALLOW_CONTROL = 1 << 11, ///< allow control codes in the strings
SLF_ALLOW_NEWLINE = 1 << 12, ///< allow new lines in the strings SLF_ALLOW_NEWLINE = 1 << 12, ///< allow new lines in the strings
/* 3 more possible flags */ SLF_HEX = 1 << 13, ///< print numbers as hex in the config file (only useful for unsigned)
/* 2 more possible flags */
}; };
typedef uint32 VarType; typedef uint32 VarType;

View File

@@ -13,10 +13,12 @@
* functions may still be available if you return an older API version * functions may still be available if you return an older API version
* in GetAPIVersion() in info.nut. * in GetAPIVersion() in info.nut.
* *
* \b 1.10.0 * \b 1.11.0
* *
* This version is not yet released. The following changes are not set in stone yet. * This version is not yet released. The following changes are not set in stone yet.
* *
* \b 1.10.0
*
* API additions: * API additions:
* \li AIGroup::SetPrimaryColour * \li AIGroup::SetPrimaryColour
* \li AIGroup::SetSecondaryColour * \li AIGroup::SetSecondaryColour

View File

@@ -13,10 +13,12 @@
* functions may still be available if you return an older API version * functions may still be available if you return an older API version
* in GetAPIVersion() in info.nut. * in GetAPIVersion() in info.nut.
* *
* \b 1.10.0 * \b 1.11.0
* *
* This version is not yet released. The following changes are not set in stone yet. * This version is not yet released. The following changes are not set in stone yet.
* *
* \b 1.10.0
*
* API additions: * API additions:
* \li GSVehicle::BuildVehicleWithRefit * \li GSVehicle::BuildVehicleWithRefit
* \li GSVehicle::GetBuildWithRefitCapacity * \li GSVehicle::GetBuildWithRefitCapacity

View File

@@ -22,6 +22,7 @@
*/ */
#include "stdafx.h" #include "stdafx.h"
#include <limits>
#include "currency.h" #include "currency.h"
#include "screenshot.h" #include "screenshot.h"
#include "network/network.h" #include "network/network.h"
@@ -176,7 +177,8 @@ static size_t LookupManyOfMany(const char *many, const char *str)
* @param maxitems the maximum number of elements the integerlist-array has * @param maxitems the maximum number of elements the integerlist-array has
* @return returns the number of items found, or -1 on an error * @return returns the number of items found, or -1 on an error
*/ */
static int ParseIntList(const char *p, int *items, int maxitems) template<typename T>
static int ParseIntList(const char *p, T *items, int maxitems)
{ {
int n = 0; // number of items read so far int n = 0; // number of items read so far
bool comma = false; // do we accept comma? bool comma = false; // do we accept comma?
@@ -196,9 +198,9 @@ static int ParseIntList(const char *p, int *items, int maxitems)
default: { default: {
if (n == maxitems) return -1; // we don't accept that many numbers if (n == maxitems) return -1; // we don't accept that many numbers
char *end; char *end;
long v = strtol(p, &end, 0); unsigned long v = strtoul(p, &end, 0);
if (p == end) return -1; // invalid character (not a number) if (p == end) return -1; // invalid character (not a number)
if (sizeof(int) < sizeof(long)) v = ClampToI32(v); if (sizeof(T) < sizeof(v)) v = Clamp<unsigned long>(v, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
items[n++] = v; items[n++] = v;
p = end; // first non-number p = end; // first non-number
comma = true; // we accept comma now comma = true; // we accept comma now
@@ -224,7 +226,7 @@ static int ParseIntList(const char *p, int *items, int maxitems)
*/ */
static bool LoadIntList(const char *str, void *array, int nelems, VarType type) static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
{ {
int items[64]; unsigned long items[64];
int i, nitems; int i, nitems;
if (str == nullptr) { if (str == nullptr) {
@@ -273,7 +275,7 @@ static void MakeIntList(char *buf, const char *last, const void *array, int nele
const byte *p = (const byte *)array; const byte *p = (const byte *)array;
for (i = 0; i != nelems; i++) { for (i = 0; i != nelems; i++) {
switch (type) { switch (GetVarMemType(type)) {
case SLE_VAR_BL: case SLE_VAR_BL:
case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break; case SLE_VAR_I8: v = *(const int8 *)p; p += 1; break;
case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break; case SLE_VAR_U8: v = *(const uint8 *)p; p += 1; break;
@@ -283,7 +285,13 @@ static void MakeIntList(char *buf, const char *last, const void *array, int nele
case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break; case SLE_VAR_U32: v = *(const uint32 *)p; p += 4; break;
default: NOT_REACHED(); default: NOT_REACHED();
} }
buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v); if (IsSignedVarMemType(type)) {
buf += seprintf(buf, last, (i == 0) ? "%d" : ",%d", v);
} else if (type & SLF_HEX) {
buf += seprintf(buf, last, (i == 0) ? "0x%X" : ",0x%X", v);
} else {
buf += seprintf(buf, last, (i == 0) ? "%u" : ",%u", v);
}
} }
} }
@@ -696,7 +704,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp
switch (sdb->cmd) { switch (sdb->cmd) {
case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break; case SDT_BOOLX: strecpy(buf, (i != 0) ? "true" : "false", lastof(buf)); break;
case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : "%u", i); break; case SDT_NUMX: seprintf(buf, lastof(buf), IsSignedVarMemType(sld->conv) ? "%d" : (sld->conv & SLF_HEX) ? "%X" : "%u", i); break;
case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break; case SDT_ONEOFMANY: MakeOneOfMany(buf, lastof(buf), sdb->many, i); break;
case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break; case SDT_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break;
default: NOT_REACHED(); default: NOT_REACHED();
@@ -724,7 +732,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp
break; break;
case SDT_INTLIST: case SDT_INTLIST:
MakeIntList(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv)); MakeIntList(buf, lastof(buf), ptr, sld->length, sld->conv);
break; break;
default: NOT_REACHED(); default: NOT_REACHED();
@@ -1703,7 +1711,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati
/* Parse parameters */ /* Parse parameters */
if (!StrEmpty(item->value)) { if (!StrEmpty(item->value)) {
int count = ParseIntList(item->value, (int*)c->param, lengthof(c->param)); int count = ParseIntList(item->value, c->param, lengthof(c->param));
if (count < 0) { if (count < 0) {
SetDParamStr(0, filename); SetDParamStr(0, filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL); ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);

View File

@@ -4081,7 +4081,7 @@ void StationMonthlyLoop()
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius) void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
{ {
ForAllStationsRadius(tile, radius, [&](Station *st) { ForAllStationsRadius(tile, radius, [&](Station *st) {
if (st->owner == owner) { if (st->owner == owner && DistanceManhattan(tile, st->xy) <= radius) {
for (CargoID i = 0; i < NUM_CARGO; i++) { for (CargoID i = 0; i < NUM_CARGO; i++) {
GoodsEntry *ge = &st->goods[i]; GoodsEntry *ge = &st->goods[i];

View File

@@ -45,6 +45,7 @@ var = engine_renew
def = false def = false
str = STR_CONFIG_SETTING_AUTORENEW_VEHICLE str = STR_CONFIG_SETTING_AUTORENEW_VEHICLE
strhelp = STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT strhelp = STR_CONFIG_SETTING_AUTORENEW_VEHICLE_HELPTEXT
cat = SC_BASIC
[SDT_VAR] [SDT_VAR]
base = CompanySettings base = CompanySettings

View File

@@ -176,6 +176,7 @@ static const NIVariable _niv_stations[] = {
NIV(0x67, "land info of nearby tiles"), NIV(0x67, "land info of nearby tiles"),
NIV(0x68, "station info of nearby tiles"), NIV(0x68, "station info of nearby tiles"),
NIV(0x69, "information about cargo accepted in the past"), NIV(0x69, "information about cargo accepted in the past"),
NIV(0x6A, "GRFID of nearby station tiles"),
NIV_END() NIV_END()
}; };