Changeset - r27851:98395ce429bf
[Not reviewed]
master
0 7 0
Michael Lutz - 11 months ago 2023-07-16 19:34:42
michi@icosahedron.de
Add: [Script] Game script control of industry production level.
7 files changed with 110 insertions and 2 deletions:
0 comments (0 inline, 0 general)
src/command_type.h
Show inline comments
 
@@ -237,24 +237,25 @@ enum Commands : uint16_t {
 
	CMD_CLEAR_ORDER_BACKUP,           ///< clear the order backup of a given user/tile
 
	CMD_MODIFY_ORDER,                 ///< modify an order (like set full-load)
 
	CMD_SKIP_TO_ORDER,                ///< skip an order to the next of specific one
 
	CMD_DELETE_ORDER,                 ///< delete an order
 
	CMD_INSERT_ORDER,                 ///< insert a new order
 

	
 
	CMD_CHANGE_SERVICE_INT,           ///< change the server interval of a vehicle
 

	
 
	CMD_BUILD_INDUSTRY,               ///< build a new industry
 
	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
 

	
 
	CMD_INCREASE_LOAN,                ///< increase the loan from the bank
 
	CMD_DECREASE_LOAN,                ///< decrease the loan from the bank
 

	
 
	CMD_WANT_ENGINE_PREVIEW,          ///< confirm the preview of an engine
 
	CMD_ENGINE_CTRL,                  ///< control availability of the engine for companies
 

	
 
	CMD_RENAME_VEHICLE,               ///< rename a whole vehicle
 
	CMD_RENAME_ENGINE,                ///< rename a engine (in the engine list)
src/industry.h
Show inline comments
 
@@ -42,26 +42,28 @@ enum ProductionLevels {
 
 */
 
enum IndustryControlFlags : byte {
 
	/** No flags in effect */
 
	INDCTL_NONE                   = 0,
 
	/** When industry production change is evaluated, rolls to decrease are ignored. */
 
	INDCTL_NO_PRODUCTION_DECREASE = 1 << 0,
 
	/** When industry production change is evaluated, rolls to increase are ignored. */
 
	INDCTL_NO_PRODUCTION_INCREASE = 1 << 1,
 
	/**
 
	 * 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);
 

	
 
static const int THIS_MONTH = 0;
 
static const int LAST_MONTH = 1;
 

	
 
/**
 
 * Defines the internal data of a functional industry.
 
 */
 
struct Industry : IndustryPool::PoolItem<&_industry_pool> {
 
	struct ProducedHistory {
 
		uint16_t production; ///< Total produced
src/industry_cmd.cpp
Show inline comments
 
@@ -59,24 +59,26 @@ INSTANTIATE_POOL_METHODS(Industry)
 
void ShowIndustryViewWindow(int industry);
 
void BuildOilRig(TileIndex tile);
 

	
 
static byte _industry_sound_ctr;
 
static TileIndex _industry_sound_tile;
 

	
 
uint16_t Industry::counts[NUM_INDUSTRYTYPES];
 

	
 
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.
 
 * It adjusts the enabling of the industry too, based on climate availability.
 
 * This will allow for clearer testings
 
 */
 
void ResetIndustries()
 
{
 
	auto industry_insert = std::copy(std::begin(_origin_industry_specs), std::end(_origin_industry_specs), std::begin(_industry_specs));
 
	std::fill(industry_insert, std::end(_industry_specs), IndustrySpec{});
 

	
 
	for (IndustryType i = 0; i < lengthof(_origin_industry_specs); i++) {
 
@@ -2107,24 +2109,77 @@ CommandCost CmdIndustrySetFlags(DoComman
 
{
 
	if (_current_company != OWNER_DEITY) return CMD_ERROR;
 

	
 
	Industry *ind = Industry::GetIfValid(ind_id);
 
	if (ind == nullptr) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) ind->ctlflags = ctlflags & INDCTL_MASK;
 

	
 
	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.
 
 * @param ind_id IndustryID
 
 * @param company_id CompanyID to set or INVALID_OWNER (available to everyone) or
 
 *                   OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
 
 * @param consumer Set exclusive consumer if true, supplier if false.
 
 * @return Empty cost or an error.
 
 */
 
CommandCost CmdIndustrySetExclusivity(DoCommandFlag flags, IndustryID ind_id, Owner company_id, bool consumer)
 
{
 
	if (_current_company != OWNER_DEITY) return CMD_ERROR;
 

	
 
@@ -2609,25 +2664,25 @@ static void CanCargoServiceIndustry(Carg
 
 * Compute who can service the industry.
 
 *
 
 * Here, 'can service' means that they have trains and stations close enough
 
 * to the industry with the right cargo type and the right orders (ie has the
 
 * technical means).
 
 *
 
 * @param ind: Industry being investigated.
 
 *
 
 * @return: 0 if nobody can service the industry, 2 if the local company can
 
 * 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
 

	
 
	int result = 0;
 
	for (const Vehicle *v : Vehicle::Iterate()) {
 
		/* Is it worthwhile to try this vehicle? */
 
		if (v->owner != _local_company && result != 0) continue;
 

	
 
		/* Check whether it accepts the right kind of cargo */
 
		bool c_accepts = false;
 
		bool c_produces = false;
 
		if (v->type == VEH_TRAIN && v->IsFrontEngine()) {
 
@@ -2811,24 +2866,29 @@ static void ChangeIndustryProduction(Ind
 
				if (new_prod > 1) closeit = false;
 

	
 
				if (abs(percent) >= 10) {
 
					ReportNewsProductionChangeIndustry(i, p.cargo, percent);
 
				}
 
			}
 
		}
 
	}
 

	
 
	/* 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)) {
 
			closeit = true;
 
		}
 
	}
 

	
 
	/* Increase if needed */
 
	while (mul-- != 0 && i->prod_level < PRODLEVEL_MAXIMUM) {
 
		i->prod_level = std::min<int>(i->prod_level * 2, PRODLEVEL_MAXIMUM);
 
		recalculate_multipliers = true;
 
		if (str == STR_NULL) str = indspec->production_up_text;
src/industry_cmd.h
Show inline comments
 
@@ -11,21 +11,23 @@
 
#define INDUSTRY_CMD_H
 

	
 
#include "command_type.h"
 
#include "company_type.h"
 
#include "industry_type.h"
 

	
 
enum IndustryControlFlags : byte;
 

	
 
CommandCost CmdBuildIndustry(DoCommandFlag flags, TileIndex tile, IndustryType it, uint32_t first_layout, bool fund, uint32_t seed);
 
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);
 

	
 
#endif /* INDUSTRY_CMD_H */
src/script/api/game_changelog.hpp
Show inline comments
 
@@ -69,24 +69,26 @@
 
 * \li GSGroup::GetProfitThisYear
 
 * \li GSGroup::GetProfitLastYear
 
 * \li GSGroup::GetCurrentUsage
 
 * \li GSGroup::SetPrimaryColour
 
 * \li GSGroup::SetSecondaryColour
 
 * \li GSGroup::GetPrimaryColour
 
 * \li GSGroup::GetSecondaryColour
 
 * \li GSGroupList
 
 * \li GSVehicleList_Group
 
 * \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.
 
 *
 
 * \b 13.0
 
 *
 
 * API additions:
 
 * \li GSCargo::GetWeight
 
 * \li GSIndustryType::ResolveNewGRFID
 
 * \li GSObjectType::ResolveNewGRFID
 
 * \li GSLeagueTable
 
 *
src/script/api/script_industry.cpp
Show inline comments
 
@@ -285,12 +285,28 @@
 
	return (ScriptCompany::CompanyID)((byte)company_id);
 
}
 

	
 
/* static */ bool ScriptIndustry::SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id)
 
{
 
	EnforceDeityMode(false);
 
	EnforcePrecondition(false, IsValidIndustry(industry_id));
 

	
 
	auto company = ScriptCompany::ResolveCompanyID(company_id);
 
	::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);
 
}
src/script/api/script_industry.hpp
Show inline comments
 
@@ -38,24 +38,28 @@ public:
 
		 * This also prevents industry closure due to production dropping to the lowest level.
 
		 */
 
		INDCTL_NO_PRODUCTION_DECREASE = ::INDCTL_NO_PRODUCTION_DECREASE,
 
		/**
 
		 * When industry production change is evaluated, rolls to increase are ignored.
 
		 */
 
		INDCTL_NO_PRODUCTION_INCREASE = ::INDCTL_NO_PRODUCTION_INCREASE,
 
		/**
 
		 * Industry can not close regardless of production level or time since last delivery.
 
		 * 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,
 
	};
 

	
 
	/**
 
	 * Gets the number of industries.
 
	 * @return The number of industries.
 
	 * @note The maximum valid IndustryID can be higher than the value returned.
 
	 */
 
	static SQInteger GetIndustryCount();
 

	
 
	/**
 
	 * Checks whether the given industry index is valid.
 
	 * @param industry_id The index to check.
 
@@ -314,15 +318,36 @@ public:
 

	
 
	/**
 
	 * Sets or resets the company that has exclusive right to take cargo from the industry.
 
	 * @param industry_id The index of the industry.
 
	 * @param company_id The company to set (ScriptCompany::COMPANY_INVALID to reset).
 
	 * @pre IsValidIndustry(industry_id).
 
	 * @pre ScriptCompanyMode::IsDeity().
 
	 * @return True if the action succeeded.
 
	 * @api -ai
 
	 */
 
	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 */
0 comments (0 inline, 0 general)