2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file script_company.cpp Implementation of ScriptCompany. */
10 #include "../../stdafx.h"
11 #include "script_company.hpp"
12 #include "script_error.hpp"
13 #include "script_companymode.hpp"
14 #include "../../company_func.h"
15 #include "../../company_base.h"
16 #include "../../company_manager_face.h"
17 #include "../../economy_func.h"
18 #include "../../object_type.h"
19 #include "../../strings_func.h"
20 #include "../../tile_map.h"
21 #include "../../string_func.h"
22 #include "../../settings_func.h"
23 #include "../../company_cmd.h"
24 #include "../../misc_cmd.h"
25 #include "../../object_cmd.h"
26 #include "../../settings_cmd.h"
27 #include "table/strings.h"
29 #include "../../safeguards.h"
31 /* static */ ScriptCompany::CompanyID
ScriptCompany::ResolveCompanyID(ScriptCompany::CompanyID company
)
33 if (company
== COMPANY_SELF
) {
34 if (!::Company::IsValidID(_current_company
)) return COMPANY_INVALID
;
35 return (CompanyID
)((uint8_t)_current_company
);
38 return ::Company::IsValidID(company
) ? company
: COMPANY_INVALID
;
41 /* static */ bool ScriptCompany::IsMine(ScriptCompany::CompanyID company
)
43 EnforceCompanyModeValid(false);
44 return ResolveCompanyID(company
) == ResolveCompanyID(COMPANY_SELF
);
47 /* static */ bool ScriptCompany::SetName(Text
*name
)
49 ScriptObjectRef
counter(name
);
51 EnforceCompanyModeValid(false);
52 EnforcePrecondition(false, name
!= nullptr);
53 const std::string
&text
= name
->GetDecodedText();
54 EnforcePreconditionEncodedText(false, text
);
55 EnforcePreconditionCustomError(false, ::Utf8StringLength(text
) < MAX_LENGTH_COMPANY_NAME_CHARS
, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG
);
57 return ScriptObject::Command
<CMD_RENAME_COMPANY
>::Do(text
);
60 /* static */ std::optional
<std::string
> ScriptCompany::GetName(ScriptCompany::CompanyID company
)
62 company
= ResolveCompanyID(company
);
63 if (company
== COMPANY_INVALID
) return std::nullopt
;
65 ::SetDParam(0, company
);
66 return GetString(STR_COMPANY_NAME
);
69 /* static */ bool ScriptCompany::SetPresidentName(Text
*name
)
71 ScriptObjectRef
counter(name
);
73 EnforceCompanyModeValid(false);
74 EnforcePrecondition(false, name
!= nullptr);
75 const std::string
&text
= name
->GetDecodedText();
76 EnforcePreconditionEncodedText(false, text
);
77 EnforcePreconditionCustomError(false, ::Utf8StringLength(text
) < MAX_LENGTH_PRESIDENT_NAME_CHARS
, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG
);
79 return ScriptObject::Command
<CMD_RENAME_PRESIDENT
>::Do(text
);
82 /* static */ std::optional
<std::string
> ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company
)
84 company
= ResolveCompanyID(company
);
85 if (company
== COMPANY_INVALID
) return std::nullopt
;
87 ::SetDParam(0, company
);
88 return GetString(STR_PRESIDENT_NAME
);
91 /* static */ bool ScriptCompany::SetPresidentGender(Gender gender
)
93 EnforceCompanyModeValid(false);
94 EnforcePrecondition(false, gender
== GENDER_MALE
|| gender
== GENDER_FEMALE
);
95 EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF
) != gender
);
97 Randomizer
&randomizer
= ScriptObject::GetRandomizer();
98 CompanyManagerFace cmf
;
99 GenderEthnicity ge
= (GenderEthnicity
)((gender
== GENDER_FEMALE
? (1 << ::GENDER_FEMALE
) : 0) | (randomizer
.Next() & (1 << ETHNICITY_BLACK
)));
100 RandomCompanyManagerFaceBits(cmf
, ge
, false, randomizer
);
102 return ScriptObject::Command
<CMD_SET_COMPANY_MANAGER_FACE
>::Do(cmf
);
105 /* static */ ScriptCompany::Gender
ScriptCompany::GetPresidentGender(CompanyID company
)
107 company
= ResolveCompanyID(company
);
108 if (company
== COMPANY_INVALID
) return GENDER_INVALID
;
110 GenderEthnicity ge
= (GenderEthnicity
)GetCompanyManagerFaceBits(Company::Get(company
)->face
, CMFV_GEN_ETHN
, GE_WM
);
111 return HasBit(ge
, ::GENDER_FEMALE
) ? GENDER_FEMALE
: GENDER_MALE
;
114 /* static */ Money
ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company
, SQInteger quarter
)
116 company
= ResolveCompanyID(company
);
117 if (company
== COMPANY_INVALID
) return -1;
118 if (quarter
> EARLIEST_QUARTER
) return -1;
119 if (quarter
< CURRENT_QUARTER
) return -1;
121 if (quarter
== CURRENT_QUARTER
) {
122 return ::Company::Get(company
)->cur_economy
.income
;
124 return ::Company::Get(company
)->old_economy
[quarter
- 1].income
;
127 /* static */ Money
ScriptCompany::GetQuarterlyExpenses(ScriptCompany::CompanyID company
, SQInteger quarter
)
129 company
= ResolveCompanyID(company
);
130 if (company
== COMPANY_INVALID
) return -1;
131 if (quarter
> EARLIEST_QUARTER
) return -1;
132 if (quarter
< CURRENT_QUARTER
) return -1;
134 if (quarter
== CURRENT_QUARTER
) {
135 return ::Company::Get(company
)->cur_economy
.expenses
;
137 return ::Company::Get(company
)->old_economy
[quarter
- 1].expenses
;
140 /* static */ SQInteger
ScriptCompany::GetQuarterlyCargoDelivered(ScriptCompany::CompanyID company
, SQInteger quarter
)
142 company
= ResolveCompanyID(company
);
143 if (company
== COMPANY_INVALID
) return -1;
144 if (quarter
> EARLIEST_QUARTER
) return -1;
145 if (quarter
< CURRENT_QUARTER
) return -1;
147 if (quarter
== CURRENT_QUARTER
) {
148 return ::Company::Get(company
)->cur_economy
.delivered_cargo
.GetSum
<OverflowSafeInt32
>();
150 return ::Company::Get(company
)->old_economy
[quarter
- 1].delivered_cargo
.GetSum
<OverflowSafeInt32
>();
153 /* static */ SQInteger
ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company
, SQInteger quarter
)
155 company
= ResolveCompanyID(company
);
156 if (company
== COMPANY_INVALID
) return -1;
157 if (quarter
> EARLIEST_QUARTER
) return -1;
158 if (quarter
<= CURRENT_QUARTER
) return -1;
160 return ::Company::Get(company
)->old_economy
[quarter
- 1].performance_history
;
163 /* static */ Money
ScriptCompany::GetQuarterlyCompanyValue(ScriptCompany::CompanyID company
, SQInteger quarter
)
165 company
= ResolveCompanyID(company
);
166 if (company
== COMPANY_INVALID
) return -1;
167 if (quarter
> EARLIEST_QUARTER
) return -1;
168 if (quarter
< CURRENT_QUARTER
) return -1;
170 if (quarter
== CURRENT_QUARTER
) {
171 return ::CalculateCompanyValue(::Company::Get(company
));
173 return ::Company::Get(company
)->old_economy
[quarter
- 1].company_value
;
177 /* static */ Money
ScriptCompany::GetBankBalance(ScriptCompany::CompanyID company
)
179 company
= ResolveCompanyID(company
);
180 if (company
== COMPANY_INVALID
) return -1;
181 /* If we return INT64_MAX as usual, overflows may occur in the script. So return a smaller value. */
182 if (_settings_game
.difficulty
.infinite_money
) return INT32_MAX
;
184 return GetAvailableMoney((::CompanyID
)company
);
187 /* static */ Money
ScriptCompany::GetLoanAmount()
189 ScriptCompany::CompanyID company
= ResolveCompanyID(COMPANY_SELF
);
190 if (company
== COMPANY_INVALID
) return -1;
192 return ::Company::Get(company
)->current_loan
;
195 /* static */ Money
ScriptCompany::GetMaxLoanAmount()
197 if (ScriptCompanyMode::IsDeity()) return _economy
.max_loan
;
199 ScriptCompany::CompanyID company
= ResolveCompanyID(COMPANY_SELF
);
200 if (company
== COMPANY_INVALID
) return -1;
202 return ::Company::Get(company
)->GetMaxLoan();
205 /* static */ bool ScriptCompany::SetMaxLoanAmountForCompany(CompanyID company
, Money amount
)
207 EnforceDeityMode(false);
208 EnforcePrecondition(false, amount
>= 0 && amount
<= (Money
)MAX_LOAN_LIMIT
);
210 company
= ResolveCompanyID(company
);
211 EnforcePrecondition(false, company
!= COMPANY_INVALID
);
212 return ScriptObject::Command
<CMD_SET_COMPANY_MAX_LOAN
>::Do((::CompanyID
)company
, amount
);
215 /* static */ bool ScriptCompany::ResetMaxLoanAmountForCompany(CompanyID company
)
217 EnforceDeityMode(false);
219 company
= ResolveCompanyID(company
);
220 EnforcePrecondition(false, company
!= COMPANY_INVALID
);
222 return ScriptObject::Command
<CMD_SET_COMPANY_MAX_LOAN
>::Do((::CompanyID
)company
, COMPANY_MAX_LOAN_DEFAULT
);
225 /* static */ Money
ScriptCompany::GetLoanInterval()
227 return LOAN_INTERVAL
;
230 /* static */ bool ScriptCompany::SetLoanAmount(Money loan
)
232 EnforceCompanyModeValid(false);
233 EnforcePrecondition(false, loan
>= 0);
234 EnforcePrecondition(false, ((int64_t)loan
% GetLoanInterval()) == 0);
235 EnforcePrecondition(false, loan
<= GetMaxLoanAmount());
236 EnforcePrecondition(false, (loan
- GetLoanAmount() + GetBankBalance(COMPANY_SELF
)) >= 0);
238 if (loan
== GetLoanAmount()) return true;
240 Money amount
= abs(loan
- GetLoanAmount());
242 if (loan
> GetLoanAmount()) {
243 return ScriptObject::Command
<CMD_INCREASE_LOAN
>::Do(LoanCommand::Amount
, amount
);
245 return ScriptObject::Command
<CMD_DECREASE_LOAN
>::Do(LoanCommand::Amount
, amount
);
249 /* static */ bool ScriptCompany::SetMinimumLoanAmount(Money loan
)
251 EnforceCompanyModeValid(false);
252 EnforcePrecondition(false, loan
>= 0);
254 Money over_interval
= (int64_t)loan
% GetLoanInterval();
255 if (over_interval
!= 0) loan
+= GetLoanInterval() - over_interval
;
257 EnforcePrecondition(false, loan
<= GetMaxLoanAmount());
261 return GetLoanAmount() == loan
;
264 /* static */ bool ScriptCompany::ChangeBankBalance(CompanyID company
, Money delta
, ExpensesType expenses_type
, TileIndex tile
)
266 EnforceDeityMode(false);
267 EnforcePrecondition(false, expenses_type
< (ExpensesType
)::EXPENSES_END
);
268 EnforcePrecondition(false, tile
== INVALID_TILE
|| ::IsValidTile(tile
));
270 company
= ResolveCompanyID(company
);
271 EnforcePrecondition(false, company
!= COMPANY_INVALID
);
273 /* Network commands only allow 0 to indicate invalid tiles, not INVALID_TILE */
274 return ScriptObject::Command
<CMD_CHANGE_BANK_BALANCE
>::Do(tile
== INVALID_TILE
? (TileIndex
)0U : tile
, delta
, (::CompanyID
)company
, (::ExpensesType
)expenses_type
);
277 /* static */ bool ScriptCompany::BuildCompanyHQ(TileIndex tile
)
279 EnforceCompanyModeValid(false);
280 EnforcePrecondition(false, ::IsValidTile(tile
));
282 return ScriptObject::Command
<CMD_BUILD_OBJECT
>::Do(tile
, OBJECT_HQ
, 0);
285 /* static */ TileIndex
ScriptCompany::GetCompanyHQ(CompanyID company
)
287 company
= ResolveCompanyID(company
);
288 if (company
== COMPANY_INVALID
) return INVALID_TILE
;
290 TileIndex loc
= ::Company::Get(company
)->location_of_HQ
;
291 return (loc
== 0) ? INVALID_TILE
: loc
;
294 /* static */ bool ScriptCompany::SetAutoRenewStatus(bool autorenew
)
296 EnforceCompanyModeValid(false);
297 return ScriptObject::Command
<CMD_CHANGE_COMPANY_SETTING
>::Do("company.engine_renew", autorenew
? 1 : 0);
300 /* static */ bool ScriptCompany::GetAutoRenewStatus(CompanyID company
)
302 company
= ResolveCompanyID(company
);
303 if (company
== COMPANY_INVALID
) return false;
305 return ::Company::Get(company
)->settings
.engine_renew
;
308 /* static */ bool ScriptCompany::SetAutoRenewMonths(SQInteger months
)
310 EnforceCompanyModeValid(false);
311 months
= Clamp
<SQInteger
>(months
, INT16_MIN
, INT16_MAX
);
313 return ScriptObject::Command
<CMD_CHANGE_COMPANY_SETTING
>::Do("company.engine_renew_months", months
);
316 /* static */ SQInteger
ScriptCompany::GetAutoRenewMonths(CompanyID company
)
318 company
= ResolveCompanyID(company
);
319 if (company
== COMPANY_INVALID
) return 0;
321 return ::Company::Get(company
)->settings
.engine_renew_months
;
324 /* static */ bool ScriptCompany::SetAutoRenewMoney(Money money
)
326 EnforceCompanyModeValid(false);
327 EnforcePrecondition(false, money
>= 0);
328 EnforcePrecondition(false, (int64_t)money
<= UINT32_MAX
);
329 return ScriptObject::Command
<CMD_CHANGE_COMPANY_SETTING
>::Do("company.engine_renew_money", money
);
332 /* static */ Money
ScriptCompany::GetAutoRenewMoney(CompanyID company
)
334 company
= ResolveCompanyID(company
);
335 if (company
== COMPANY_INVALID
) return 0;
337 return ::Company::Get(company
)->settings
.engine_renew_money
;
340 /* static */ bool ScriptCompany::SetPrimaryLiveryColour(LiveryScheme scheme
, Colours colour
)
342 EnforceCompanyModeValid(false);
343 return ScriptObject::Command
<CMD_SET_COMPANY_COLOUR
>::Do((::LiveryScheme
)scheme
, true, (::Colours
)colour
);
346 /* static */ bool ScriptCompany::SetSecondaryLiveryColour(LiveryScheme scheme
, Colours colour
)
348 EnforceCompanyModeValid(false);
349 return ScriptObject::Command
<CMD_SET_COMPANY_COLOUR
>::Do((::LiveryScheme
)scheme
, false, (::Colours
)colour
);
352 /* static */ ScriptCompany::Colours
ScriptCompany::GetPrimaryLiveryColour(ScriptCompany::LiveryScheme scheme
)
354 if ((::LiveryScheme
)scheme
< LS_BEGIN
|| (::LiveryScheme
)scheme
>= LS_END
) return COLOUR_INVALID
;
356 const Company
*c
= ::Company::GetIfValid(_current_company
);
357 if (c
== nullptr) return COLOUR_INVALID
;
359 return (ScriptCompany::Colours
)c
->livery
[scheme
].colour1
;
362 /* static */ ScriptCompany::Colours
ScriptCompany::GetSecondaryLiveryColour(ScriptCompany::LiveryScheme scheme
)
364 if ((::LiveryScheme
)scheme
< LS_BEGIN
|| (::LiveryScheme
)scheme
>= LS_END
) return COLOUR_INVALID
;
366 const Company
*c
= ::Company::GetIfValid(_current_company
);
367 if (c
== nullptr) return COLOUR_INVALID
;
369 return (ScriptCompany::Colours
)c
->livery
[scheme
].colour2
;