Add: [GS] Allow to set max loan for each company separately (#11224)

This commit is contained in:
dP 2024-01-30 23:45:19 +05:30 committed by GitHub
parent b370ae1212
commit 897b59c158
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 129 additions and 20 deletions

View File

@ -253,6 +253,7 @@ enum Commands : uint16_t {
CMD_INCREASE_LOAN, ///< increase the loan from the bank
CMD_DECREASE_LOAN, ///< decrease the loan from the bank
CMD_SET_COMPANY_MAX_LOAN, ///< sets the max loan for the company
CMD_WANT_ENGINE_PREVIEW, ///< confirm the preview of an engine
CMD_ENGINE_CTRL, ///< control availability of the engine for companies

View File

@ -18,6 +18,8 @@
#include "settings_type.h"
#include "group.h"
static const Money COMPANY_MAX_LOAN_DEFAULT = INT64_MIN;
/** Statistics about the economy. */
struct CompanyEconomyEntry {
Money income; ///< The amount of income.
@ -50,7 +52,6 @@ struct CompanyInfrastructure {
typedef Pool<Company, CompanyID, 1, MAX_COMPANIES> CompanyPool;
extern CompanyPool _company_pool;
/** Statically loadable part of Company pool item */
struct CompanyProperties {
uint32_t name_2; ///< Parameter of #name_1.
@ -66,6 +67,7 @@ struct CompanyProperties {
Money money; ///< Money owned by the company.
byte money_fraction; ///< Fraction of money of the company, too small to represent in #money.
Money current_loan; ///< Amount of money borrowed from the bank.
Money max_loan; ///< Max allowed amount of the loan or COMPANY_MAX_LOAN_DEFAULT.
Colours colour; ///< Company colour.
@ -105,8 +107,8 @@ struct CompanyProperties {
// TODO: Change some of these member variables to use relevant INVALID_xxx constants
CompanyProperties()
: name_2(0), name_1(0), president_name_1(0), president_name_2(0),
face(0), money(0), money_fraction(0), current_loan(0), colour(COLOUR_BEGIN), block_preview(0),
location_of_HQ(0), last_build_coordinate(0), inaugurated_year(0),
face(0), money(0), money_fraction(0), current_loan(0), max_loan(COMPANY_MAX_LOAN_DEFAULT),
colour(COLOUR_BEGIN), block_preview(0), location_of_HQ(0), last_build_coordinate(0), inaugurated_year(0),
months_of_bankruptcy(0), bankrupt_asked(0), bankrupt_timeout(0), bankrupt_value(0),
terraform_limit(0), clear_limit(0), tree_limit(0), build_object_limit(0), is_ai(false), engine_renew_list(nullptr) {}
};
@ -126,6 +128,8 @@ struct Company : CompanyProperties, CompanyPool::PoolItem<&_company_pool> {
CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure.
Money GetMaxLoan() const;
/**
* Is this company a valid company, controlled by the computer (a NoAI program)?
* @param index Index in the pool.

View File

@ -95,6 +95,16 @@ void Company::PostDestructor(size_t index)
InvalidateWindowData(WC_ERRMSG, 0);
}
/**
* Calculate the max allowed loan for this company.
* @return the max loan amount.
*/
Money Company::GetMaxLoan() const
{
if (this->max_loan == COMPANY_MAX_LOAN_DEFAULT) return _economy.max_loan;
return this->max_loan;
}
/**
* Sets the local company and updates the settings that are set on a
* per-company basis to reflect the core's state in the GUI.

View File

@ -374,9 +374,11 @@ struct CompanyFinancesWindow : Window {
SetDParam(0, _settings_game.difficulty.initial_interest);
break;
case WID_CF_MAXLOAN_VALUE:
SetDParam(0, _economy.max_loan);
case WID_CF_MAXLOAN_VALUE: {
const Company *c = Company::Get((CompanyID)this->window_number);
SetDParam(0, c->GetMaxLoan());
break;
}
case WID_CF_INCREASE_LOAN:
case WID_CF_REPAY_LOAN:
@ -474,7 +476,7 @@ struct CompanyFinancesWindow : Window {
}
const Company *c = Company::Get(company);
this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan == _economy.max_loan); // Borrow button only shows when there is any more money to loan.
this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan >= c->GetMaxLoan()); // Borrow button only shows when there is any more money to loan.
this->SetWidgetDisabledState(WID_CF_REPAY_LOAN, company != _local_company || c->current_loan == 0); // Repay button only shows when there is any more money to repay.
}

View File

@ -572,7 +572,7 @@ static void CompanyCheckBankrupt(Company *c)
if (_settings_game.difficulty.infinite_money) return;
/* If the company has money again, it does not go bankrupt */
if (c->money - c->current_loan >= -_economy.max_loan) {
if (c->money - c->current_loan >= -c->GetMaxLoan()) {
int previous_months_of_bankruptcy = CeilDiv(c->months_of_bankruptcy, 3);
c->months_of_bankruptcy = 0;
c->bankrupt_asked = 0;

View File

@ -200,6 +200,8 @@ struct PriceBaseSpec {
static const int LOAN_INTERVAL = 10000;
/** The size of loan for a new company, in British Pounds! */
static const int64_t INITIAL_LOAN = 100000;
/** The max amount possible to configure for a max loan of a company. */
static const int64_t MAX_LOAN_LIMIT = 2000000000;
/**
* Maximum inflation (including fractional part) without causing overflows in int64_t price computations.

View File

@ -39,9 +39,9 @@
CommandCost CmdIncreaseLoan(DoCommandFlag flags, LoanCommand cmd, Money amount)
{
Company *c = Company::Get(_current_company);
if (c->current_loan >= _economy.max_loan) {
SetDParam(0, _economy.max_loan);
Money max_loan = c->GetMaxLoan();
if (c->current_loan >= max_loan) {
SetDParam(0, max_loan);
return_cmd_error(STR_ERROR_MAXIMUM_PERMITTED_LOAN);
}
@ -52,11 +52,11 @@ CommandCost CmdIncreaseLoan(DoCommandFlag flags, LoanCommand cmd, Money amount)
loan = LOAN_INTERVAL;
break;
case LoanCommand::Max: // Take a loan as big as possible
loan = _economy.max_loan - c->current_loan;
loan = max_loan - c->current_loan;
break;
case LoanCommand::Amount: // Take the given amount of loan
loan = amount;
if (loan < LOAN_INTERVAL || c->current_loan + loan > _economy.max_loan || loan % LOAN_INTERVAL != 0) return CMD_ERROR;
if (loan < LOAN_INTERVAL || c->current_loan + loan > max_loan || loan % LOAN_INTERVAL != 0) return CMD_ERROR;
break;
}
@ -118,6 +118,32 @@ CommandCost CmdDecreaseLoan(DoCommandFlag flags, LoanCommand cmd, Money amount)
return CommandCost();
}
/**
* Sets the max loan amount of your company. Does not respect the global loan setting.
* @param company the company ID.
* @param amount the new max loan amount, will be rounded down to the multitude of LOAN_INTERVAL. If set to COMPANY_MAX_LOAN_DEFAULT reset the max loan to default(global) value.
* @return zero cost or an error
*/
CommandCost CmdSetCompanyMaxLoan(DoCommandFlag flags, CompanyID company, Money amount)
{
if (_current_company != OWNER_DEITY) return CMD_ERROR;
if (amount != COMPANY_MAX_LOAN_DEFAULT) {
if (amount < 0 || amount > (Money)MAX_LOAN_LIMIT) return CMD_ERROR;
}
Company *c = Company::GetIfValid(company);
if (c == nullptr) return CMD_ERROR;
if (flags & DC_EXEC) {
/* Round the amount down to a multiple of LOAN_INTERVAL. */
if (amount != COMPANY_MAX_LOAN_DEFAULT) amount -= (int64_t)amount % LOAN_INTERVAL;
c->max_loan = amount;
InvalidateCompanyWindows(c);
}
return CommandCost();
}
/**
* In case of an unsafe unpause, we want the
* user to confirm that it might crash.

View File

@ -25,12 +25,14 @@ CommandCost CmdMoneyCheat(DoCommandFlag flags, Money amount);
CommandCost CmdChangeBankBalance(DoCommandFlag flags, TileIndex tile, Money delta, CompanyID company, ExpensesType expenses_type);
CommandCost CmdIncreaseLoan(DoCommandFlag flags, LoanCommand cmd, Money amount);
CommandCost CmdDecreaseLoan(DoCommandFlag flags, LoanCommand cmd, Money amount);
CommandCost CmdSetCompanyMaxLoan(DoCommandFlag flags, CompanyID company, Money amount);
CommandCost CmdPause(DoCommandFlag flags, PauseMode mode, bool pause);
DEF_CMD_TRAIT(CMD_MONEY_CHEAT, CmdMoneyCheat, CMD_OFFLINE, CMDT_CHEAT)
DEF_CMD_TRAIT(CMD_CHANGE_BANK_BALANCE, CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INCREASE_LOAN, CmdIncreaseLoan, 0, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_DECREASE_LOAN, CmdDecreaseLoan, 0, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_PAUSE, CmdPause, CMD_SERVER | CMD_NO_EST, CMDT_SERVER_SETTING)
DEF_CMD_TRAIT(CMD_MONEY_CHEAT, CmdMoneyCheat, CMD_OFFLINE, CMDT_CHEAT)
DEF_CMD_TRAIT(CMD_CHANGE_BANK_BALANCE, CmdChangeBankBalance, CMD_DEITY, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INCREASE_LOAN, CmdIncreaseLoan, 0, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_DECREASE_LOAN, CmdDecreaseLoan, 0, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_SET_COMPANY_MAX_LOAN, CmdSetCompanyMaxLoan, CMD_DEITY, CMDT_MONEY_MANAGEMENT)
DEF_CMD_TRAIT(CMD_PAUSE, CmdPause, CMD_SERVER | CMD_NO_EST, CMDT_SERVER_SETTING)
#endif /* MISC_CMD_H */

View File

@ -3280,6 +3280,12 @@ bool AfterLoadGame()
}
}
if (IsSavegameVersionBefore(SLV_MAX_LOAN_FOR_COMPANY)) {
for (Company *c : Company::Iterate()) {
c->max_loan = COMPANY_MAX_LOAN_DEFAULT;
}
}
for (Company *c : Company::Iterate()) {
UpdateCompanyLiveries(c);
}

View File

@ -458,6 +458,7 @@ static const SaveLoad _company_desc[] = {
SLE_CONDVAR(CompanyProperties, current_loan, SLE_VAR_I64 | SLE_FILE_I32, SL_MIN_VERSION, SLV_65),
SLE_CONDVAR(CompanyProperties, current_loan, SLE_INT64, SLV_65, SL_MAX_VERSION),
SLE_CONDVAR(CompanyProperties, max_loan, SLE_INT64, SLV_MAX_LOAN_FOR_COMPANY, SL_MAX_VERSION),
SLE_VAR(CompanyProperties, colour, SLE_UINT8),
SLE_VAR(CompanyProperties, money_fraction, SLE_UINT8),

View File

@ -373,6 +373,8 @@ enum SaveLoadVersion : uint16_t {
SLV_CALENDAR_SUB_DATE_FRACT, ///< 328 PR#11428 Add sub_date_fract to measure calendar days.
SLV_SHIP_ACCELERATION, ///< 329 PR#10734 Start using Vehicle's acceleration field for ships too.
SLV_MAX_LOAN_FOR_COMPANY, ///< 330 PR#11224 Separate max loan for each company.
SL_MAX_VERSION, ///< Highest possible saveload version
};

View File

@ -47,6 +47,8 @@
* \li GSCompany::SetAutoRenewStatus
* \li GSCompany::SetAutoRenewMonths
* \li GSCompany::SetAutoRenewMoney
* \li GSCompany::SetMaxLoanAmountForCompany
* \li GSCompany::ResetMaxLoanAmountForCompany
* \li GSGameSettings::IsDisabledVehicleType
* \li GSGroup::GroupID
* \li GSGroup::IsValidGroup

View File

@ -192,7 +192,32 @@
/* static */ Money ScriptCompany::GetMaxLoanAmount()
{
return _economy.max_loan;
if (ScriptCompanyMode::IsDeity()) return _economy.max_loan;
ScriptCompany::CompanyID company = ResolveCompanyID(COMPANY_SELF);
if (company == COMPANY_INVALID) return -1;
return ::Company::Get(company)->GetMaxLoan();
}
/* static */ bool ScriptCompany::SetMaxLoanAmountForCompany(CompanyID company, Money amount)
{
EnforceDeityMode(false);
EnforcePrecondition(false, amount >= 0 && amount <= (Money)MAX_LOAN_LIMIT);
company = ResolveCompanyID(company);
EnforcePrecondition(false, company != COMPANY_INVALID);
return ScriptObject::Command<CMD_SET_COMPANY_MAX_LOAN>::Do((::CompanyID)company, amount);
}
/* static */ bool ScriptCompany::ResetMaxLoanAmountForCompany(CompanyID company)
{
EnforceDeityMode(false);
company = ResolveCompanyID(company);
EnforcePrecondition(false, company != COMPANY_INVALID);
return ScriptObject::Command<CMD_SET_COMPANY_MAX_LOAN>::Do((::CompanyID)company, COMPANY_MAX_LOAN_DEFAULT);
}
/* static */ Money ScriptCompany::GetLoanInterval()

View File

@ -217,12 +217,38 @@ public:
static Money GetLoanAmount();
/**
* Gets the maximum amount your company can loan.
* Gets the maximum amount your company can loan. In deity mode returns the global max loan.
* @return The maximum amount your company can loan.
* @post GetLoanInterval() is always a multiplier of the return value.
*/
static Money GetMaxLoanAmount();
/**
* Sets the max amount of money company can loan.
* @param company The company ID.
* @param amount Max loan amount. Will be rounded down to a multiple of GetLoanInterval().
* @return True, if the max loan was changed.
* @pre ScriptCompanyMode::IsDeity().
* @pre amount >= 0.
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @note You need to create your own news message to inform about max loan change.
* @note Max loan value set with this method is not affected by inflation.
* @api -ai
*/
static bool SetMaxLoanAmountForCompany(CompanyID company, Money amount);
/**
* Makes the max amount of money company can loan follow the global max loan setting.
* @param company The company ID.
* @return True, if the max loan was reset.
* @pre ScriptCompanyMode::IsDeity().
* @pre amount >= 0 && amount <= MAX_LOAN_LIMIT.
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @note You need to create your own news message to inform about max loan change.
* @api -ai
*/
static bool ResetMaxLoanAmountForCompany(CompanyID company);
/**
* Gets the interval/loan step.
* @return The loan step.

View File

@ -111,7 +111,7 @@ from = SLV_97
flags = SF_NEWGAME_ONLY | SF_SCENEDIT_TOO | SF_GUI_CURRENCY | SF_GUI_0_IS_SPECIAL
def = 300000
min = LOAN_INTERVAL
max = 2000000000
max = MAX_LOAN_LIMIT
pre_cb = [](auto &new_value) { new_value = (new_value + LOAN_INTERVAL / 2) / LOAN_INTERVAL * LOAN_INTERVAL; return true; }
interval = LOAN_INTERVAL
str = STR_CONFIG_SETTING_MAXIMUM_INITIAL_LOAN