Change: replace per-AI "start_date" with a global "competitors_interval" (#10653)

The per-AI "start_date" is a lot of custom code, and was rarely
used in the way it was meant.

While at it, also ported this part over to the new timer system.
pull/544/head
Patric Stout 1 year ago committed by GitHub
parent 43a7e54067
commit ed83c4b0da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -88,9 +88,9 @@
abs( 21): 21 abs( 21): 21
--AIBase-- --AIBase--
Rand(): 2232656694 Rand(): 2113409458
Rand(): 2514636170 Rand(): 2000129769
Rand(): 3897038727 Rand(): 1788051963
RandRange(0): 0 RandRange(0): 0
RandRange(0): 0 RandRange(0): 0
RandRange(0): 0 RandRange(0): 0
@ -99,13 +99,13 @@
RandRange(1): 0 RandRange(1): 0
RandRange(2): 0 RandRange(2): 0
RandRange(2): 0 RandRange(2): 0
RandRange(2): 0 RandRange(2): 1
RandRange(1000000): 666804 RandRange(1000000): 338687
RandRange(1000000): 624059 RandRange(1000000): 274895
RandRange(1000000): 697029 RandRange(1000000): 217539
Chance(1, 2): true
Chance(1, 2): false Chance(1, 2): false
Chance(1, 2): true Chance(1, 2): true
Chance(1, 2): false
--List-- --List--
IsEmpty(): true IsEmpty(): true
@ -420,144 +420,144 @@
1098 => 46116 1098 => 46116
1099 => 46158 1099 => 46158
Randomize ListDump: Randomize ListDump:
1 => 688298322 1 => 1667006376
2 => 2585420314 2 => 814756458
1000 => 1701392078 1000 => 2792131700
1001 => 2664118875 1001 => 3417650573
1002 => 3408466361 1002 => 1856129988
1003 => 4098642324 1003 => 1800973341
1004 => 3858929894 1004 => 4197962148
1005 => 3774625512 1005 => 2463509731
1006 => 2809742492 1006 => 2312121797
1007 => 3983931060 1007 => 1357932132
1008 => 2791524857 1008 => 1603755907
1009 => 4184021601 1009 => 1718096015
1010 => 4212142121 1010 => 3850074449
1011 => 46859773 1011 => 2711130211
1012 => 3095744278 1012 => 2371249199
1013 => 3104411371 1013 => 881020769
1014 => 326384434 1014 => 3366660077
1015 => 1486817960 1015 => 808768948
1016 => 2883541699 1016 => 3035331984
1017 => 3786540442 1017 => 2813590961
1018 => 820019294 1018 => 2745021820
1019 => 710762995 1019 => 3075151719
1020 => 3534100264 1020 => 2553774560
1021 => 3585356150 1021 => 4267762096
1022 => 732190215 1022 => 3863175846
1023 => 236336673 1023 => 4198397908
1024 => 740596257 1024 => 817599906
1025 => 1135321785 1025 => 3149240362
1026 => 2067474156 1026 => 3003005979
1027 => 2899283689 1027 => 1214815375
1028 => 4054438597 1028 => 3784363817
1029 => 928616892 1029 => 3181864540
1030 => 1712486685 1030 => 325341059
1031 => 1994118287 1031 => 1011889231
1032 => 1333321243 1032 => 3142617173
1033 => 194124284 1033 => 1197220206
1034 => 615083294 1034 => 4060510885
1035 => 628086450 1035 => 3596342467
1036 => 498957825 1036 => 219406671
1037 => 1359697121 1037 => 3695508783
1038 => 1888433963 1038 => 2823603997
1039 => 941623020 1039 => 2625659720
1040 => 2369304004 1040 => 4113498476
1041 => 3523427032 1041 => 1125297786
1042 => 3236625937 1042 => 671905104
1043 => 182127597 1043 => 1231077134
1044 => 646955927 1044 => 892292375
1045 => 2870345582 1045 => 2441486929
1046 => 623062612 1046 => 1804593432
1047 => 2308011710 1047 => 2536560053
1048 => 3026140316 1048 => 1896826021
1049 => 3838191076 1049 => 1672512966
1051 => 3182411967 1051 => 977884299
1052 => 2762833244 1052 => 681948608
1053 => 1960404034 1053 => 3853505792
1054 => 1573325453 1054 => 4118706553
1055 => 3978347993 1055 => 3581698138
1056 => 699712177 1056 => 3073782502
1057 => 863274966 1057 => 1084753140
1058 => 1728276475 1058 => 2266056077
1059 => 4048271407 1059 => 1239805090
1060 => 1919485436 1060 => 1183528423
1061 => 111273464 1061 => 501361238
1062 => 125435213 1062 => 66542127
1063 => 155132602 1063 => 775638990
1064 => 4123293220 1064 => 1111474321
1065 => 655046914 1065 => 3465462871
1066 => 1577399562 1066 => 2317535037
1067 => 1028818150 1067 => 878310882
1068 => 447058239 1068 => 2231368582
1069 => 3237047027 1069 => 2353633007
1070 => 2968751973 1070 => 179259867
1071 => 4096278708 1071 => 1322707275
1072 => 1523643051 1072 => 1474105363
1073 => 231373233 1073 => 619989187
1074 => 1121759962 1074 => 3221603092
1075 => 1449439846 1075 => 2400416540
1076 => 2679696543 1076 => 3926392705
1077 => 2785673432 1077 => 1122978123
1078 => 2116903943 1078 => 3266139701
1079 => 672822173 1079 => 2948697341
1080 => 3325393385 1080 => 3262493501
1081 => 1589904755 1081 => 2200252596
1082 => 1148782015 1082 => 4091101485
1083 => 663503316 1083 => 2797438343
1084 => 933352745 1084 => 2608201933
1085 => 577717039 1085 => 2577605442
1086 => 402172048 1086 => 1178956760
1087 => 1812250453 1087 => 3047709109
1088 => 667300501 1088 => 1065186815
1089 => 2456141519 1089 => 841440515
1090 => 3438492520 1090 => 842182476
1091 => 420696035 1091 => 289059855
1092 => 2131427774 1092 => 2114106829
1093 => 3859663748 1093 => 436435334
1094 => 4134083418 1094 => 111052607
1095 => 1969629634 1095 => 81827083
1096 => 3739173141 1096 => 1961213887
1097 => 3459847605 1097 => 1374385392
1098 => 2834059387 1098 => 3255118186
1099 => 3148043212 1099 => 2245402931
KeepTop(10): KeepTop(10):
1 => 688298322 1 => 1667006376
2 => 2585420314 2 => 814756458
1000 => 1701392078 1000 => 2792131700
1001 => 2664118875 1001 => 3417650573
1002 => 3408466361 1002 => 1856129988
1003 => 4098642324 1003 => 1800973341
1004 => 3858929894 1004 => 4197962148
1005 => 3774625512 1005 => 2463509731
1006 => 2809742492 1006 => 2312121797
1007 => 3983931060 1007 => 1357932132
KeepBottom(8): KeepBottom(8):
1000 => 1701392078 1000 => 2792131700
1001 => 2664118875 1001 => 3417650573
1002 => 3408466361 1002 => 1856129988
1003 => 4098642324 1003 => 1800973341
1004 => 3858929894 1004 => 4197962148
1005 => 3774625512 1005 => 2463509731
1006 => 2809742492 1006 => 2312121797
1007 => 3983931060 1007 => 1357932132
RemoveBottom(2): RemoveBottom(2):
1000 => 1701392078 1000 => 2792131700
1001 => 2664118875 1001 => 3417650573
1002 => 3408466361 1002 => 1856129988
1003 => 4098642324 1003 => 1800973341
1004 => 3858929894 1004 => 4197962148
1005 => 3774625512 1005 => 2463509731
RemoveTop(2): RemoveTop(2):
1002 => 3408466361 1002 => 1856129988
1003 => 4098642324 1003 => 1800973341
1004 => 3858929894 1004 => 4197962148
1005 => 3774625512 1005 => 2463509731
RemoveList({1003, 1004}): RemoveList({1003, 1004}):
1002 => 3408466361 1002 => 1856129988
1005 => 3774625512 1005 => 2463509731
KeepList({1003, 1004, 1005}): KeepList({1003, 1004, 1005}):
1005 => 3774625512 1005 => 2463509731
AddList({1005, 4000, 4001, 4002}): AddList({1005, 4000, 4001, 4002}):
1005 => 1005 1005 => 1005
4000 => 8000 4000 => 8000
@ -588,7 +588,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
SetName(): false SetName(): false
GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE GetLastErrorString(): ERR_NAME_IS_NOT_UNIQUE
GetName(): Regression GetName(): Regression
GetPresidentName(): J. Green GetPresidentName(): F. Gribble
SetPresidentName(): true SetPresidentName(): true
GetPresidentName(): Regression AI GetPresidentName(): Regression AI
GetBankBalance(): 100000 GetBankBalance(): 100000
@ -9320,12 +9320,12 @@ ERROR: IsEnd() is invalid as Begin() is never called
GetLocation(): 33417 GetLocation(): 33417
GetEngineType(): 153 GetEngineType(): 153
GetUnitNumber(): 1 GetUnitNumber(): 1
GetAge(): 0 GetAge(): 1
GetMaxAge(): 5490 GetMaxAge(): 5490
GetAgeLeft(): 5490 GetAgeLeft(): 5489
GetCurrentSpeed(): 7 GetCurrentSpeed(): 7
GetRunningCost(): 421 GetRunningCost(): 421
GetProfitThisYear(): 0 GetProfitThisYear(): -1
GetProfitLastYear(): 0 GetProfitLastYear(): 0
GetCurrentValue(): 5947 GetCurrentValue(): 5947
GetVehicleType(): 1 GetVehicleType(): 1
@ -9335,7 +9335,7 @@ ERROR: IsEnd() is invalid as Begin() is never called
IsInDepot(): false IsInDepot(): false
GetNumWagons(): 1 GetNumWagons(): 1
GetWagonEngineType(): 153 GetWagonEngineType(): 153
GetWagonAge(): 0 GetWagonAge(): 1
GetLength(): 8 GetLength(): 8
GetOwner(): 1 GetOwner(): 1
BuildVehicle(): 14 BuildVehicle(): 14
@ -9408,11 +9408,11 @@ ERROR: IsEnd() is invalid as Begin() is never called
14 => 1 14 => 1
12 => 1 12 => 1
Age ListDump: Age ListDump:
17 => 1
16 => 1
14 => 1 14 => 1
13 => 1 13 => 1
12 => 1 12 => 1
17 => 0
16 => 0
MaxAge ListDump: MaxAge ListDump:
16 => 10980 16 => 10980
14 => 10980 14 => 10980
@ -9420,9 +9420,9 @@ ERROR: IsEnd() is invalid as Begin() is never called
13 => 5490 13 => 5490
12 => 5490 12 => 5490
AgeLeft ListDump: AgeLeft ListDump:
16 => 10979 16 => 10980
14 => 10979 14 => 10979
17 => 7319 17 => 7320
13 => 5489 13 => 5489
12 => 5489 12 => 5489
CurrentSpeed ListDump: CurrentSpeed ListDump:

Binary file not shown.

@ -19,18 +19,6 @@
*/ */
class AI { class AI {
public: public:
/**
* The default months AIs start after each other.
*/
enum StartNext {
START_NEXT_EASY = DAYS_IN_YEAR * 2,
START_NEXT_MEDIUM = DAYS_IN_YEAR,
START_NEXT_HARD = DAYS_IN_YEAR / 2,
START_NEXT_MIN = 0,
START_NEXT_MAX = 3600,
START_NEXT_DEVIATION = 60,
};
/** /**
* Is it possible to start a new AI company? * Is it possible to start a new AI company?
* @return True if a new AI company can be started. * @return True if a new AI company can be started.
@ -124,11 +112,6 @@ public:
*/ */
static void Save(CompanyID company); static void Save(CompanyID company);
/**
* Get the number of days before the next AI should start.
*/
static int GetStartNextTime();
/** Wrapper function for AIScanner::GetAIConsoleList */ /** Wrapper function for AIScanner::GetAIConsoleList */
static std::string GetConsoleList(bool newest_only = false); static std::string GetConsoleList(bool newest_only = false);
/** Wrapper function for AIScanner::GetAIConsoleLibraryList */ /** Wrapper function for AIScanner::GetAIConsoleLibraryList */

@ -16,32 +16,6 @@
#include "../safeguards.h" #include "../safeguards.h"
/** Configuration for AI start date, every AI has this setting. */
ScriptConfigItem _start_date_config = {
"start_date",
"", // STR_AI_SETTINGS_START_DELAY
AI::START_NEXT_MIN,
AI::START_NEXT_MAX,
AI::START_NEXT_MEDIUM,
AI::START_NEXT_EASY,
AI::START_NEXT_MEDIUM,
AI::START_NEXT_HARD,
AI::START_NEXT_DEVIATION,
30,
SCRIPTCONFIG_NONE,
nullptr,
false
};
AIConfig::AIConfig(const AIConfig *config) : ScriptConfig(config)
{
/* Override start_date as per AIConfig::AddRandomDeviation().
* This is necessary because the ScriptConfig constructor will instead call
* ScriptConfig::AddRandomDeviation(). */
int start_date = config->GetSetting("start_date");
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
}
/* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source) /* static */ AIConfig *AIConfig::GetConfig(CompanyID company, ScriptSettingSource source)
{ {
AIConfig **config; AIConfig **config;
@ -69,70 +43,3 @@ bool AIConfig::ResetInfo(bool force_exact_match)
this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match); this->info = (ScriptInfo *)AI::FindInfo(this->name, force_exact_match ? this->version : -1, force_exact_match);
return this->info != nullptr; return this->info != nullptr;
} }
void AIConfig::PushExtraConfigList()
{
this->config_list->push_back(_start_date_config);
}
void AIConfig::ClearConfigList()
{
/* The special casing for start_date is here to ensure that the
* start_date setting won't change even if you chose another Script. */
int start_date = this->GetSetting("start_date");
ScriptConfig::ClearConfigList();
this->SetSetting("start_date", start_date);
}
int AIConfig::GetSetting(const char *name) const
{
if (this->info == nullptr) {
SettingValueList::const_iterator it = this->settings.find(name);
if (it == this->settings.end()) {
assert(strcmp("start_date", name) == 0);
switch (GetGameSettings().script.settings_profile) {
case SP_EASY: return AI::START_NEXT_EASY;
case SP_MEDIUM: return AI::START_NEXT_MEDIUM;
case SP_HARD: return AI::START_NEXT_HARD;
case SP_CUSTOM: return AI::START_NEXT_MEDIUM;
default: NOT_REACHED();
}
}
return (*it).second;
}
return ScriptConfig::GetSetting(name);
}
void AIConfig::SetSetting(const char *name, int value)
{
if (this->info == nullptr) {
if (strcmp("start_date", name) != 0) return;
value = Clamp(value, AI::START_NEXT_MIN, AI::START_NEXT_MAX);
SettingValueList::iterator it = this->settings.find(name);
if (it != this->settings.end()) {
(*it).second = value;
} else {
this->settings[stredup(name)] = value;
}
return;
}
ScriptConfig::SetSetting(name, value);
}
void AIConfig::AddRandomDeviation()
{
int start_date = this->GetSetting("start_date");
ScriptConfig::AddRandomDeviation();
/* start_date = 0 is a special case, where random deviation does not occur.
* If start_date was not already 0, then a minimum value of 1 must apply. */
this->SetSetting("start_date", start_date != 0 ? std::max(1, this->GetSetting("start_date")) : 0);
}

@ -24,14 +24,12 @@ public:
ScriptConfig() ScriptConfig()
{} {}
AIConfig(const AIConfig *config); AIConfig(const AIConfig *config) :
ScriptConfig(config)
{}
class AIInfo *GetInfo() const; class AIInfo *GetInfo() const;
int GetSetting(const char *name) const override;
void SetSetting(const char *name, int value) override;
void AddRandomDeviation() override;
/** /**
* When ever the AI Scanner is reloaded, all infos become invalid. This * When ever the AI Scanner is reloaded, all infos become invalid. This
* function tells AIConfig about this. * function tells AIConfig about this.
@ -43,8 +41,6 @@ public:
bool ResetInfo(bool force_exact_match); bool ResetInfo(bool force_exact_match);
protected: protected:
void PushExtraConfigList() override;
void ClearConfigList() override;
ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override; ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) override;
}; };

@ -289,17 +289,6 @@
} }
} }
/* static */ int AI::GetStartNextTime()
{
/* Find the first company which doesn't exist yet */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (!Company::IsValidID(c)) return AIConfig::GetConfig(c, AIConfig::SSS_FORCE_GAME)->GetSetting("start_date");
}
/* Currently no AI can be started, check again in a year. */
return DAYS_IN_YEAR;
}
/* static */ std::string AI::GetConsoleList(bool newest_only) /* static */ std::string AI::GetConsoleList(bool newest_only)
{ {
return AI::scanner_info->GetConsoleList(newest_only); return AI::scanner_info->GetConsoleList(newest_only);

@ -35,11 +35,17 @@ static const NWidgetPart _nested_ai_config_widgets[] = {
NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND), NWidget(WWT_PANEL, COLOUR_MAUVE, WID_AIC_BACKGROUND),
NWidget(NWID_VERTICAL), SetPIP(4, 4, 4), NWidget(NWID_VERTICAL), SetPIP(4, 4, 4),
NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7), NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_NUMBER), SetDataTip(AWV_DECREASE, STR_NULL),
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE), SetDataTip(AWV_INCREASE, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_NUMBER), SetDataTip(AWV_INCREASE, STR_NULL),
NWidget(NWID_SPACER), SetMinimalSize(6, 0), NWidget(NWID_SPACER), SetMinimalSize(6, 0),
NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_AI_CONFIG_MAX_COMPETITORS, STR_NULL), SetFill(1, 0), NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_NUMBER), SetDataTip(STR_AI_CONFIG_MAX_COMPETITORS, STR_NULL), SetFill(1, 0),
EndContainer(), EndContainer(),
NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_DECREASE_INTERVAL), SetDataTip(AWV_DECREASE, STR_NULL),
NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_AIC_INCREASE_INTERVAL), SetDataTip(AWV_INCREASE, STR_NULL),
NWidget(NWID_SPACER), SetMinimalSize(6, 0),
NWidget(WWT_TEXT, COLOUR_MAUVE, WID_AIC_INTERVAL), SetDataTip(STR_AI_CONFIG_COMPETITORS_INTERVAL, STR_NULL), SetFill(1, 0),
EndContainer(),
NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(7, 0, 7),
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_UP), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_UP, STR_AI_CONFIG_MOVE_UP_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP), NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_AIC_MOVE_DOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_AI_CONFIG_MOVE_DOWN, STR_AI_CONFIG_MOVE_DOWN_TOOLTIP),
@ -106,14 +112,20 @@ struct AIConfigWindow : public Window {
case WID_AIC_NUMBER: case WID_AIC_NUMBER:
SetDParam(0, GetGameSettings().difficulty.max_no_competitors); SetDParam(0, GetGameSettings().difficulty.max_no_competitors);
break; break;
case WID_AIC_INTERVAL:
SetDParam(0, GetGameSettings().difficulty.competitors_interval);
break;
} }
} }
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
{ {
switch (widget) { switch (widget) {
case WID_AIC_DECREASE: case WID_AIC_DECREASE_NUMBER:
case WID_AIC_INCREASE: case WID_AIC_INCREASE_NUMBER:
case WID_AIC_DECREASE_INTERVAL:
case WID_AIC_INCREASE_INTERVAL:
*size = maxdim(*size, NWidgetScrollbar::GetHorizontalDimension()); *size = maxdim(*size, NWidgetScrollbar::GetHorizontalDimension());
break; break;
@ -179,10 +191,10 @@ struct AIConfigWindow : public Window {
} }
switch (widget) { switch (widget) {
case WID_AIC_DECREASE: case WID_AIC_DECREASE_NUMBER:
case WID_AIC_INCREASE: { case WID_AIC_INCREASE_NUMBER: {
int new_value; int new_value;
if (widget == WID_AIC_DECREASE) { if (widget == WID_AIC_DECREASE_NUMBER) {
new_value = std::max(0, GetGameSettings().difficulty.max_no_competitors - 1); new_value = std::max(0, GetGameSettings().difficulty.max_no_competitors - 1);
} else { } else {
new_value = std::min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1); new_value = std::min(MAX_COMPANIES - 1, GetGameSettings().difficulty.max_no_competitors + 1);
@ -191,6 +203,18 @@ struct AIConfigWindow : public Window {
break; break;
} }
case WID_AIC_DECREASE_INTERVAL:
case WID_AIC_INCREASE_INTERVAL: {
int new_value;
if (widget == WID_AIC_DECREASE_INTERVAL) {
new_value = std::max(static_cast<int>(MIN_COMPETITORS_INTERVAL), GetGameSettings().difficulty.competitors_interval - 1);
} else {
new_value = std::min(static_cast<int>(MAX_COMPETITORS_INTERVAL), GetGameSettings().difficulty.competitors_interval + 1);
}
IConsoleSetSetting("difficulty.competitors_interval", new_value);
break;
}
case WID_AIC_LIST: { // Select a slot case WID_AIC_LIST: { // Select a slot
this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget); this->selected_slot = (CompanyID)this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
this->InvalidateData(); this->InvalidateData();
@ -251,8 +275,10 @@ struct AIConfigWindow : public Window {
if (!gui_scope) return; if (!gui_scope) return;
this->SetWidgetDisabledState(WID_AIC_DECREASE, GetGameSettings().difficulty.max_no_competitors == 0); this->SetWidgetDisabledState(WID_AIC_DECREASE_NUMBER, GetGameSettings().difficulty.max_no_competitors == 0);
this->SetWidgetDisabledState(WID_AIC_INCREASE, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1); this->SetWidgetDisabledState(WID_AIC_INCREASE_NUMBER, GetGameSettings().difficulty.max_no_competitors == MAX_COMPANIES - 1);
this->SetWidgetDisabledState(WID_AIC_DECREASE_INTERVAL, GetGameSettings().difficulty.competitors_interval == MIN_COMPETITORS_INTERVAL);
this->SetWidgetDisabledState(WID_AIC_INCREASE_INTERVAL, GetGameSettings().difficulty.competitors_interval == MAX_COMPETITORS_INTERVAL);
this->SetWidgetDisabledState(WID_AIC_CHANGE, this->selected_slot == INVALID_COMPANY); this->SetWidgetDisabledState(WID_AIC_CHANGE, this->selected_slot == INVALID_COMPANY);
this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot)->GetConfigList()->size() == 0); this->SetWidgetDisabledState(WID_AIC_CONFIGURE, this->selected_slot == INVALID_COMPANY || AIConfig::GetConfig(this->selected_slot)->GetConfigList()->size() == 0);
this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1))); this->SetWidgetDisabledState(WID_AIC_MOVE_UP, this->selected_slot == INVALID_COMPANY || !IsEditable((CompanyID)(this->selected_slot - 1)));

@ -69,11 +69,6 @@ template <> const char *GetClassName<AIInfo, ST_AI>() { return "AIInfo"; }
SQInteger res = ScriptInfo::Constructor(vm, info); SQInteger res = ScriptInfo::Constructor(vm, info);
if (res != 0) return res; if (res != 0) return res;
ScriptConfigItem config = _start_date_config;
config.name = stredup(config.name);
config.description = stredup(config.description);
info->config_list.push_front(config);
if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) { if (info->engine->MethodExists(*info->SQ_instance, "MinVersionToLoad")) {
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR; if (!info->engine->CallIntegerMethod(*info->SQ_instance, "MinVersionToLoad", &info->min_loadable_version, MAX_GET_OPS)) return SQ_ERROR;
} else { } else {

@ -170,7 +170,6 @@ struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> {
Money CalculateCompanyValue(const Company *c, bool including_loan = true); Money CalculateCompanyValue(const Company *c, bool including_loan = true);
Money CalculateCompanyValueExcludingShares(const Company *c, bool including_loan = true); Money CalculateCompanyValueExcludingShares(const Company *c, bool including_loan = true);
extern uint _next_competitor_start;
extern uint _cur_company_tick_index; extern uint _cur_company_tick_index;
#endif /* COMPANY_BASE_H */ #endif /* COMPANY_BASE_H */

@ -38,6 +38,7 @@
#include "company_cmd.h" #include "company_cmd.h"
#include "timer/timer.h" #include "timer/timer.h"
#include "timer/timer_game_calendar.h" #include "timer/timer_game_calendar.h"
#include "timer/timer_game_tick.h"
#include "table/strings.h" #include "table/strings.h"
@ -50,7 +51,6 @@ CompanyID _local_company; ///< Company controlled by the human player at this
CompanyID _current_company; ///< Company currently doing an action. CompanyID _current_company; ///< Company currently doing an action.
Colours _company_colours[MAX_COMPANIES]; ///< NOSAVE: can be determined from company structs. Colours _company_colours[MAX_COMPANIES]; ///< NOSAVE: can be determined from company structs.
CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg
uint _next_competitor_start; ///< the number of ticks before the next AI is started
uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick uint _cur_company_tick_index; ///< used to generate a name for one company that doesn't have a name yet per tick
CompanyPool _company_pool("Company"); ///< Pool of companies. CompanyPool _company_pool("Company"); ///< Pool of companies.
@ -599,16 +599,10 @@ Company *DoStartupNewCompany(bool is_ai, CompanyID company = INVALID_COMPANY)
return c; return c;
} }
/** Start the next competitor now. */
void StartupCompanies()
{
_next_competitor_start = 0;
}
/** Start a new competitor company if possible. */ /** Start a new competitor company if possible. */
static bool MaybeStartNewCompany() TimeoutTimer<TimerGameTick> _new_competitor_timeout(0, []() {
{ if (_game_mode == GM_MENU || !AI::CanStartNew()) return;
if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return false; if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) return;
/* count number of competitors */ /* count number of competitors */
uint n = 0; uint n = 0;
@ -616,13 +610,26 @@ static bool MaybeStartNewCompany()
if (c->is_ai) n++; if (c->is_ai) n++;
} }
if (n < (uint)_settings_game.difficulty.max_no_competitors) { if (n >= (uint)_settings_game.difficulty.max_no_competitors) return;
/* Send a command to all clients to start up a new AI.
* Works fine for Multiplayer and Singleplayer */
return Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID );
}
return false; /* Send a command to all clients to start up a new AI.
* Works fine for Multiplayer and Singleplayer */
Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
});
/** Start of a new game. */
void StartupCompanies()
{
/* Ensure the timeout is aborted, so it doesn't fire based on information of the last game. */
_new_competitor_timeout.Abort();
/* If there is no delay till the start of the next competitor, start all competitors at the start of the game. */
if (_settings_game.difficulty.competitors_interval == 0 && _game_mode != GM_MENU && AI::CanStartNew()) {
for (auto i = 0; i < _settings_game.difficulty.max_no_competitors; i++) {
if (_networking && Company::GetNumItems() >= _settings_client.network.max_companies) break;
Command<CMD_COMPANY_CTRL>::Post(CCA_NEW_AI, INVALID_COMPANY, CRR_NONE, INVALID_CLIENT_ID);
}
}
} }
/** Initialize the pool of companies. */ /** Initialize the pool of companies. */
@ -722,20 +729,15 @@ void OnTick_Companies()
if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c); if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c);
} }
if (_next_competitor_start == 0) { if (_new_competitor_timeout.HasFired() && _game_mode != GM_MENU && AI::CanStartNew()) {
/* AI::GetStartNextTime() can return 0. */ int32 timeout = _settings_game.difficulty.competitors_interval * 60 * TICKS_PER_SECOND;
_next_competitor_start = std::max(1, AI::GetStartNextTime() * DAY_TICKS); /* If the interval is zero, check every ~10 minutes if a company went bankrupt and needs replacing. */
} if (timeout == 0) timeout = 10 * 60 * TICKS_PER_SECOND;
if (_game_mode != GM_MENU && AI::CanStartNew() && --_next_competitor_start == 0) { /* Randomize a bit when the AI is actually going to start; ranges from 87.5% .. 112.5% of indicated value. */
/* Allow multiple AIs to possibly start in the same tick. */ timeout += ScriptObject::GetRandomizer(OWNER_NONE).Next(timeout / 4) - timeout / 8;
do {
if (!MaybeStartNewCompany()) break;
/* In networking mode, we can only send a command to start but it _new_competitor_timeout.Reset(std::max(1, timeout));
* didn't execute yet, so we cannot loop. */
if (_networking) break;
} while (AI::GetStartNextTime() == 0);
} }
_cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES; _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES;

@ -42,6 +42,9 @@ static const uint MAX_LENGTH_COMPANY_NAME_CHARS = 32; ///< The maximum length
static const uint MAX_HISTORY_QUARTERS = 24; ///< The maximum number of quarters kept as performance's history static const uint MAX_HISTORY_QUARTERS = 24; ///< The maximum number of quarters kept as performance's history
static const uint MAX_COMPANY_SHARE_OWNERS = 4; ///< The maximum number of shares of a company that can be owned by another company. static const uint MAX_COMPANY_SHARE_OWNERS = 4; ///< The maximum number of shares of a company that can be owned by another company.
static const uint MIN_COMPETITORS_INTERVAL = 0; ///< The minimum interval (in minutes) between competitors.
static const uint MAX_COMPETITORS_INTERVAL = 500; ///< The maximum interval (in minutes) between competitors.
/** Define basic enum properties */ /** Define basic enum properties */
template <> struct EnumPropsT<Owner> : MakeEnumPropsT<Owner, byte, OWNER_BEGIN, OWNER_END, INVALID_OWNER> {}; template <> struct EnumPropsT<Owner> : MakeEnumPropsT<Owner, byte, OWNER_BEGIN, OWNER_END, INVALID_OWNER> {};

@ -4592,6 +4592,7 @@ STR_AI_CONFIG_RANDOM_AI :Random AI
STR_AI_CONFIG_NONE :(none) STR_AI_CONFIG_NONE :(none)
STR_AI_CONFIG_NAME_VERSION :{RAW_STRING} {YELLOW}v{NUM} STR_AI_CONFIG_NAME_VERSION :{RAW_STRING} {YELLOW}v{NUM}
STR_AI_CONFIG_MAX_COMPETITORS :{LTBLUE}Maximum no. competitors: {ORANGE}{COMMA} STR_AI_CONFIG_MAX_COMPETITORS :{LTBLUE}Maximum no. competitors: {ORANGE}{COMMA}
STR_AI_CONFIG_COMPETITORS_INTERVAL :{LTBLUE}Interval between starting of competitors: {ORANGE}{COMMA} minute{P "" s}
STR_AI_CONFIG_MOVE_UP :{BLACK}Move Up STR_AI_CONFIG_MOVE_UP :{BLACK}Move Up
STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Move selected AI up in the list STR_AI_CONFIG_MOVE_UP_TOOLTIP :{BLACK}Move selected AI up in the list
@ -4638,7 +4639,6 @@ STR_AI_SETTINGS_CAPTION_GAMESCRIPT :Game Script
STR_AI_SETTINGS_CLOSE :{BLACK}Close STR_AI_SETTINGS_CLOSE :{BLACK}Close
STR_AI_SETTINGS_RESET :{BLACK}Reset STR_AI_SETTINGS_RESET :{BLACK}Reset
STR_AI_SETTINGS_SETTING :{RAW_STRING}: {ORANGE}{STRING1} STR_AI_SETTINGS_SETTING :{RAW_STRING}: {ORANGE}{STRING1}
STR_AI_SETTINGS_START_DELAY :Number of days to start this AI after the previous one (give or take): {ORANGE}{STRING1}
# Textfile window # Textfile window

@ -70,6 +70,7 @@
#include "misc_cmd.h" #include "misc_cmd.h"
#include "timer/timer.h" #include "timer/timer.h"
#include "timer/timer_game_calendar.h" #include "timer/timer_game_calendar.h"
#include "timer/timer_game_tick.h"
#include "linkgraph/linkgraphschedule.h" #include "linkgraph/linkgraphschedule.h"
@ -1419,6 +1420,7 @@ void StateGameLoop()
BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP); BasePersistentStorageArray::SwitchMode(PSM_ENTER_GAMELOOP);
AnimateAnimatedTiles(); AnimateAnimatedTiles();
TimerManager<TimerGameCalendar>::Elapsed(1); TimerManager<TimerGameCalendar>::Elapsed(1);
TimerManager<TimerGameTick>::Elapsed(1);
RunTileLoop(); RunTileLoop();
CallVehicleTicks(); CallVehicleTicks();
CallLandscapeTick(); CallLandscapeTick();

@ -58,6 +58,8 @@
#include "../disaster_vehicle.h" #include "../disaster_vehicle.h"
#include "../ship.h" #include "../ship.h"
#include "../water.h" #include "../water.h"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "saveload_internal.h" #include "saveload_internal.h"
@ -3259,6 +3261,16 @@ bool AfterLoadGame()
for (Station *st : Station::Iterate()) UpdateStationAcceptance(st, false); for (Station *st : Station::Iterate()) UpdateStationAcceptance(st, false);
} }
if (IsSavegameVersionBefore(SLV_AI_START_DATE)) {
/* For older savegames, we don't now the actual interval; so set it to the newgame value. */
_settings_game.difficulty.competitors_interval = _settings_newgame.difficulty.competitors_interval;
/* We did load the "period" of the timer, but not the fired/elapsed. We can deduce that here. */
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
_new_competitor_timeout.storage.elapsed = 0;
_new_competitor_timeout.fired = _new_competitor_timeout.period == 0;
}
AfterLoadLabelMaps(); AfterLoadLabelMaps();
AfterLoadCompanyStats(); AfterLoadCompanyStats();
AfterLoadStoryBook(); AfterLoadStoryBook();

@ -20,6 +20,8 @@
#include "../gfx_func.h" #include "../gfx_func.h"
#include "../core/random_func.hpp" #include "../core/random_func.hpp"
#include "../fios.h" #include "../fios.h"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "../safeguards.h" #include "../safeguards.h"
@ -67,6 +69,7 @@ void ResetViewportAfterLoadGame()
} }
byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162. byte _age_cargo_skip_counter; ///< Skip aging of cargo? Used before savegame version 162.
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
static const SaveLoad _date_desc[] = { static const SaveLoad _date_desc[] = {
SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31), SLEG_CONDVAR("date", _date, SLE_FILE_U16 | SLE_VAR_I32, SL_MIN_VERSION, SLV_31),
@ -81,10 +84,14 @@ static const SaveLoad _date_desc[] = {
SLEG_VAR("random_state[0]", _random.state[0], SLE_UINT32), SLEG_VAR("random_state[0]", _random.state[0], SLE_UINT32),
SLEG_VAR("random_state[1]", _random.state[1], SLE_UINT32), SLEG_VAR("random_state[1]", _random.state[1], SLE_UINT32),
SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), SLEG_VAR("company_tick_counter", _cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32),
SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR("next_competitor_start", _next_competitor_start, SLE_UINT32, SLV_109, SL_MAX_VERSION),
SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8), SLEG_VAR("trees_tick_counter", _trees_tick_ctr, SLE_UINT8),
SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION), SLEG_CONDVAR("pause_mode", _pause_mode, SLE_UINT8, SLV_4, SL_MAX_VERSION),
/* For older savegames, we load the current value as the "period"; afterload will set the "fired" and "elapsed". */
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_109),
SLEG_CONDVAR("next_competitor_start", _new_competitor_timeout.period, SLE_UINT32, SLV_109, SLV_AI_START_DATE),
SLEG_CONDVAR("competitors_interval", _new_competitor_timeout.period, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_elapsed", _new_competitor_timeout.storage.elapsed, SLE_UINT32, SLV_AI_START_DATE, SL_MAX_VERSION),
SLEG_CONDVAR("competitors_interval_fired", _new_competitor_timeout.fired, SLE_BOOL, SLV_AI_START_DATE, SL_MAX_VERSION),
}; };
static const SaveLoad _date_check_desc[] = { static const SaveLoad _date_check_desc[] = {

@ -27,6 +27,8 @@
#include "../company_base.h" #include "../company_base.h"
#include "../disaster_vehicle.h" #include "../disaster_vehicle.h"
#include "../core/smallvec_type.hpp" #include "../core/smallvec_type.hpp"
#include "../timer/timer.h"
#include "../timer/timer_game_tick.h"
#include "saveload_internal.h" #include "saveload_internal.h"
#include "oldloader.h" #include "oldloader.h"
#include <array> #include <array>
@ -489,6 +491,7 @@ static inline uint RemapOrderIndex(uint x)
} }
extern std::vector<TileIndex> _animated_tiles; extern std::vector<TileIndex> _animated_tiles;
extern TimeoutTimer<TimerGameTick> _new_competitor_timeout;
extern char *_old_name_array; extern char *_old_name_array;
static uint32 _old_town_index; static uint32 _old_town_index;
@ -1677,7 +1680,7 @@ static const OldChunks main_chunk[] = {
OCL_ASSERT( OC_TTO, 0x496CE ), OCL_ASSERT( OC_TTO, 0x496CE ),
OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_next_competitor_start ), OCL_VAR ( OC_FILE_U16 | OC_VAR_U32, 1, &_new_competitor_timeout.period ),
OCL_CNULL( OC_TTO, 2 ), ///< available monorail bitmask OCL_CNULL( OC_TTO, 2 ), ///< available monorail bitmask

@ -351,6 +351,7 @@ enum SaveLoadVersion : uint16 {
SLV_CONSISTENT_PARTIAL_Z, ///< 306 PR#10570 Conversion from an inconsistent partial Z calculation for slopes, to one that is (more) consistent. SLV_CONSISTENT_PARTIAL_Z, ///< 306 PR#10570 Conversion from an inconsistent partial Z calculation for slopes, to one that is (more) consistent.
SLV_MORE_CARGO_AGE, ///< 307 PR#10596 Track cargo age for a longer period. SLV_MORE_CARGO_AGE, ///< 307 PR#10596 Track cargo age for a longer period.
SLV_LINKGRAPH_SECONDS, ///< 308 PR#10610 Store linkgraph update intervals in seconds instead of days. SLV_LINKGRAPH_SECONDS, ///< 308 PR#10610 Store linkgraph update intervals in seconds instead of days.
SLV_AI_START_DATE, ///< 309 PR#10653 Removal of individual AI start dates and added a generic one.
SL_MAX_VERSION, ///< Highest possible saveload version SL_MAX_VERSION, ///< Highest possible saveload version
}; };

@ -26,7 +26,6 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match,
this->is_random = is_random; this->is_random = is_random;
if (this->config_list != nullptr) delete this->config_list; if (this->config_list != nullptr) delete this->config_list;
this->config_list = (info == nullptr) ? nullptr : new ScriptConfigItemList(); this->config_list = (info == nullptr) ? nullptr : new ScriptConfigItemList();
if (this->config_list != nullptr) this->PushExtraConfigList();
this->to_load_data.reset(); this->to_load_data.reset();
this->ClearConfigList(); this->ClearConfigList();
@ -79,7 +78,6 @@ const ScriptConfigItemList *ScriptConfig::GetConfigList()
if (this->info != nullptr) return this->info->GetConfigList(); if (this->info != nullptr) return this->info->GetConfigList();
if (this->config_list == nullptr) { if (this->config_list == nullptr) {
this->config_list = new ScriptConfigItemList(); this->config_list = new ScriptConfigItemList();
this->PushExtraConfigList();
} }
return this->config_list; return this->config_list;
} }

@ -51,8 +51,6 @@ struct ScriptConfigItem {
typedef std::list<ScriptConfigItem> ScriptConfigItemList; ///< List of ScriptConfig items. typedef std::list<ScriptConfigItem> ScriptConfigItemList; ///< List of ScriptConfig items.
extern ScriptConfigItem _start_date_config;
/** /**
* Script settings. * Script settings.
*/ */
@ -127,12 +125,12 @@ public:
* @return The (default) value of the setting, or -1 if the setting was not * @return The (default) value of the setting, or -1 if the setting was not
* found. * found.
*/ */
virtual int GetSetting(const char *name) const; int GetSetting(const char *name) const;
/** /**
* Set the value of a setting for this config. * Set the value of a setting for this config.
*/ */
virtual void SetSetting(const char *name, int value); void SetSetting(const char *name, int value);
/** /**
* Reset all settings to their default value. * Reset all settings to their default value.
@ -147,7 +145,7 @@ public:
/** /**
* Randomize all settings the Script requested to be randomized. * Randomize all settings the Script requested to be randomized.
*/ */
virtual void AddRandomDeviation(); void AddRandomDeviation();
/** /**
* Is this config attached to an Script? In other words, is there a Script * Is this config attached to an Script? In other words, is there a Script
@ -202,16 +200,10 @@ protected:
bool is_random; ///< True if the AI in this slot was randomly chosen. bool is_random; ///< True if the AI in this slot was randomly chosen.
std::unique_ptr<ScriptInstance::ScriptData> to_load_data; ///< Data to load after the Script start. std::unique_ptr<ScriptInstance::ScriptData> to_load_data; ///< Data to load after the Script start.
/**
* In case you have mandatory non-Script-definable config entries in your
* list, add them to this function.
*/
virtual void PushExtraConfigList() {};
/** /**
* Routine that clears the config list. * Routine that clears the config list.
*/ */
virtual void ClearConfigList(); void ClearConfigList();
/** /**
* This function should call back to the Scanner in charge of this Config, * This function should call back to the Scanner in charge of this Config,

@ -379,14 +379,8 @@ struct ScriptSettingsWindow : public Window {
TextColour colour; TextColour colour;
uint idx = 0; uint idx = 0;
if (StrEmpty(config_item.description)) { if (StrEmpty(config_item.description)) {
if (this->slot != OWNER_DEITY && !strcmp(config_item.name, "start_date")) { str = STR_JUST_STRING;
/* Build-in translation */ colour = TC_ORANGE;
str = STR_AI_SETTINGS_START_DELAY;
colour = TC_LIGHT_BLUE;
} else {
str = STR_JUST_STRING;
colour = TC_ORANGE;
}
} else { } else {
str = STR_AI_SETTINGS_SETTING; str = STR_AI_SETTINGS_SETTING;
colour = TC_LIGHT_BLUE; colour = TC_LIGHT_BLUE;

@ -76,6 +76,7 @@ struct DifficultySettings {
byte competitor_intelligence; ///< Unused value, used to load old savegames. byte competitor_intelligence; ///< Unused value, used to load old savegames.
byte max_no_competitors; ///< the number of competitors (AIs) byte max_no_competitors; ///< the number of competitors (AIs)
uint16 competitors_interval; ///< the interval (in minutes) between adding competitors
byte number_towns; ///< the amount of towns byte number_towns; ///< the amount of towns
byte industry_density; ///< The industry density. @see IndustryDensity byte industry_density; ///< The industry density. @see IndustryDensity
uint32 max_loan; ///< the maximum initial loan uint32 max_loan; ///< the maximum initial loan

@ -57,6 +57,15 @@ interval = 1
post_cb = MaxNoAIsChange post_cb = MaxNoAIsChange
cat = SC_BASIC cat = SC_BASIC
[SDT_VAR]
var = difficulty.competitors_interval
type = SLE_UINT16
from = SLV_AI_START_DATE
def = 10
min = MIN_COMPETITORS_INTERVAL
max = MAX_COMPETITORS_INTERVAL
interval = 1
[SDT_VAR] [SDT_VAR]
var = difficulty.competitor_start_time var = difficulty.competitor_start_time
type = SLE_UINT8 type = SLE_UINT8

@ -1,6 +1,8 @@
add_files( add_files(
timer_game_calendar.cpp timer_game_calendar.cpp
timer_game_calendar.h timer_game_calendar.h
timer_game_tick.cpp
timer_game_tick.h
timer_window.cpp timer_window.cpp
timer_window.h timer_window.h
timer_manager.h timer_manager.h

@ -0,0 +1,64 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file timer_game_tick.cpp
* This file implements the timer logic for the tick-based game-timer.
*/
#include "stdafx.h"
#include "timer.h"
#include "timer_game_tick.h"
#include "safeguards.h"
template<>
void IntervalTimer<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
{
if (this->period == 0) return;
this->storage.elapsed += delta;
uint count = 0;
while (this->storage.elapsed >= this->period) {
this->storage.elapsed -= this->period;
count++;
}
if (count > 0) {
this->callback(count);
}
}
template<>
void TimeoutTimer<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
{
if (this->fired) return;
if (this->period == 0) return;
this->storage.elapsed += delta;
if (this->storage.elapsed >= this->period) {
this->callback();
this->fired = true;
}
}
template<>
void TimerManager<TimerGameTick>::Elapsed(TimerGameTick::TElapsed delta)
{
for (auto timer : TimerManager<TimerGameTick>::GetTimers()) {
timer->Elapsed(delta);
}
}
#ifdef WITH_ASSERT
template<>
void TimerManager<TimerGameTick>::Validate(TimerGameTick::TPeriod period)
{
}
#endif /* WITH_ASSERT */

@ -0,0 +1,34 @@
/*
* This file is part of OpenTTD.
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file timer_game_tick.h Definition of the tick-based game-timer */
#ifndef TIMER_GAME_TICK_H
#define TIMER_GAME_TICK_H
#include "gfx_type.h"
#include <chrono>
/** Estimation of how many ticks fit in a single second. */
static const uint TICKS_PER_SECOND = 1000 / MILLISECONDS_PER_TICK;
/**
* Timer that represents the game-ticks. It will pause when the game is paused.
*
* @note Callbacks are executed in the game-thread.
*/
class TimerGameTick {
public:
using TPeriod = uint;
using TElapsed = uint;
struct TStorage {
uint elapsed;
};
};
#endif /* TIMER_GAME_TICK_H */

@ -15,9 +15,12 @@
/** Widgets of the #AIConfigWindow class. */ /** Widgets of the #AIConfigWindow class. */
enum AIConfigWidgets { enum AIConfigWidgets {
WID_AIC_BACKGROUND, ///< Window background. WID_AIC_BACKGROUND, ///< Window background.
WID_AIC_DECREASE, ///< Decrease the number of AIs. WID_AIC_DECREASE_NUMBER, ///< Decrease the number of AIs.
WID_AIC_INCREASE, ///< Increase the number of AIs. WID_AIC_INCREASE_NUMBER, ///< Increase the number of AIs.
WID_AIC_NUMBER, ///< Number of AIs. WID_AIC_NUMBER, ///< Number of AIs.
WID_AIC_DECREASE_INTERVAL,///< Decrease the interval.
WID_AIC_INCREASE_INTERVAL,///< Increase the interval.
WID_AIC_INTERVAL, ///< Interval between time AIs start.
WID_AIC_LIST, ///< List with currently selected AIs. WID_AIC_LIST, ///< List with currently selected AIs.
WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs. WID_AIC_SCROLLBAR, ///< Scrollbar to scroll through the selected AIs.
WID_AIC_MOVE_UP, ///< Move up button. WID_AIC_MOVE_UP, ///< Move up button.

Loading…
Cancel
Save