Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 2 commits into from
Sep 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/command_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/industry.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
68 changes: 67 additions & 1 deletion src/industry_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -2115,6 +2117,65 @@ 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.
* @param custom_news Custom news message text.
* @return Empty cost or an error.
*/
CommandCost CmdIndustrySetProduction(DoCommandFlag flags, IndustryID ind_id, byte prod_level, bool show_news, const std::string &custom_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;
}
if (prod_level != ind->prod_level && !custom_news.empty()) str = STR_NEWS_CUSTOM_ITEM;

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 */
NewsAllocatedData *data = nullptr;
if (str == STR_NEWS_CUSTOM_ITEM) {
NewsStringData *news = new NewsStringData(custom_news);
SetDParamStr(0, news->string);
} else 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, data);
}
}

return CommandCost();
}

/**
* Change exclusive consumer or supplier for the industry.
* @param flags Type of operation.
Expand Down Expand Up @@ -2618,7 +2679,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

Expand Down Expand Up @@ -2820,6 +2881,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)) {
Expand Down
2 changes: 2 additions & 0 deletions src/industry_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, const std::string &text);

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

Expand Down
4 changes: 2 additions & 2 deletions src/news_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ static inline void AddTileNewsItem(StringID string, NewsType type, TileIndex til
AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_TILE, static_cast<uint32_t>(tile), station == INVALID_STATION ? NR_NONE : NR_STATION, station, data);
}

static inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry)
static inline void AddIndustryNewsItem(StringID string, NewsType type, IndustryID industry, const NewsAllocatedData *data = nullptr)
{
AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_INDUSTRY, industry);
AddNewsItem(string, type, NF_NO_TRANSPARENT | NF_SHADE | NF_THIN, NR_INDUSTRY, industry, NR_NONE, UINT32_MAX, data);
}

void NewsLoop();
Expand Down
2 changes: 2 additions & 0 deletions src/script/api/game_changelog.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
18 changes: 18 additions & 0 deletions src/script/api/script_industry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,3 +294,21 @@
::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, Text *custom_news)
{
CCountedPtr<Text> counter(custom_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, custom_news != nullptr ? custom_news->GetEncodedText() : std::string{});
}
26 changes: 26 additions & 0 deletions src/script/api/script_industry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class ScriptIndustry : public ScriptObject {
* 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,
};

/**
Expand Down Expand Up @@ -323,6 +327,28 @@ class ScriptIndustry : public ScriptObject {
*/
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.
* @param custom_news Custom news message text to override the default news text with. Pass null to use the default text. Only used if \c show_news is set to true.
* @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, Text *custom_news);
};

#endif /* SCRIPT_INDUSTRY_HPP */