/* * 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 . */ /** @file script_company.cpp Implementation of ScriptCompany. */ #include "../../stdafx.h" #include "script_company.hpp" #include "script_error.hpp" #include "script_companymode.hpp" #include "../../company_func.h" #include "../../company_base.h" #include "../../company_manager_face.h" #include "../../economy_func.h" #include "../../object_type.h" #include "../../strings_func.h" #include "../../tile_map.h" #include "../../string_func.h" #include "../../settings_func.h" #include "../../company_cmd.h" #include "../../misc_cmd.h" #include "../../object_cmd.h" #include "../../settings_cmd.h" #include "table/strings.h" #include "../../safeguards.h" /* static */ ::CompanyID ScriptCompany::FromScriptCompanyID(ScriptCompany::CompanyID company) { /* If this assert gets triggered, then ScriptCompany::ResolveCompanyID needed to be called before. */ assert(company != ScriptCompany::COMPANY_SELF && company != ScriptCompany::COMPANY_SPECTATOR); if (company == ScriptCompany::COMPANY_INVALID) return ::CompanyID::Invalid(); return static_cast<::CompanyID>(company); } /* static */ ScriptCompany::CompanyID ScriptCompany::ToScriptCompanyID(::CompanyID company) { if (company == ::CompanyID::Invalid()) return ScriptCompany::COMPANY_INVALID; return static_cast<::ScriptCompany::CompanyID>(company.base()); } /* static */ ScriptCompany::CompanyID ScriptCompany::ResolveCompanyID(ScriptCompany::CompanyID company) { if (company == ScriptCompany::COMPANY_SELF) { if (!::Company::IsValidID(_current_company)) return ScriptCompany::COMPANY_INVALID; return ScriptCompany::ToScriptCompanyID(_current_company); } return ::Company::IsValidID(ScriptCompany::FromScriptCompanyID(company)) ? company : ScriptCompany::COMPANY_INVALID; } /* static */ bool ScriptCompany::IsMine(ScriptCompany::CompanyID company) { EnforceCompanyModeValid(false); return ResolveCompanyID(company) == ResolveCompanyID(ScriptCompany::COMPANY_SELF); } /* static */ bool ScriptCompany::SetName(Text *name) { ScriptObjectRef counter(name); EnforceCompanyModeValid(false); EnforcePrecondition(false, name != nullptr); const std::string &text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_COMPANY_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::Command::Do(text); } /* static */ std::optional ScriptCompany::GetName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return std::nullopt; return ::StrMakeValid(::GetString(STR_COMPANY_NAME, ScriptCompany::FromScriptCompanyID(company)), {}); } /* static */ bool ScriptCompany::SetPresidentName(Text *name) { ScriptObjectRef counter(name); EnforceCompanyModeValid(false); EnforcePrecondition(false, name != nullptr); const std::string &text = name->GetDecodedText(); EnforcePreconditionEncodedText(false, text); EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_PRESIDENT_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG); return ScriptObject::Command::Do(text); } /* static */ std::optional ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return std::nullopt; return ::StrMakeValid(::GetString(STR_PRESIDENT_NAME, ScriptCompany::FromScriptCompanyID(company)), {}); } /* static */ bool ScriptCompany::SetPresidentGender(Gender gender) { EnforceCompanyModeValid(false); EnforcePrecondition(false, gender == GENDER_MALE || gender == GENDER_FEMALE); EnforcePrecondition(false, GetPresidentGender(ScriptCompany::COMPANY_SELF) != gender); Randomizer &randomizer = ScriptObject::GetRandomizer(); CompanyManagerFace cmf; GenderEthnicity ge = (GenderEthnicity)((gender == GENDER_FEMALE ? (1 << ::GENDER_FEMALE) : 0) | (randomizer.Next() & (1 << ETHNICITY_BLACK))); RandomCompanyManagerFaceBits(cmf, ge, false, randomizer); return ScriptObject::Command::Do(cmf); } /* static */ ScriptCompany::Gender ScriptCompany::GetPresidentGender(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return GENDER_INVALID; GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(Company::Get(ScriptCompany::FromScriptCompanyID(company))->face, CMFV_GEN_ETHN, GE_WM); return HasBit(ge, ::GENDER_FEMALE) ? GENDER_FEMALE : GENDER_MALE; } /* static */ Money ScriptCompany::GetQuarterlyIncome(ScriptCompany::CompanyID company, SQInteger quarter) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter < CURRENT_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->cur_economy.income; } return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->old_economy[quarter - 1].income; } /* static */ Money ScriptCompany::GetQuarterlyExpenses(ScriptCompany::CompanyID company, SQInteger quarter) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter < CURRENT_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->cur_economy.expenses; } return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->old_economy[quarter - 1].expenses; } /* static */ SQInteger ScriptCompany::GetQuarterlyCargoDelivered(ScriptCompany::CompanyID company, SQInteger quarter) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter < CURRENT_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->cur_economy.delivered_cargo.GetSum(); } return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->old_economy[quarter - 1].delivered_cargo.GetSum(); } /* static */ SQInteger ScriptCompany::GetQuarterlyPerformanceRating(ScriptCompany::CompanyID company, SQInteger quarter) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter <= CURRENT_QUARTER) return -1; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->old_economy[quarter - 1].performance_history; } /* static */ Money ScriptCompany::GetQuarterlyCompanyValue(ScriptCompany::CompanyID company, SQInteger quarter) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; if (quarter > EARLIEST_QUARTER) return -1; if (quarter < CURRENT_QUARTER) return -1; if (quarter == CURRENT_QUARTER) { return ::CalculateCompanyValue(::Company::Get(ScriptCompany::FromScriptCompanyID(company))); } return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->old_economy[quarter - 1].company_value; } /* static */ Money ScriptCompany::GetBankBalance(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return -1; /* If we return INT64_MAX as usual, overflows may occur in the script. So return a smaller value. */ if (_settings_game.difficulty.infinite_money) return INT32_MAX; return GetAvailableMoney(ScriptCompany::FromScriptCompanyID(company)); } /* static */ Money ScriptCompany::GetLoanAmount() { ScriptCompany::CompanyID company = ResolveCompanyID(ScriptCompany::COMPANY_SELF); if (company == ScriptCompany::COMPANY_INVALID) return -1; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->current_loan; } /* static */ Money ScriptCompany::GetMaxLoanAmount() { if (ScriptCompanyMode::IsDeity()) return _economy.max_loan; ScriptCompany::CompanyID company = ResolveCompanyID(ScriptCompany::COMPANY_SELF); if (company == ScriptCompany::COMPANY_INVALID) return -1; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->GetMaxLoan(); } /* static */ bool ScriptCompany::SetMaxLoanAmountForCompany(ScriptCompany::CompanyID company, Money amount) { EnforceDeityMode(false); EnforcePrecondition(false, amount >= 0 && amount <= (Money)MAX_LOAN_LIMIT); company = ResolveCompanyID(company); EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID); return ScriptObject::Command::Do(ScriptCompany::FromScriptCompanyID(company), amount); } /* static */ bool ScriptCompany::ResetMaxLoanAmountForCompany(ScriptCompany::CompanyID company) { EnforceDeityMode(false); company = ResolveCompanyID(company); EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID); return ScriptObject::Command::Do(ScriptCompany::FromScriptCompanyID(company), COMPANY_MAX_LOAN_DEFAULT); } /* static */ Money ScriptCompany::GetLoanInterval() { return LOAN_INTERVAL; } /* static */ bool ScriptCompany::SetLoanAmount(Money loan) { EnforceCompanyModeValid(false); EnforcePrecondition(false, loan >= 0); EnforcePrecondition(false, ((int64_t)loan % GetLoanInterval()) == 0); EnforcePrecondition(false, loan <= GetMaxLoanAmount()); EnforcePrecondition(false, (loan - GetLoanAmount() + GetBankBalance(ScriptCompany::COMPANY_SELF)) >= 0); if (loan == GetLoanAmount()) return true; Money amount = abs(loan - GetLoanAmount()); if (loan > GetLoanAmount()) { return ScriptObject::Command::Do(LoanCommand::Amount, amount); } else { return ScriptObject::Command::Do(LoanCommand::Amount, amount); } } /* static */ bool ScriptCompany::SetMinimumLoanAmount(Money loan) { EnforceCompanyModeValid(false); EnforcePrecondition(false, loan >= 0); Money over_interval = (int64_t)loan % GetLoanInterval(); if (over_interval != 0) loan += GetLoanInterval() - over_interval; EnforcePrecondition(false, loan <= GetMaxLoanAmount()); SetLoanAmount(loan); return GetLoanAmount() == loan; } /* static */ bool ScriptCompany::ChangeBankBalance(ScriptCompany::CompanyID company, Money delta, ExpensesType expenses_type, TileIndex tile) { EnforceDeityMode(false); EnforcePrecondition(false, expenses_type < (ExpensesType)::EXPENSES_END); EnforcePrecondition(false, tile == INVALID_TILE || ::IsValidTile(tile)); company = ResolveCompanyID(company); EnforcePrecondition(false, company != ScriptCompany::COMPANY_INVALID); /* Network commands only allow 0 to indicate invalid tiles, not INVALID_TILE */ return ScriptObject::Command::Do(tile == INVALID_TILE ? (TileIndex)0U : tile, delta, ScriptCompany::FromScriptCompanyID(company), (::ExpensesType)expenses_type); } /* static */ bool ScriptCompany::BuildCompanyHQ(TileIndex tile) { EnforceCompanyModeValid(false); EnforcePrecondition(false, ::IsValidTile(tile)); return ScriptObject::Command::Do(tile, OBJECT_HQ, 0); } /* static */ TileIndex ScriptCompany::GetCompanyHQ(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return INVALID_TILE; TileIndex loc = ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->location_of_HQ; return (loc == 0) ? INVALID_TILE : loc; } /* static */ bool ScriptCompany::SetAutoRenewStatus(bool autorenew) { EnforceCompanyModeValid(false); return ScriptObject::Command::Do("company.engine_renew", autorenew ? 1 : 0); } /* static */ bool ScriptCompany::GetAutoRenewStatus(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return false; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->settings.engine_renew; } /* static */ bool ScriptCompany::SetAutoRenewMonths(SQInteger months) { EnforceCompanyModeValid(false); months = Clamp(months, INT16_MIN, INT16_MAX); return ScriptObject::Command::Do("company.engine_renew_months", months); } /* static */ SQInteger ScriptCompany::GetAutoRenewMonths(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return 0; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->settings.engine_renew_months; } /* static */ bool ScriptCompany::SetAutoRenewMoney(Money money) { EnforceCompanyModeValid(false); EnforcePrecondition(false, money >= 0); EnforcePrecondition(false, (int64_t)money <= UINT32_MAX); return ScriptObject::Command::Do("company.engine_renew_money", money); } /* static */ Money ScriptCompany::GetAutoRenewMoney(ScriptCompany::CompanyID company) { company = ResolveCompanyID(company); if (company == ScriptCompany::COMPANY_INVALID) return 0; return ::Company::Get(ScriptCompany::FromScriptCompanyID(company))->settings.engine_renew_money; } /* static */ bool ScriptCompany::SetPrimaryLiveryColour(LiveryScheme scheme, Colours colour) { EnforceCompanyModeValid(false); return ScriptObject::Command::Do((::LiveryScheme)scheme, true, (::Colours)colour); } /* static */ bool ScriptCompany::SetSecondaryLiveryColour(LiveryScheme scheme, Colours colour) { EnforceCompanyModeValid(false); return ScriptObject::Command::Do((::LiveryScheme)scheme, false, (::Colours)colour); } /* static */ ScriptCompany::Colours ScriptCompany::GetPrimaryLiveryColour(ScriptCompany::LiveryScheme scheme) { if ((::LiveryScheme)scheme < LS_BEGIN || (::LiveryScheme)scheme >= LS_END) return COLOUR_INVALID; const Company *c = ::Company::GetIfValid(_current_company); if (c == nullptr) return COLOUR_INVALID; return (ScriptCompany::Colours)c->livery[scheme].colour1; } /* static */ ScriptCompany::Colours ScriptCompany::GetSecondaryLiveryColour(ScriptCompany::LiveryScheme scheme) { if ((::LiveryScheme)scheme < LS_BEGIN || (::LiveryScheme)scheme >= LS_END) return COLOUR_INVALID; const Company *c = ::Company::GetIfValid(_current_company); if (c == nullptr) return COLOUR_INVALID; return (ScriptCompany::Colours)c->livery[scheme].colour2; }