Skip to content
Permalink
Browse files
Feature: Set exclusive access to industry from GS (#8115)
  • Loading branch information
ldpl committed Dec 22, 2020
1 parent b7751c4 commit 9a45a0f535e312cd97db12c3a2ec1068fa381136
@@ -1042,6 +1042,8 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
/* Check if industry temporarily refuses acceptance */
if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue;

if (ind->exclusive_supplier != INVALID_OWNER && ind->exclusive_supplier != st->owner) continue;

/* Insert the industry into _cargo_delivery_destinations, if not yet contained */
include(_cargo_delivery_destinations, ind);

@@ -29,7 +29,7 @@ int UpdateCompanyRatingAndValue(Company *c, bool update);
void StartupIndustryDailyChanges(bool init_counter);

Money GetTransportedGoodsIncome(uint num_pieces, uint dist, byte transit_days, CargoID cargo_type);
uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations);
uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations, Owner exclusivity = INVALID_OWNER);

void PrepareUnload(Vehicle *front_v);
void LoadUnloadStation(Station *st);
@@ -90,6 +90,8 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType)
Date last_cargo_accepted_at[INDUSTRY_NUM_INPUTS]; ///< Last day each cargo type was accepted by this industry
byte selected_layout; ///< Which tile layout was used when creating the industry
Owner exclusive_supplier; ///< Which company has exclusive rights to deliver cargo (INVALID_OWNER = anyone)
Owner exclusive_consumer; ///< Which company has exclusive rights to take cargo (INVALID_OWNER = anyone)

uint16 random; ///< Random value used for randomisation of all kinds of things

@@ -17,6 +17,7 @@
#include "town.h"
#include "news_func.h"
#include "cheat_type.h"
#include "company_base.h"
#include "genworld.h"
#include "tree_map.h"
#include "newgrf_cargo.h"
@@ -539,7 +540,7 @@ static bool TransportIndustryGoods(TileIndex tile)

i->this_month_production[j] += cw;

uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, &i->stations_near);
uint am = MoveGoodsToStation(i->produced_cargo[j], cw, ST_INDUSTRY, i->index, &i->stations_near, i->exclusive_consumer);
i->this_month_transported[j] += am;

moved_cargo |= (am != 0);
@@ -946,6 +947,9 @@ static void ChangeTileOwner_Industry(TileIndex tile, Owner old_owner, Owner new_
/* If the founder merges, the industry was created by the merged company */
Industry *i = Industry::GetByTile(tile);
if (i->founder == old_owner) i->founder = (new_owner == INVALID_OWNER) ? OWNER_NONE : new_owner;

if (i->exclusive_supplier == old_owner) i->exclusive_supplier = new_owner;
if (i->exclusive_consumer == old_owner) i->exclusive_consumer = new_owner;
}

/**
@@ -1764,6 +1768,9 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
* else, chosen layout + 1 */
i->selected_layout = (byte)(layout_index + 1);

i->exclusive_supplier = INVALID_OWNER;
i->exclusive_consumer = INVALID_OWNER;

i->prod_level = PRODLEVEL_DEFAULT;

/* Call callbacks after the regular fields got initialised. */
@@ -2058,8 +2065,13 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
* @param p2 various bitstuffed elements
* - p2 = (bit 0 - 7) - action to perform:
* 0 = set control flags
* 1 = set exclusive supplier
* 2 = set exclusive consumer
* - p2 = (bit 8 - 15) - IndustryControlFlags
* (only used with set control flags)
* - p2 = (bit 16 - 23) - CompanyID to set or INVALID_OWNER (available to everyone) or
* OWNER_NONE (neutral stations only) or OWNER_DEITY (no one)
* (only used with set exclusive supplier / consumer)
* @param text unused
* @return Empty cost or an error.
*/
@@ -2081,6 +2093,24 @@ CommandCost CmdIndustryCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
break;
}

case 1:
case 2: {
Owner company_id = (Owner)GB(p2, 16, 8);

if (company_id != OWNER_NONE && company_id != INVALID_OWNER && company_id != OWNER_DEITY
&& !Company::IsValidID(company_id)) return CMD_ERROR;

if (flags & DC_EXEC) {
if (action == 1) {
ind->exclusive_supplier = company_id;
} else {
ind->exclusive_consumer = company_id;
}
}

break;
}

default:
NOT_REACHED();
}
@@ -3125,6 +3125,14 @@ bool AfterLoadGame()
}
}

/* Make sure all industries exclusive supplier/consumer set correctly. */
if (IsSavegameVersionBefore(SLV_GS_INDUSTRY_CONTROL)) {
for (Industry *i : Industry::Iterate()) {
i->exclusive_supplier = INVALID_OWNER;
i->exclusive_consumer = INVALID_OWNER;
}
}

/* Compute station catchment areas. This is needed here in case UpdateStationAcceptance is called below. */
Station::RecomputeCatchmentForAll();

@@ -64,6 +64,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, last_cargo_accepted_at[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_cargo_accepted_at, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDVAR(Industry, selected_layout, SLE_UINT8, SLV_73, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_supplier, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),
SLE_CONDVAR(Industry, exclusive_consumer, SLE_UINT8, SLV_GS_INDUSTRY_CONTROL, SL_MAX_VERSION),

SLEG_CONDARR(_old_ind_persistent_storage.storage, SLE_UINT32, 16, SLV_76, SLV_161),
SLE_CONDREF(Industry, psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),
@@ -320,7 +320,7 @@ enum SaveLoadVersion : uint16 {
SLV_START_PATCHPACKS, ///< 220 First known patchpack to use a version just above ours.
SLV_END_PATCHPACKS = 286, ///< 286 Last known patchpack to use a version just above ours.

SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 GS industry control.
SLV_GS_INDUSTRY_CONTROL, ///< 287 PR#7912 and PR#8115 GS industry control.

SL_MAX_VERSION, ///< Highest possible saveload version
};
@@ -23,8 +23,12 @@
* \li GSEventStoryPageVehicleSelect
* \li GSIndustry::GetCargoLastAcceptedDate
* \li GSIndustry::GetControlFlags
* \li GSIndustry::GetExclusiveConsumer
* \li GSIndustry::GetExclusiveSupplier
* \li GSIndustry::GetLastProductionYear
* \li GSIndustry::SetControlFlags
* \li GSIndustry::SetExclusiveConsumer
* \li GSIndustry::SetExclusiveSupplier
* \li GSStoryPage::MakePushButtonReference
* \li GSStoryPage::MakeTileButtonReference
* \li GSStoryPage::MakeVehicleButtonReference
@@ -10,7 +10,10 @@
#include "../../stdafx.h"
#include "script_industry.hpp"
#include "script_cargo.hpp"
#include "script_company.hpp"
#include "script_error.hpp"
#include "script_map.hpp"
#include "../../company_base.h"
#include "../../industry.h"
#include "../../strings_func.h"
#include "../../station_base.h"
@@ -241,3 +244,41 @@ bool ScriptIndustry::SetControlFlags(IndustryID industry_id, uint32 control_flag

return ScriptObject::DoCommand(0, industry_id, 0 | ((control_flags & ::INDCTL_MASK) << 8), CMD_INDUSTRY_CTRL);
}

/* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveSupplier(IndustryID industry_id)
{
if (!IsValidIndustry(industry_id)) return ScriptCompany::COMPANY_INVALID;

auto company_id = ::Industry::Get(industry_id)->exclusive_supplier;
if (!::Company::IsValidID(company_id)) return ScriptCompany::COMPANY_INVALID;

return (ScriptCompany::CompanyID)((byte)company_id);
}

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

auto company = ScriptCompany::ResolveCompanyID(company_id);
::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
return ScriptObject::DoCommand(0, industry_id, 1 | (((uint8)owner) << 16), CMD_INDUSTRY_CTRL);
}

/* static */ ScriptCompany::CompanyID ScriptIndustry::GetExclusiveConsumer(IndustryID industry_id)
{
if (!IsValidIndustry(industry_id)) return ScriptCompany::COMPANY_INVALID;

auto company_id = ::Industry::Get(industry_id)->exclusive_consumer;
if (!::Company::IsValidID(company_id)) return ScriptCompany::COMPANY_INVALID;

return (ScriptCompany::CompanyID)((byte)company_id);
}

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

auto company = ScriptCompany::ResolveCompanyID(company_id);
::Owner owner = (company == ScriptCompany::COMPANY_INVALID ? ::INVALID_OWNER : (::Owner)company);
return ScriptObject::DoCommand(0, industry_id, 2 | (((uint8)owner) << 16), CMD_INDUSTRY_CTRL);
}
@@ -10,8 +10,9 @@
#ifndef SCRIPT_INDUSTRY_HPP
#define SCRIPT_INDUSTRY_HPP

#include "script_object.hpp"
#include "script_company.hpp"
#include "script_date.hpp"
#include "script_object.hpp"
#include "../../industry.h"

/**
@@ -259,6 +260,47 @@ class ScriptIndustry : public ScriptObject {
* @api -ai
*/
static bool SetControlFlags(IndustryID industry_id, uint32 control_flags);

/**
* Find out which company currently has the exclusive rights to deliver cargo to the industry.
* @param industry_id The index of the industry.
* @pre IsValidIndustry(industry_id).
* @return The company that has the exclusive rights. The value
* ScriptCompany::COMPANY_INVALID means that there are currently no
* exclusive rights given out to anyone.
*/
static ScriptCompany::CompanyID GetExclusiveSupplier(IndustryID industry_id);

/**
* Sets or resets the company that has exclusive right to deliver cargo to 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).
* @return True if the action succeeded.
* @api -ai
*/
static bool SetExclusiveSupplier(IndustryID industry_id, ScriptCompany::CompanyID company_id);

/**
* Find out which company currently has the exclusive rights to take cargo from the industry.
* @param industry_id The index of the industry.
* @pre IsValidIndustry(industry_id).
* @return The company that has the exclusive rights. The value
* ScriptCompany::COMPANY_SPECTATOR means that there are currently no
* exclusive rights given out to anyone.
*/
static ScriptCompany::CompanyID GetExclusiveConsumer(IndustryID industry_id);

/**
* 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).
* @return True if the action succeeded.
* @api -ai
*/
static bool SetExclusiveConsumer(IndustryID industry_id, ScriptCompany::CompanyID company_id);

};

#endif /* SCRIPT_INDUSTRY_HPP */
@@ -4013,7 +4013,7 @@ static bool CanMoveGoodsToStation(const Station *st, CargoID type)
return true;
}

uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations)
uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, SourceID source_id, const StationList *all_stations, Owner exclusivity)
{
/* Return if nothing to do. Also the rounding below fails for 0. */
if (all_stations->empty()) return 0;
@@ -4024,6 +4024,7 @@ uint MoveGoodsToStation(CargoID type, uint amount, SourceType source_type, Sourc
std::vector<StationInfo> used_stations;

for (Station *st : *all_stations) {
if (exclusivity != INVALID_OWNER && exclusivity != st->owner) continue;
if (!CanMoveGoodsToStation(st, type)) continue;

/* Avoid allocating a vector if there is only one station to significantly

1 comment on commit 9a45a0f

@SamuXarick

This comment has been minimized.

Copy link
Contributor

@SamuXarick SamuXarick commented on 9a45a0f Dec 22, 2020

I have some concerns about this. Not sure if this is the right place to ask, but here goes...

How would players or AIs know that an industry is exclusive to someone else? I think there should be some indication in the industry window, maybe also in the industry directory.

What happens to exclusivity when a company bankrupts? What about oil rigs with their neutral station?

Please sign in to comment.