Merge branch 'master' into jgrpp

# Conflicts:
#	src/network/network_server.h
#	src/pathfinder/yapf/yapf_road.cpp
#	src/viewport.cpp
pull/132/head
Jonathan G Rennison 4 years ago
commit babe98cdb1

@ -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.
* 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.");

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

@ -4,7 +4,7 @@ class Regression extends AIInfo {
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 GetVersion() { return 1; }
function GetAPIVersion() { return "1.10"; }
function GetAPIVersion() { return "1.11"; }
function GetDate() { return "2007-03-18"; }
function CreateInstance() { return "Regression"; }
}

@ -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.
* 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.");

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

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

@ -17,9 +17,9 @@
#
Name: openttd
Version: 1.10.beta2
Version: 1.11.beta1
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
License: GPL-2.0
Group: Amusements/Games/Strategy/Other

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

@ -38,7 +38,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
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=0;
@ -56,7 +56,7 @@ void sqstd_printcallstack(HSQUIRRELVM v)
break;
case OT_INTEGER:
sq_getinteger(v,-1,&i);
pf(v,"[%s] %d\n",name,i);
pf(v,"[%s] " OTTD_PRINTF64 "\n",name,i);
break;
case OT_FLOAT:
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);
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);
}
}

@ -219,7 +219,7 @@ static SQInteger base_array(HSQUIRRELVM v)
SQInteger nInitialSize = tointeger(stack_get(v,2));
SQInteger ret = 1;
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;
ret = -1;
}

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

@ -179,6 +179,7 @@ struct AIListWindow : public Window {
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_AI);
InvalidateWindowClassesData(WC_AI_SETTINGS);
DeleteWindowByClass(WC_QUERY_STRING);
InvalidateWindowClassesData(WC_TEXTFILE);
}
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)
{
const char *textfile = GetConfig(slot)->GetTextfile(file_type, slot);
this->LoadTextfile(textfile, (slot == OWNER_DEITY) ? GAME_DIR : AI_DIR);
this->OnInvalidateData();
}
void SetStringParameters(int widget) const override
{
if (widget == WID_TF_CAPTION) {
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);
}
}
};

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

@ -21,6 +21,7 @@
#include "safeguards.h"
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 */
IConsoleCmd *_iconsole_cmds; ///< list of registered commands
@ -317,13 +318,18 @@ IConsoleAlias *IConsoleAliasGet(const char *name)
* @param tokencount the number of parameters passed
* @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_stream = alias_buffer;
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++) {
switch (*cmdptr) {
case '\'': // ' will double for ""
@ -331,7 +337,7 @@ static void IConsoleAliasExec(const IConsoleAlias *alias, byte tokencount, char
break;
case ';': // Cmd separator; execute previous and start new command
IConsoleCmdExec(alias_buffer);
IConsoleCmdExec(alias_buffer, recurse_count);
alias_stream = alias_buffer;
*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
* @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;
char *tokens[ICON_TOKEN_COUNT], tokenstream[ICON_MAX_STREAMSIZE];
@ -505,7 +511,7 @@ void IConsoleCmdExec(const char *cmdstr)
t_index--;
IConsoleAlias *alias = IConsoleAliasGet(tokens[0]);
if (alias != nullptr) {
IConsoleAliasExec(alias, t_index, &tokens[1]);
IConsoleAliasExec(alias, t_index, &tokens[1], recurse_count + 1);
return;
}

@ -526,7 +526,7 @@ DEF_CONSOLE_CMD(ConClearBuffer)
* 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;
@ -550,14 +550,14 @@ static bool ConKickOrBan(const char *argv, bool ban)
if (!ban) {
/* Kick only this client, not all clients with that IP */
NetworkServerKickClient(client_id);
NetworkServerKickClient(client_id, reason);
return true;
}
/* When banning, kick+ban all clients with that IP */
n = NetworkServerKickOrBanIP(client_id, ban);
n = NetworkServerKickOrBanIP(client_id, ban, reason);
} else {
n = NetworkServerKickOrBanIP(argv, ban);
n = NetworkServerKickOrBanIP(argv, ban, reason);
}
if (n == 0) {
@ -572,28 +572,48 @@ static bool ConKickOrBan(const char *argv, bool ban)
DEF_CONSOLE_CMD(ConKick)
{
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'");
return true;
}
if (argc != 2) return false;
if (argc != 2 && argc != 3) return false;
/* No reason supplied for kicking */
if (argc == 2) return ConKickOrBan(argv[1], false, nullptr);
return ConKickOrBan(argv[1], false);
/* 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)
{
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("If the client is no longer online, you can still ban his/her IP");
return true;
}
if (argc != 2) return false;
if (argc != 2 && argc != 3) return false;
/* No reason supplied for kicking */
if (argc == 2) return ConKickOrBan(argv[1], true, nullptr);
return ConKickOrBan(argv[1], true);
/* 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)

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

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

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

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

@ -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_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_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_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_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_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_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}
@ -3477,8 +3483,17 @@ STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL :{WHITE}{CURRENC
# Industry directory
STR_INDUSTRY_DIRECTORY_CAPTION :{WHITE}Průmysl
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_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_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
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_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
STR_AI_SETTINGS_CAPTION :{WHITE}{STRING} Parametry

@ -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_BANNED :{WHITE}You are banned from this server
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_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
@ -2465,6 +2466,7 @@ STR_NETWORK_MESSAGE_MONEY_GIVEN :*** {RAW_STRING
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_REBOOT :{WHITE}The server is restarting...{}Please wait...
STR_NETWORK_MESSAGE_KICKED :*** {RAW_STRING} was kicked. Reason: ({RAW_STRING})
# Content downloading window
STR_CONTENT_TITLE :{WHITE}Content downloading

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

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

@ -15,11 +15,13 @@
#include "midifile.hpp"
#include <fluidsynth.h>
#include "../mixer.h"
#include <mutex>
static struct {
fluid_settings_t* settings; ///< FluidSynth settings handle
fluid_synth_t* synth; ///< FluidSynth synthesizer 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.
/** Factory for the FluidSynth driver. */
@ -42,12 +44,16 @@ static const char *default_sf[] = {
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);
}
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");
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 */
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. */
_midi.synth = new_fluid_synth(_midi.settings);
if (!_midi.synth) return "Could not open synth";
@ -81,19 +92,23 @@ const char *MusicDriver_FluidSynth::Start(const char * const *param)
_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;
}
void MusicDriver_FluidSynth::Stop()
{
MxSetMusicSource(nullptr);
this->StopSong();
delete_fluid_synth(_midi.synth);
delete_fluid_settings(_midi.settings);
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
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)
@ -106,6 +121,8 @@ void MusicDriver_FluidSynth::PlaySong(const MusicSongInfo &song)
return;
}
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
_midi.player = new_fluid_player(_midi.synth);
if (!_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()
{
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
if (!_midi.player) return;
fluid_player_stop(_midi.player);
@ -142,6 +161,7 @@ void MusicDriver_FluidSynth::StopSong()
bool MusicDriver_FluidSynth::IsSongPlaying()
{
std::lock_guard<std::mutex> lock{ _midi.synth_mutex };
if (!_midi.player) return false;
return fluid_player_get_status(_midi.player) == FLUID_PLAYER_PLAYING;
@ -149,6 +169,9 @@ bool MusicDriver_FluidSynth::IsSongPlaying()
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 */
/* fluidsynth's default gain is 0.2, so use this as "full
* volume". Set gain using OpenTTD's volume, as a number between 0

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

@ -776,8 +776,15 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR(Packet *p
StringID err = STR_NETWORK_ERROR_LOSTCONNECTION;
if (error < (ptrdiff_t)lengthof(network_error_strings)) err = network_error_strings[error];
ShowErrorMessage(err, INVALID_STRING_ID, WL_CRITICAL);
/* In case of kicking a client, we assume there is a kick message in the packet if we can read one byte */
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 */
if (this->status == STATUS_ACTIVE) ClientNetworkEmergencySave();

@ -76,9 +76,9 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id);
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 NetworkServerKickClient(ClientID client_id);
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban);
uint NetworkServerKickOrBanIP(const char *ip, bool ban);
void NetworkServerKickClient(ClientID client_id, const char *reason);
uint NetworkServerKickOrBanIP(ClientID client_id, bool ban, const char *reason);
uint NetworkServerKickOrBanIP(const char *ip, bool ban, const char *reason);
void NetworkInitChatMessage();
void CDECL NetworkAddChatMessage(TextColour colour, uint duration, const char *message, ...) WARN_FORMAT(3, 4);

@ -1688,12 +1688,12 @@ static WindowDesc _client_list_popup_desc(
/* Here we start to define the options out of the menu */
static void ClientList_Kick(const NetworkClientInfo *ci)
{
NetworkServerKickClient(ci->client_id);
NetworkServerKickClient(ci->client_id, nullptr);
}
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)

@ -422,13 +422,15 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendCompanyInfo()
/**
* Send an error to the client, and close its connection.
* @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];
Packet *p = new Packet(PACKET_SERVER_ERROR);
p->Send_uint8(error);
if (reason != nullptr) p->Send_string(reason);
this->SendPacket(p);
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);
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()) {
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.
* @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;
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.
* @param client_id The client to check for.
* @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.
* @param ip The IP address/range to ban/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 */
if (ban) {
@ -2177,11 +2186,16 @@ uint NetworkServerKickOrBanIP(const char *ip, bool ban)
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()) {
if (cs->client_id == CLIENT_ID_SERVER) continue;
if (cs->client_id == _redirect_console_to_client) continue;
if (cs->client_address.IsInNetmask(ip)) {
NetworkServerKickClient(cs->client_id);
NetworkServerKickClient(cs->client_id, reason);
n++;
}
}

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

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

@ -368,6 +368,16 @@ TownScopeResolver *StationResolverObject::GetTown()
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 */
case 0x82: return 50;
case 0x84: return this->st->string_id;

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

@ -44,6 +44,9 @@ static const int YAPF_SHIP_PATH_CACHE_LENGTH = 32;
/** Maximum segments of road vehicle path cache */
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
*/

@ -429,9 +429,9 @@ public:
const RoadStop *stop = st->GetPrimaryRoadStop(v);
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,
* 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;
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())) {
path_cache.td.pop_back();
path_cache.tile.pop_back();

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

@ -305,7 +305,7 @@ enum SaveLoadVersion : uint16 {
SLV_SCRIPT_MEMLIMIT, ///< 215 PR#7516 Limit on AI/GS memory consumption.
SLV_MULTITILE_DOCKS, ///< 216 PR#7380 Multiple docks per station.
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
@ -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_ALLOW_CONTROL = 1 << 11, ///< allow control codes 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;

@ -13,10 +13,12 @@
* functions may still be available if you return an older API version
* 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.
*
* \b 1.10.0
*
* API additions:
* \li AIGroup::SetPrimaryColour
* \li AIGroup::SetSecondaryColour

@ -13,10 +13,12 @@
* functions may still be available if you return an older API version
* 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.
*
* \b 1.10.0
*
* API additions:
* \li GSVehicle::BuildVehicleWithRefit
* \li GSVehicle::GetBuildWithRefitCapacity

@ -22,6 +22,7 @@
*/
#include "stdafx.h"
#include <limits>
#include "currency.h"
#include "screenshot.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
* @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
bool comma = false; // do we accept comma?
@ -196,9 +198,9 @@ static int ParseIntList(const char *p, int *items, int maxitems)
default: {
if (n == maxitems) return -1; // we don't accept that many numbers
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 (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;
p = end; // first non-number
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)
{
int items[64];
unsigned long items[64];
int i, nitems;
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;
for (i = 0; i != nelems; i++) {
switch (type) {
switch (GetVarMemType(type)) {
case SLE_VAR_BL:
case SLE_VAR_I8: v = *(const int8 *)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;
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) {
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_MANYOFMANY: MakeManyOfMany(buf, lastof(buf), sdb->many, i); break;
default: NOT_REACHED();
@ -724,7 +732,7 @@ static void IniSaveSettings(IniFile *ini, const SettingDesc *sd, const char *grp
break;
case SDT_INTLIST:
MakeIntList(buf, lastof(buf), ptr, sld->length, GetVarMemType(sld->conv));
MakeIntList(buf, lastof(buf), ptr, sld->length, sld->conv);
break;
default: NOT_REACHED();
@ -1703,7 +1711,7 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati
/* Parse parameters */
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) {
SetDParamStr(0, filename);
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);

@ -4081,7 +4081,7 @@ void StationMonthlyLoop()
void ModifyStationRatingAround(TileIndex tile, Owner owner, int amount, uint radius)
{
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++) {
GoodsEntry *ge = &st->goods[i];

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

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

Loading…
Cancel
Save