Add: [Script] Game script control of industry production level.

This commit is contained in:
Michael Lutz 2023-07-16 21:34:42 +02:00
parent a5c8365aa4
commit 1c56991213
7 changed files with 110 additions and 2 deletions

View File

@ -246,6 +246,7 @@ enum Commands : uint16_t {
CMD_INDUSTRY_SET_FLAGS, ///< change industry control flags
CMD_INDUSTRY_SET_EXCLUSIVITY, ///< change industry exclusive consumer/supplier
CMD_INDUSTRY_SET_TEXT, ///< change additional text for the industry
CMD_INDUSTRY_SET_PRODUCTION, ///< change industry production
CMD_SET_COMPANY_MANAGER_FACE, ///< set the manager's face of the company
CMD_SET_COMPANY_COLOUR, ///< set the colour of the company

View File

@ -51,8 +51,10 @@ enum IndustryControlFlags : byte {
* Industry can not close regardless of production level or time since last delivery.
* This does not prevent a closure already announced. */
INDCTL_NO_CLOSURE = 1 << 2,
/** Indicates that the production level of the industry is externally controlled. */
INDCTL_EXTERNAL_PROD_LEVEL = 1 << 3,
/** Mask of all flags set */
INDCTL_MASK = INDCTL_NO_PRODUCTION_DECREASE | INDCTL_NO_PRODUCTION_INCREASE | INDCTL_NO_CLOSURE,
INDCTL_MASK = INDCTL_NO_PRODUCTION_DECREASE | INDCTL_NO_PRODUCTION_INCREASE | INDCTL_NO_CLOSURE | INDCTL_EXTERNAL_PROD_LEVEL,
};
DECLARE_ENUM_AS_BIT_SET(IndustryControlFlags);

View File

@ -68,6 +68,8 @@ IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
IndustryBuildData _industry_builder; ///< In-game manager of industries.
static int WhoCanServiceIndustry(Industry *ind);
/**
* This function initialize the spec arrays of both
* industry and industry tiles.
@ -2115,6 +2117,59 @@ CommandCost CmdIndustrySetFlags(DoCommandFlag flags, IndustryID ind_id, Industry
return CommandCost();
}
/**
* Set industry production.
* @param flags Type of operation.
* @param ind_id IndustryID
* @param prod_level Production level.
* @param show_news Show a news message on production change.
* @return Empty cost or an error.
*/
CommandCost CmdIndustrySetProduction(DoCommandFlag flags, IndustryID ind_id, byte prod_level, bool show_news)
{
if (_current_company != OWNER_DEITY) return CMD_ERROR;
if (prod_level < PRODLEVEL_MINIMUM || prod_level > PRODLEVEL_MAXIMUM) return CMD_ERROR;
Industry *ind = Industry::GetIfValid(ind_id);
if (ind == nullptr) return CMD_ERROR;
if (flags & DC_EXEC) {
StringID str = STR_NULL;
if (prod_level > ind->prod_level) {
str = GetIndustrySpec(ind->type)->production_up_text;
} else if (prod_level < ind->prod_level) {
str = GetIndustrySpec(ind->type)->production_down_text;
}
ind->ctlflags |= INDCTL_EXTERNAL_PROD_LEVEL;
ind->prod_level = prod_level;
ind->RecomputeProductionMultipliers();
/* Show news message if requested. */
if (show_news && str != STR_NULL) {
NewsType nt;
switch (WhoCanServiceIndustry(ind)) {
case 0: nt = NT_INDUSTRY_NOBODY; break;
case 1: nt = NT_INDUSTRY_OTHER; break;
case 2: nt = NT_INDUSTRY_COMPANY; break;
default: NOT_REACHED();
}
/* Set parameters of news string */
if (str > STR_LAST_STRINGID) {
SetDParam(0, STR_TOWN_NAME);
SetDParam(1, ind->town->index);
SetDParam(2, GetIndustrySpec(ind->type)->name);
} else {
SetDParam(0, ind->index);
}
AddIndustryNewsItem(str, nt, ind->index);
}
}
return CommandCost();
}
/**
* Change exclusive consumer or supplier for the industry.
* @param flags Type of operation.
@ -2618,7 +2673,7 @@ static void CanCargoServiceIndustry(CargoID cargo, Industry *ind, bool *c_accept
* service the industry, and 1 otherwise (only competitors can service the
* industry)
*/
static int WhoCanServiceIndustry(Industry *ind)
int WhoCanServiceIndustry(Industry *ind)
{
if (ind->stations_near.size() == 0) return 0; // No stations found at all => nobody services
@ -2820,6 +2875,11 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
/* If override flags are set, prevent actually changing production if any was decided on */
if ((i->ctlflags & INDCTL_NO_PRODUCTION_DECREASE) && (div > 0 || increment < 0)) return;
if ((i->ctlflags & INDCTL_NO_PRODUCTION_INCREASE) && (mul > 0 || increment > 0)) return;
if (i->ctlflags & INDCTL_EXTERNAL_PROD_LEVEL) {
div = 0;
mul = 0;
increment = 0;
}
if (!callback_enabled && (indspec->life_type & INDUSTRYLIFE_PROCESSING)) {
if (TimerGameCalendar::year - i->last_prod_year >= PROCESSING_INDUSTRY_ABANDONMENT_YEARS && Chance16(1, original_economy ? 2 : 180)) {

View File

@ -20,11 +20,13 @@ CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType i
CommandCost CmdIndustrySetFlags(DoCommandFlag flags, IndustryID ind_id, IndustryControlFlags ctlflags);
CommandCost CmdIndustrySetExclusivity(DoCommandFlag flags, IndustryID ind_id, Owner company_id, bool consumer);
CommandCost CmdIndustrySetText(DoCommandFlag flags, IndustryID ind_id, const std::string &text);
CommandCost CmdIndustrySetProduction(DoCommandFlag flags, IndustryID ind_id, byte prod_level, bool show_news);
DEF_CMD_TRAIT(CMD_BUILD_INDUSTRY, CmdBuildIndustry, CMD_DEITY, CMDT_LANDSCAPE_CONSTRUCTION)
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_FLAGS, CmdIndustrySetFlags, CMD_DEITY, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_EXCLUSIVITY, CmdIndustrySetExclusivity, CMD_DEITY, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_TEXT, CmdIndustrySetText, CMD_DEITY | CMD_STR_CTRL, CMDT_OTHER_MANAGEMENT)
DEF_CMD_TRAIT(CMD_INDUSTRY_SET_PRODUCTION, CmdIndustrySetProduction, CMD_DEITY, CMDT_OTHER_MANAGEMENT)
void CcBuildIndustry(Commands cmd, const CommandCost &result, TileIndex tile, IndustryType indtype, uint32_t, bool, uint32_t);

View File

@ -78,6 +78,8 @@
* \li GSVehicleList_DefaultGroup
* \li GSGoal::IsValidGoalDestination
* \li GSGoal::SetDestination
* \li GSIndustry::GetProductionLevel
* \li GSIndustry::SetProductionLevel
*
* API removals:
* \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.

View File

@ -294,3 +294,19 @@
::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
return ScriptObject::Command<CMD_INDUSTRY_SET_EXCLUSIVITY>::Do(industry_id, owner, true);
}
/* static */ SQInteger ScriptIndustry::GetProductionLevel(IndustryID industry_id)
{
Industry *i = Industry::GetIfValid(industry_id);
if (i == nullptr) return 0;
return i->prod_level;
}
/* static */ bool ScriptIndustry::SetProductionLevel(IndustryID industry_id, SQInteger prod_level, bool show_news)
{
EnforceDeityMode(false);
EnforcePrecondition(false, IsValidIndustry(industry_id));
EnforcePrecondition(false, prod_level >= PRODLEVEL_MINIMUM && prod_level <= PRODLEVEL_MAXIMUM);
return ScriptObject::Command<CMD_INDUSTRY_SET_PRODUCTION>::Do(industry_id, prod_level, show_news);
}

View File

@ -47,6 +47,10 @@ public:
* This does not prevent a closure already announced.
*/
INDCTL_NO_CLOSURE = ::INDCTL_NO_CLOSURE,
/**
* Indicates that the production level of the industry is controlled by a game script.
*/
INDCTL_EXTERNAL_PROD_LEVEL = ::INDCTL_EXTERNAL_PROD_LEVEL,
};
/**
@ -323,6 +327,27 @@ public:
*/
static bool SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id);
/**
* Gets the current production level of an industry.
* @param industry_id The index of the industry.
* @api -ai
*/
static SQInteger GetProductionLevel(IndustryID industry_id);
/**
* Sets the current production level of an industry.
* @note Setting the production level automatically sets the control flag INDCTL_EXTERNAL_PROD_LEVEL if it wasn't already set.
* Normal production behaviour can be restored by clearing the control flag.
* @param industry_id The index of the industry.
* @param prod_level The production level to set.
* @param show_news If set to true and the production changed, generate a production change news message. If set to false, no news message is shown.
* @pre IsValidIndustry(industry_id).
* @pre ScriptCompanyMode::IsDeity().
* @pre prod_level >= 4 && prod_level <= 128.
* @return True if the action succeeded.
* @api -ai
*/
static bool SetProductionLevel(IndustryID industry_id, SQInteger prod_level, bool show_news);
};
#endif /* SCRIPT_INDUSTRY_HPP */