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.
This commit is contained in:
Patric Stout 2023-04-16 20:14:22 +02:00 committed by GitHub
parent 43a7e54067
commit ed83c4b0da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 370 additions and 348 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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[] = {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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