Change: Reorganise industry accept/produce arrays. (#10853)

Use a array of struct for each cargo instead of an array for each statistic.
This makes iterating for acceptance and production much simpler.
pct_transported is now calculated when needed.
pull/564/head
PeterN 1 year ago committed by GitHub
parent db3b086a52
commit 584faaf064
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1017,9 +1017,9 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
Industry *ind = i.industry;
if (ind->index == source) continue;
int cargo_index = ind->GetCargoAcceptedIndex(cargo_type);
auto it = ind->GetCargoAccepted(cargo_type);
/* Check if matching cargo has been found */
if (cargo_index < 0) continue;
if (it == std::end(ind->accepted)) continue;
/* Check if industry temporarily refuses acceptance */
if (IndustryTemporarilyRefusesCargo(ind, cargo_type)) continue;
@ -1029,9 +1029,9 @@ static uint DeliverGoodsToIndustry(const Station *st, CargoID cargo_type, uint n
/* Insert the industry into _cargo_delivery_destinations, if not yet contained */
include(_cargo_delivery_destinations, ind);
uint amount = std::min(num_pieces, 0xFFFFu - ind->incoming_cargo_waiting[cargo_index]);
ind->incoming_cargo_waiting[cargo_index] += amount;
ind->last_cargo_accepted_at[cargo_index] = TimerGameCalendar::date;
uint amount = std::min(num_pieces, 0xFFFFu - it->waiting);
it->waiting += amount;
it->last_accepted = TimerGameCalendar::date;
num_pieces -= amount;
accepted += amount;
@ -1119,15 +1119,14 @@ static void TriggerIndustryProduction(Industry *i)
SetWindowDirty(WC_INDUSTRY_VIEW, i->index);
}
} else {
for (uint ci_in = 0; ci_in < lengthof(i->incoming_cargo_waiting); ci_in++) {
uint cargo_waiting = i->incoming_cargo_waiting[ci_in];
if (cargo_waiting == 0) continue;
for (auto ita = std::begin(i->accepted); ita != std::end(i->accepted); ++ita) {
if (ita->waiting == 0) continue;
for (uint ci_out = 0; ci_out < lengthof(i->produced_cargo_waiting); ci_out++) {
i->produced_cargo_waiting[ci_out] = ClampTo<uint16_t>(i->produced_cargo_waiting[ci_out] + (cargo_waiting * indspec->input_cargo_multiplier[ci_in][ci_out] / 256));
for (auto itp = std::begin(i->produced); itp != std::end(i->produced); ++itp) {
itp->waiting = ClampTo<uint16_t>(itp->waiting + (ita->waiting * indspec->input_cargo_multiplier[ita - std::begin(i->accepted)][itp - std::begin(i->produced)] / 256));
}
i->incoming_cargo_waiting[ci_in] = 0;
ita->waiting = 0;
}
}

@ -56,24 +56,46 @@ enum IndustryControlFlags : byte {
};
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
uint16_t transported; ///< Total transported
uint8_t PctTransported() const
{
if (this->production == 0) return 0;
return ClampTo<uint8_t>(this->transported * 256 / this->production);
}
};
struct ProducedCargo {
CargoID cargo; ///< Cargo type
uint16_t waiting; ///< Amount of cargo produced
uint8_t rate; ///< Production rate
std::array<ProducedHistory, 2> history; ///< History of cargo produced and transported
};
struct AcceptedCargo {
CargoID cargo; ///< Cargo type
uint16_t waiting; ///< Amount of cargo waiting to processed
TimerGameCalendar::Date last_accepted; ///< Last day cargo was accepted by this industry
};
using ProducedCargoArray = std::array<ProducedCargo, INDUSTRY_NUM_OUTPUTS>;
using AcceptedCargoArray = std::array<AcceptedCargo, INDUSTRY_NUM_INPUTS>;
TileArea location; ///< Location of the industry
Town *town; ///< Nearest town
Station *neutral_station; ///< Associated neutral station
CargoID produced_cargo[INDUSTRY_NUM_OUTPUTS]; ///< 16 production cargo slots
uint16 produced_cargo_waiting[INDUSTRY_NUM_OUTPUTS]; ///< amount of cargo produced per cargo
uint16 incoming_cargo_waiting[INDUSTRY_NUM_INPUTS]; ///< incoming cargo waiting to be processed
byte production_rate[INDUSTRY_NUM_OUTPUTS]; ///< production rate for each cargo
ProducedCargoArray produced; ///< INDUSTRY_NUM_OUTPUTS production cargo slots
AcceptedCargoArray accepted; ///< INDUSTRY_NUM_INPUTS input cargo slots
byte prod_level; ///< general production level
CargoID accepts_cargo[INDUSTRY_NUM_INPUTS]; ///< 16 input cargo slots
uint16 this_month_production[INDUSTRY_NUM_OUTPUTS]; ///< stats of this month's production per cargo
uint16 this_month_transported[INDUSTRY_NUM_OUTPUTS]; ///< stats of this month's transport per cargo
byte last_month_pct_transported[INDUSTRY_NUM_OUTPUTS]; ///< percentage transported per cargo in the last full month
uint16 last_month_production[INDUSTRY_NUM_OUTPUTS]; ///< total units produced per cargo in the last full month
uint16 last_month_transported[INDUSTRY_NUM_OUTPUTS]; ///< total units transported per cargo in the last full month
uint16 counter; ///< used for animation and/or production (if available cargo)
IndustryType type; ///< type of industry.
@ -90,7 +112,6 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
Owner founder; ///< Founder of the industry
TimerGameCalendar::Date construction_date; ///< Date of the construction of the industry
uint8 construction_type; ///< Way the industry was constructed (@see IndustryConstructionType)
TimerGameCalendar::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)
@ -115,43 +136,39 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> {
return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index;
}
inline int GetCargoProducedIndex(CargoID cargo) const
inline ProducedCargoArray::iterator GetCargoProduced(CargoID cargo)
{
if (!IsValidCargoID(cargo)) return -1;
const CargoID *pos = std::find(this->produced_cargo, endof(this->produced_cargo), cargo);
if (pos == endof(this->produced_cargo)) return -1;
return pos - this->produced_cargo;
if (!IsValidCargoID(cargo)) return std::end(this->produced);
return std::find_if(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; });
}
inline int GetCargoAcceptedIndex(CargoID cargo) const
inline AcceptedCargoArray::iterator GetCargoAccepted(CargoID cargo)
{
if (!IsValidCargoID(cargo)) return -1;
const CargoID *pos = std::find(this->accepts_cargo, endof(this->accepts_cargo), cargo);
if (pos == endof(this->accepts_cargo)) return -1;
return pos - this->accepts_cargo;
if (!IsValidCargoID(cargo)) return std::end(this->accepted);
return std::find_if(std::begin(this->accepted), std::end(this->accepted), [&cargo](const auto &a) { return a.cargo == cargo; });
}
/** Test if this industry accepts any cargo.
* @return true iff the industry accepts any cargo.
*/
bool IsCargoAccepted() const { return std::any_of(std::begin(this->accepts_cargo), std::end(this->accepts_cargo), [](const auto &cargo) { return IsValidCargoID(cargo); }); }
bool IsCargoAccepted() const { return std::any_of(std::begin(this->accepted), std::end(this->accepted), [](const auto &a) { return IsValidCargoID(a.cargo); }); }
/** Test if this industry produces any cargo.
* @return true iff the industry produces any cargo.
*/
bool IsCargoProduced() const { return std::any_of(std::begin(this->produced_cargo), std::end(this->produced_cargo), [](const auto &cargo) { return IsValidCargoID(cargo); }); }
bool IsCargoProduced() const { return std::any_of(std::begin(this->produced), std::end(this->produced), [](const auto &p) { return IsValidCargoID(p.cargo); }); }
/** Test if this industry accepts a specific cargo.
* @param cargo Cargo type to test.
* @return true iff the industry accepts the given cargo type.
*/
bool IsCargoAccepted(CargoID cargo) const { return std::any_of(std::begin(this->accepts_cargo), std::end(this->accepts_cargo), [&cargo](const auto &cid) { return cid == cargo; }); }
bool IsCargoAccepted(CargoID cargo) const { return std::any_of(std::begin(this->accepted), std::end(this->accepted), [&cargo](const auto &a) { return a.cargo == cargo; }); }
/** Test if this industry produces a specific cargo.
* @param cargo Cargo type to test.
* @return true iff the industry produces the given cargo types.
*/
bool IsCargoProduced(CargoID cargo) const { return std::any_of(std::begin(this->produced_cargo), std::end(this->produced_cargo), [&cargo](const auto &cid) { return cid == cargo; }); }
bool IsCargoProduced(CargoID cargo) const { return std::any_of(std::begin(this->produced), std::end(this->produced), [&cargo](const auto &p) { return p.cargo == cargo; }); }
/**
* Get the industry of the given tile

@ -420,13 +420,13 @@ static void AddAcceptedCargo_Industry(TileIndex tile, CargoArray &acceptance, Ca
if (itspec->special_flags & INDTILE_SPECIAL_ACCEPTS_ALL_CARGO) {
/* Copy all accepted cargoes from industry itself */
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID *pos = std::find(accepts_cargo, endof(accepts_cargo), ind->accepts_cargo[i]);
for (const auto &a : ind->accepted) {
CargoID *pos = std::find(accepts_cargo, endof(accepts_cargo), a.cargo);
if (pos == endof(accepts_cargo)) {
/* Not found, insert */
pos = std::find(accepts_cargo, endof(accepts_cargo), CT_INVALID);
if (pos == endof(accepts_cargo)) continue; // nowhere to place, give up on this one
*pos = ind->accepts_cargo[i];
*pos = a.cargo;
}
cargo_acceptance[pos - accepts_cargo] += 8;
}
@ -524,18 +524,18 @@ static bool TransportIndustryGoods(TileIndex tile)
const IndustrySpec *indspec = GetIndustrySpec(i->type);
bool moved_cargo = false;
for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
uint cw = ClampTo<uint8_t>(i->produced_cargo_waiting[j]);
if (cw > indspec->minimal_cargo && IsValidCargoID(i->produced_cargo[j])) {
i->produced_cargo_waiting[j] -= cw;
for (auto &p : i->produced) {
uint cw = ClampTo<uint8_t>(p.waiting);
if (cw > indspec->minimal_cargo && IsValidCargoID(p.cargo)) {
p.waiting -= cw;
/* fluctuating economy? */
if (EconomyIsInRecession()) cw = (cw + 1) / 2;
i->this_month_production[j] += cw;
p.history[THIS_MONTH].production += cw;
uint am = MoveGoodsToStation(i->produced_cargo[j], cw, SourceType::Industry, i->index, &i->stations_near, i->exclusive_consumer);
i->this_month_transported[j] += am;
uint am = MoveGoodsToStation(p.cargo, cw, SourceType::Industry, i->index, &i->stations_near, i->exclusive_consumer);
p.history[THIS_MONTH].transported += am;
moved_cargo |= (am != 0);
}
@ -981,12 +981,7 @@ bool IsTileForestIndustry(TileIndex tile)
if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_ORGANIC) == 0) return false;
/* Check for wood production */
for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
/* The industry produces wood. */
if (IsValidCargoID(ind->produced_cargo[i]) && CargoSpec::Get(ind->produced_cargo[i])->label == 'WOOD') return true;
}
return false;
return std::any_of(std::begin(ind->produced), std::end(ind->produced), [](const auto &p) { return IsValidCargoID(p.cargo) && CargoSpec::Get(p.cargo)->label == 'WOOD'; });
}
static const byte _plantfarmfield_type[] = {1, 1, 1, 1, 1, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6};
@ -1134,7 +1129,7 @@ static void ChopLumberMillTrees(Industry *i)
TileIndex tile = i->location.tile;
if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search.
i->produced_cargo_waiting[0] = ClampTo<uint16_t>(i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo.
i->produced[0].waiting = ClampTo<uint16_t>(i->produced[0].waiting + 45); // Found a tree, add according value to waiting cargo.
}
}
@ -1146,14 +1141,11 @@ static void ProduceIndustryGoods(Industry *i)
if ((i->counter & 0x3F) == 0) {
uint32 r;
if (Chance16R(1, 14, r) && indsp->number_of_sounds != 0 && _settings_client.sound.ambient) {
for (size_t j = 0; j < lengthof(i->last_month_production); j++) {
if (i->last_month_production[j] > 0) {
/* Play sound since last month had production */
SndPlayTileFx(
(SoundFx)(indsp->random_sounds[((r >> 16) * indsp->number_of_sounds) >> 16]),
i->location.tile);
break;
}
if (std::any_of(std::begin(i->produced), std::end(i->produced), [](const auto &p) { return p.history[LAST_MONTH].production > 0; })) {
/* Play sound since last month had production */
SndPlayTileFx(
(SoundFx)(indsp->random_sounds[((r >> 16) * indsp->number_of_sounds) >> 16]),
i->location.tile);
}
}
}
@ -1165,8 +1157,8 @@ static void ProduceIndustryGoods(Industry *i)
if (HasBit(indsp->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) IndustryProductionCallback(i, 1);
IndustryBehaviour indbehav = indsp->behaviour;
for (size_t j = 0; j < lengthof(i->produced_cargo_waiting); j++) {
i->produced_cargo_waiting[j] = ClampTo<uint16_t>(i->produced_cargo_waiting[j] + i->production_rate[j]);
for (auto &p : i->produced) {
p.waiting = ClampTo<uint16_t>(p.waiting + p.rate);
}
if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) {
@ -1762,22 +1754,21 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
i->type = type;
Industry::IncIndustryTypeCount(type);
MemCpyT(i->produced_cargo, indspec->produced_cargo, lengthof(i->produced_cargo));
MemCpyT(i->production_rate, indspec->production_rate, lengthof(i->production_rate));
MemCpyT(i->accepts_cargo, indspec->accepts_cargo, lengthof(i->accepts_cargo));
for (auto it = std::begin(i->produced); it != std::end(i->produced); ++it) {
size_t index = it - std::begin(i->produced);
it->cargo = indspec->produced_cargo[index];
it->rate = indspec->production_rate[index];
}
MemSetT(i->produced_cargo_waiting, 0, lengthof(i->produced_cargo_waiting));
MemSetT(i->this_month_production, 0, lengthof(i->this_month_production));
MemSetT(i->this_month_transported, 0, lengthof(i->this_month_transported));
MemSetT(i->last_month_pct_transported, 0, lengthof(i->last_month_pct_transported));
MemSetT(i->last_month_transported, 0, lengthof(i->last_month_transported));
MemSetT(i->incoming_cargo_waiting, 0, lengthof(i->incoming_cargo_waiting));
MemSetT(i->last_cargo_accepted_at, 0, lengthof(i->last_cargo_accepted_at));
for (auto it = std::begin(i->accepted); it != std::end(i->accepted); ++it) {
size_t index = it - std::begin(i->accepted);
it->cargo = indspec->accepts_cargo[index];
}
/* Randomize inital production if non-original economy is used and there are no production related callbacks. */
if (!indspec->UsesOriginalEconomy()) {
for (size_t ci = 0; ci < lengthof(i->production_rate); ci++) {
i->production_rate[ci] = ClampTo<byte>((RandomRange(256) + 128) * i->production_rate[ci] >> 8);
for (auto &p : i->produced) {
p.rate = ClampTo<byte>((RandomRange(256) + 128) * p.rate >> 8);
}
}
@ -1824,14 +1815,14 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
if (_generating_world) {
if (HasBit(indspec->callback_mask, CBM_IND_PRODUCTION_256_TICKS)) {
IndustryProductionCallback(i, 1);
for (size_t ci = 0; ci < lengthof(i->last_month_production); ci++) {
i->last_month_production[ci] = i->produced_cargo_waiting[ci] * 8;
i->produced_cargo_waiting[ci] = 0;
for (auto &p : i->produced) {
p.history[LAST_MONTH].production = p.waiting * 8;
p.waiting = 0;
}
}
for (size_t ci = 0; ci < lengthof(i->last_month_production); ci++) {
i->last_month_production[ci] += i->production_rate[ci] * 8;
for (auto &p : i->produced) {
p.history[LAST_MONTH].production += p.rate * 8;
}
}
@ -1845,9 +1836,9 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
if (HasBit(indspec->callback_mask, CBM_IND_INPUT_CARGO_TYPES)) {
/* Clear all input cargo types */
for (uint j = 0; j < lengthof(i->accepts_cargo); j++) i->accepts_cargo[j] = CT_INVALID;
for (auto &a : i->accepted) a.cargo = CT_INVALID;
/* Query actual types */
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->accepts_cargo) : 3;
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? static_cast<uint>(i->accepted.size()) : 3;
for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_INPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
@ -1866,20 +1857,20 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
break;
}
if (std::find(i->accepts_cargo, i->accepts_cargo + j, cargo) != i->accepts_cargo + j) {
if (std::any_of(std::begin(i->accepted), std::begin(i->accepted) + j, [&cargo](const auto &a) { return a.cargo == cargo; })) {
/* Duplicate cargo */
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_INPUT_CARGO_TYPES, res);
break;
}
i->accepts_cargo[j] = cargo;
i->accepted[j].cargo = cargo;
}
}
if (HasBit(indspec->callback_mask, CBM_IND_OUTPUT_CARGO_TYPES)) {
/* Clear all output cargo types */
for (uint j = 0; j < lengthof(i->produced_cargo); j++) i->produced_cargo[j] = CT_INVALID;
for (auto &p : i->produced) p.cargo = CT_INVALID;
/* Query actual types */
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? lengthof(i->produced_cargo) : 2;
uint maxcargoes = (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) ? static_cast<uint>(i->produced.size()) : 2;
for (uint j = 0; j < maxcargoes; j++) {
uint16 res = GetIndustryCallback(CBID_INDUSTRY_OUTPUT_CARGO_TYPES, j, 0, i, type, INVALID_TILE);
if (res == CALLBACK_FAILED || GB(res, 0, 8) == CT_INVALID) break;
@ -1896,12 +1887,12 @@ static void DoCreateNewIndustry(Industry *i, TileIndex tile, IndustryType type,
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
break;
}
if (std::find(i->produced_cargo, i->produced_cargo + j, cargo) != i->produced_cargo + j) {
if (std::any_of(std::begin(i->produced), std::begin(i->produced) + j, [&cargo](const auto &p) { return p.cargo == cargo; })) {
/* Duplicate cargo */
ErrorUnknownCallbackResult(indspec->grf_prop.grffile->grfid, CBID_INDUSTRY_OUTPUT_CARGO_TYPES, res);
break;
}
i->produced_cargo[j] = cargo;
i->produced[j].cargo = cargo;
}
}
@ -2411,20 +2402,14 @@ void GenerateIndustries()
*/
static void UpdateIndustryStatistics(Industry *i)
{
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (IsValidCargoID(i->produced_cargo[j])) {
byte pct = 0;
if (i->this_month_production[j] != 0) {
i->last_prod_year = TimerGameCalendar::year;
pct = ClampTo<byte>(i->this_month_transported[j] * 256 / i->this_month_production[j]);
}
i->last_month_pct_transported[j] = pct;
i->last_month_production[j] = i->this_month_production[j];
i->this_month_production[j] = 0;
for (auto &p : i->produced) {
if (IsValidCargoID(p.cargo)) {
if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameCalendar::year;
i->last_month_transported[j] = i->this_month_transported[j];
i->this_month_transported[j] = 0;
/* Move history from this month to last month. */
std::rotate(std::rbegin(p.history), std::rbegin(p.history) + 1, std::rend(p.history));
p.history[THIS_MONTH].production = 0;
p.history[THIS_MONTH].transported = 0;
}
}
}
@ -2439,8 +2424,8 @@ void Industry::RecomputeProductionMultipliers()
assert(indspec->UsesOriginalEconomy());
/* Rates are rounded up, so e.g. oilrig always produces some passengers */
for (size_t i = 0; i < lengthof(this->production_rate); i++) {
this->production_rate[i] = ClampTo<byte>(CeilDiv(indspec->production_rate[i] * this->prod_level, PRODLEVEL_DEFAULT));
for (auto &p : this->produced) {
p.rate = ClampTo<uint8_t>(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT));
}
}
@ -2773,7 +2758,7 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
if (original_economy) {
if (only_decrease || Chance16(1, 3)) {
/* If more than 60% transported, 66% chance of increase, else 33% chance of increase */
if (!only_decrease && (i->last_month_pct_transported[0] > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
if (!only_decrease && (i->produced[0].history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) {
mul = 1; // Increase production
} else {
div = 1; // Decrease production
@ -2781,14 +2766,14 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
}
} else if (_settings_game.economy.type == ET_SMOOTH) {
closeit = !(i->ctlflags & (INDCTL_NO_CLOSURE | INDCTL_NO_PRODUCTION_DECREASE));
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (!IsValidCargoID(i->produced_cargo[j])) continue;
for (auto &p : i->produced) {
if (!IsValidCargoID(p.cargo)) continue;
uint32 r = Random();
int old_prod, new_prod, percent;
/* If over 60% is transported, mult is 1, else mult is -1. */
int mult = (i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_60) ? 1 : -1;
int mult = (p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) ? 1 : -1;
new_prod = old_prod = i->production_rate[j];
new_prod = old_prod = p.rate;
/* For industries with only_decrease flags (temperate terrain Oil Wells),
* the multiplier will always be -1 so they will only decrease. */
@ -2796,7 +2781,7 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
mult = -1;
/* For normal industries, if over 60% is transported, 33% chance for decrease.
* Bonus for very high station ratings (over 80%): 16% chance for decrease. */
} else if (Chance16I(1, ((i->last_month_pct_transported[j] > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
} else if (Chance16I(1, ((p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_80) ? 6 : 3), r)) {
mult *= -1;
}
@ -2808,7 +2793,7 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
/* Prevent production to overflow or Oil Rig passengers to be over-"produced" */
new_prod = Clamp(new_prod, 1, 255);
if (i->produced_cargo[j] == CT_PASSENGERS && !(indspec->behaviour & INDUSTRYBEH_NO_PAX_PROD_CLAMP)) {
if (p.cargo == CT_PASSENGERS && !(indspec->behaviour & INDUSTRYBEH_NO_PAX_PROD_CLAMP)) {
new_prod = Clamp(new_prod, 0, 16);
}
@ -2823,13 +2808,13 @@ static void ChangeIndustryProduction(Industry *i, bool monthly)
}
percent = (old_prod == 0) ? 100 : (new_prod * 100 / old_prod - 100);
i->production_rate[j] = new_prod;
p.rate = new_prod;
/* Close the industry when it has the lowest possible production rate */
if (new_prod > 1) closeit = false;
if (abs(percent) >= 10) {
ReportNewsProductionChangeIndustry(i, i->produced_cargo[j], percent);
ReportNewsProductionChangeIndustry(i, p.cargo, percent);
}
}
}

@ -189,6 +189,33 @@ static inline void GetAllCargoSuffixes(CargoSuffixInOut use_input, CargoSuffixTy
}
}
/**
* Gets the strings to display after the cargo of industries (using callback 37)
* @param use_input get suffixes for output cargo or input cargo?
* @param cst the cargo suffix type (for which window is it requested). @see CargoSuffixType
* @param ind the industry (nullptr if in fund window)
* @param ind_type the industry type
* @param indspec the industry spec
* @param cargo cargotype. for CT_INVALID no suffix will be determined
* @param slot accepts/produced slot number, used for old-style 3-in/2-out industries.
* @param suffix is filled with the suffix
*/
void GetCargoSuffix(CargoSuffixInOut use_input, CargoSuffixType cst, const Industry *ind, IndustryType ind_type, const IndustrySpec *indspec, CargoID cargo, uint8_t slot, CargoSuffix &suffix)
{
suffix.text[0] = '\0';
suffix.display = CSD_CARGO;
if (!IsValidCargoID(cargo)) return;
if (indspec->behaviour & INDUSTRYBEH_CARGOTYPES_UNLIMITED) {
byte local_id = indspec->grf_prop.grffile->cargo_map[cargo]; // should we check the value for valid?
uint cargotype = local_id << 16 | use_input;
GetCargoSuffix(cargotype, cst, ind, ind_type, indspec, suffix);
} else if (use_input == CARGOSUFFIX_IN) {
if (slot < 3) GetCargoSuffix(slot, cst, ind, ind_type, indspec, suffix);
} else if (use_input == CARGOSUFFIX_OUT) {
if (slot < 2) GetCargoSuffix(slot + 3, cst, ind, ind_type, indspec, suffix);
}
}
std::array<IndustryType, NUM_INDUSTRYTYPES> _sorted_industry_types; ///< Industry types sorted by name.
/** Sort industry types by their name. */
@ -840,33 +867,35 @@ public:
ir.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_wide;
}
CargoSuffix cargo_suffix[lengthof(i->accepts_cargo)];
GetAllCargoSuffixes(CARGOSUFFIX_IN, CST_VIEW, i, i->type, ind, i->accepts_cargo, cargo_suffix);
bool stockpiling = HasBit(ind->callback_mask, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_mask, CBM_IND_PRODUCTION_256_TICKS);
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (!IsValidCargoID(i->accepts_cargo[j])) continue;
for (const auto &a : i->accepted) {
if (!IsValidCargoID(a.cargo)) continue;
has_accept = true;
if (first) {
DrawString(ir, STR_INDUSTRY_VIEW_REQUIRES);
ir.top += FONT_HEIGHT_NORMAL;
first = false;
}
SetDParam(0, CargoSpec::Get(i->accepts_cargo[j])->name);
SetDParam(1, i->accepts_cargo[j]);
SetDParam(2, i->incoming_cargo_waiting[j]);
CargoSuffix suffix;
GetCargoSuffix(CARGOSUFFIX_IN, CST_VIEW, i, i->type, ind, a.cargo, &a - i->accepted.data(), suffix);
SetDParam(0, CargoSpec::Get(a.cargo)->name);
SetDParam(1, a.cargo);
SetDParam(2, a.waiting);
SetDParamStr(3, "");
StringID str = STR_NULL;
switch (cargo_suffix[j].display) {
switch (suffix.display) {
case CSD_CARGO_AMOUNT_TEXT:
SetDParamStr(3, cargo_suffix[j].text);
SetDParamStr(3, suffix.text);
FALLTHROUGH;
case CSD_CARGO_AMOUNT:
str = stockpiling ? STR_INDUSTRY_VIEW_ACCEPT_CARGO_AMOUNT : STR_INDUSTRY_VIEW_ACCEPT_CARGO;
break;
case CSD_CARGO_TEXT:
SetDParamStr(3, cargo_suffix[j].text);
SetDParamStr(3, suffix.text);
FALLTHROUGH;
case CSD_CARGO:
str = STR_INDUSTRY_VIEW_ACCEPT_CARGO;
@ -879,13 +908,12 @@ public:
ir.top += FONT_HEIGHT_NORMAL;
}
GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_VIEW, i, i->type, ind, i->produced_cargo, cargo_suffix);
int line_height = this->editable == EA_RATE ? this->cheat_line_height : FONT_HEIGHT_NORMAL;
int text_y_offset = (line_height - FONT_HEIGHT_NORMAL) / 2;
int button_y_offset = (line_height - SETTING_BUTTON_HEIGHT) / 2;
first = true;
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (!IsValidCargoID(i->produced_cargo[j])) continue;
for (const auto &p : i->produced) {
if (!IsValidCargoID(p.cargo)) continue;
if (first) {
if (has_accept) ir.top += WidgetDimensions::scaled.vsep_wide;
DrawString(ir, STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE);
@ -894,15 +922,18 @@ public:
first = false;
}
SetDParam(0, i->produced_cargo[j]);
SetDParam(1, i->last_month_production[j]);
SetDParamStr(2, cargo_suffix[j].text);
SetDParam(3, ToPercent8(i->last_month_pct_transported[j]));
CargoSuffix suffix;
GetCargoSuffix(CARGOSUFFIX_OUT, CST_VIEW, i, i->type, ind, p.cargo, &p - i->produced.data(), suffix);
SetDParam(0, p.cargo);
SetDParam(1, p.history[LAST_MONTH].production);
SetDParamStr(2, suffix.text);
SetDParam(3, ToPercent8(p.history[LAST_MONTH].PctTransported()));
DrawString(ir.Indent(WidgetDimensions::scaled.hsep_indent + (this->editable == EA_RATE ? SETTING_BUTTON_WIDTH + WidgetDimensions::scaled.hsep_normal : 0), rtl).Translate(0, text_y_offset), STR_INDUSTRY_VIEW_TRANSPORTED);
/* Let's put out those buttons.. */
if (this->editable == EA_RATE) {
DrawArrowButtons(ir.Indent(WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(SETTING_BUTTON_WIDTH, rtl).left, ir.top + button_y_offset, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + j) ? this->clicked_button : 0,
i->production_rate[j] > 0, i->production_rate[j] < 255);
DrawArrowButtons(ir.Indent(WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(SETTING_BUTTON_WIDTH, rtl).left, ir.top + button_y_offset, COLOUR_YELLOW, (this->clicked_line == IL_RATE1 + (&p - i->produced.data())) ? this->clicked_button : 0,
p.rate > 0, p.rate < 255);
}
ir.top += line_height;
}
@ -980,11 +1011,11 @@ public:
case EA_RATE:
if (pt.y >= this->production_offset_y) {
int row = (pt.y - this->production_offset_y) / this->cheat_line_height;
for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
if (!IsValidCargoID(i->produced_cargo[j])) continue;
for (auto itp = std::begin(i->produced); itp != std::end(i->produced); ++itp) {
if (!IsValidCargoID(itp->cargo)) continue;
row--;
if (row < 0) {
line = (InfoLine)(IL_RATE1 + j);
line = (InfoLine)(IL_RATE1 + (itp - std::begin(i->produced)));
break;
}
}
@ -1012,13 +1043,13 @@ public:
case EA_RATE:
if (decrease) {
if (i->production_rate[line - IL_RATE1] <= 0) return;
i->production_rate[line - IL_RATE1] = std::max(i->production_rate[line - IL_RATE1] / 2, 0);
if (i->produced[line - IL_RATE1].rate <= 0) return;
i->produced[line - IL_RATE1].rate = std::max(i->produced[line - IL_RATE1].rate / 2, 0);
} else {
if (i->production_rate[line - IL_RATE1] >= 255) return;
if (i->produced[line - IL_RATE1].rate >= 255) return;
/* a zero production industry is unlikely to give anything but zero, so push it a little bit */
int new_prod = i->production_rate[line - IL_RATE1] == 0 ? 1 : i->production_rate[line - IL_RATE1] * 2;
i->production_rate[line - IL_RATE1] = ClampTo<byte>(new_prod);
int new_prod = i->produced[line - IL_RATE1].rate == 0 ? 1 : i->produced[line - IL_RATE1].rate * 2;
i->produced[line - IL_RATE1].rate = ClampTo<byte>(new_prod);
}
break;
@ -1040,7 +1071,7 @@ public:
break;
case EA_RATE:
SetDParam(0, i->production_rate[line - IL_RATE1] * 8);
SetDParam(0, i->produced[line - IL_RATE1].rate * 8);
ShowQueryString(STR_JUST_INT, STR_CONFIG_GAME_PRODUCTION, 10, this, CS_ALPHANUMERAL, QSF_NONE);
break;
@ -1099,7 +1130,7 @@ public:
break;
default:
i->production_rate[this->editbox_line - IL_RATE1] = ClampU(RoundDivSU(value, 8), 0, 255);
i->produced[this->editbox_line - IL_RATE1].rate = ClampU(RoundDivSU(value, 8), 0, 255);
break;
}
UpdateIndustryProduction(i);
@ -1139,9 +1170,9 @@ static void UpdateIndustryProduction(Industry *i)
const IndustrySpec *indspec = GetIndustrySpec(i->type);
if (indspec->UsesOriginalEconomy()) i->RecomputeProductionMultipliers();
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (IsValidCargoID(i->produced_cargo[j])) {
i->last_month_production[j] = 8 * i->production_rate[j];
for (auto &p : i->produced) {
if (IsValidCargoID(p.cargo)) {
p.history[LAST_MONTH].production = 8 * p.rate;
}
}
}
@ -1415,12 +1446,10 @@ protected:
* @param id cargo slot
* @return percents of cargo transported, or -1 if industry doesn't use this cargo slot
*/
static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id)
static inline int GetCargoTransportedPercentsIfValid(const Industry::ProducedCargo &p)
{
assert(id < lengthof(i->produced_cargo));
if (!IsValidCargoID(i->produced_cargo[id])) return -1;
return ToPercent8(i->last_month_pct_transported[id]);
if (!IsValidCargoID(p.cargo)) return -1;
return ToPercent8(p.history[LAST_MONTH].PctTransported());
}
/**
@ -1436,18 +1465,18 @@ protected:
if (filter == CF_NONE) return 0;
int percentage = 0, produced_cargo_count = 0;
for (uint id = 0; id < lengthof(i->produced_cargo); id++) {
for (const auto &p : i->produced) {
if (filter == CF_ANY) {
int transported = GetCargoTransportedPercentsIfValid(i, id);
int transported = GetCargoTransportedPercentsIfValid(p);
if (transported != -1) {
produced_cargo_count++;
percentage += transported;
}
if (produced_cargo_count == 0 && id == lengthof(i->produced_cargo) - 1 && percentage == 0) {
if (produced_cargo_count == 0 && &p == &i->produced.back() && percentage == 0) {
return transported;
}
} else if (filter == i->produced_cargo[id]) {
return GetCargoTransportedPercentsIfValid(i, id);
} else if (filter == p.cargo) {
return GetCargoTransportedPercentsIfValid(p);
}
}
@ -1481,13 +1510,13 @@ protected:
if (filter == CF_NONE) return IndustryTypeSorter(a, b);
uint prod_a = 0, prod_b = 0;
for (uint i = 0; i < lengthof(a->produced_cargo); i++) {
for (auto ita = std::begin(a->produced), itb = std::begin(b->produced); ita != std::end(a->produced) && itb != std::end(b->produced); ++ita, ++itb) {
if (filter == CF_ANY) {
if (IsValidCargoID(a->produced_cargo[i])) prod_a += a->last_month_production[i];
if (IsValidCargoID(b->produced_cargo[i])) prod_b += b->last_month_production[i];
if (IsValidCargoID(ita->cargo)) prod_a += ita->history[LAST_MONTH].production;
if (IsValidCargoID(itb->cargo)) prod_b += ita->history[LAST_MONTH].production;
} else {
if (a->produced_cargo[i] == filter) prod_a += a->last_month_production[i];
if (b->produced_cargo[i] == filter) prod_b += b->last_month_production[i];
if (ita->cargo == filter) prod_a += ita->history[LAST_MONTH].production;
if (itb->cargo == filter) prod_b += itb->history[LAST_MONTH].production;
}
}
int r = prod_a - prod_b;
@ -1515,8 +1544,7 @@ protected:
/* Industry name */
SetDParam(p++, i->index);
static CargoSuffix cargo_suffix[lengthof(i->produced_cargo)];
GetAllCargoSuffixes(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, i->produced_cargo, cargo_suffix);
static CargoSuffix cargo_suffix[INDUSTRY_NUM_OUTPUTS];
/* Get industry productions (CargoID, production, suffix, transported) */
struct CargoInfo {
@ -1527,9 +1555,10 @@ protected:
};
std::vector<CargoInfo> cargos;
for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
if (!IsValidCargoID(i->produced_cargo[j])) continue;
cargos.push_back({ i->produced_cargo[j], i->last_month_production[j], cargo_suffix[j].text.c_str(), ToPercent8(i->last_month_pct_transported[j]) });
for (auto itp = std::begin(i->produced); itp != std::end(i->produced); ++itp) {
if (!IsValidCargoID(itp->cargo)) continue;
GetCargoSuffix(CARGOSUFFIX_OUT, CST_DIR, i, i->type, indsp, itp->cargo, itp - std::begin(i->produced), cargo_suffix[itp - std::begin(i->produced)]);
cargos.push_back({ itp->cargo, itp->history[LAST_MONTH].production, cargo_suffix[itp - std::begin(i->produced)].text.c_str(), ToPercent8(itp->history[LAST_MONTH].PctTransported()) });
}
switch (static_cast<IndustryDirectoryWindow::SorterType>(this->industries.SortType())) {

@ -214,9 +214,9 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
if (HasBit(callback, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(callback, CBM_IND_PRODUCTION_256_TICKS)) {
if ((indspec->behaviour & INDUSTRYBEH_PROD_MULTI_HNDLING) != 0) {
if (this->industry->prod_level == 0) return 0;
return ClampTo<uint16>(this->industry->incoming_cargo_waiting[variable - 0x40] / this->industry->prod_level);
return ClampTo<uint16>(this->industry->accepted[variable - 0x40].waiting / this->industry->prod_level);
} else {
return ClampTo<uint16>(this->industry->incoming_cargo_waiting[variable - 0x40]);
return ClampTo<uint16>(this->industry->accepted[variable - 0x40].waiting);
}
} else {
return 0;
@ -317,16 +317,16 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
case 0x71: {
CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
if (!IsValidCargoID(cargo)) return 0;
int index = this->industry->GetCargoProducedIndex(cargo);
if (index < 0) return 0; // invalid cargo
auto it = this->industry->GetCargoProduced(cargo);
if (it == std::end(this->industry->produced)) return 0; // invalid cargo
switch (variable) {
case 0x69: return this->industry->produced_cargo_waiting[index];
case 0x6A: return this->industry->this_month_production[index];
case 0x6B: return this->industry->this_month_transported[index];
case 0x6C: return this->industry->last_month_production[index];
case 0x6D: return this->industry->last_month_transported[index];
case 0x70: return this->industry->production_rate[index];
case 0x71: return this->industry->last_month_pct_transported[index];
case 0x69: return it->waiting;
case 0x6A: return it->history[THIS_MONTH].production;
case 0x6B: return it->history[THIS_MONTH].transported;
case 0x6C: return it->history[LAST_MONTH].production;
case 0x6D: return it->history[LAST_MONTH].transported;
case 0x70: return it->rate;
case 0x71: return it->history[LAST_MONTH].PctTransported();
default: NOT_REACHED();
}
}
@ -336,10 +336,10 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
case 0x6F: {
CargoID cargo = GetCargoTranslation(parameter, this->ro.grffile);
if (!IsValidCargoID(cargo)) return 0;
int index = this->industry->GetCargoAcceptedIndex(cargo);
if (index < 0) return 0; // invalid cargo
if (variable == 0x6E) return this->industry->last_cargo_accepted_at[index];
if (variable == 0x6F) return this->industry->incoming_cargo_waiting[index];
auto it = this->industry->GetCargoAccepted(cargo);
if (it == std::end(this->industry->accepted)) return 0; // invalid cargo
if (variable == 0x6E) return it->last_accepted;
if (variable == 0x6F) return it->waiting;
NOT_REACHED();
}
@ -358,40 +358,40 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
case 0x87: return this->industry->location.h;// xy dimensions
case 0x88:
case 0x89: return this->industry->produced_cargo[variable - 0x88];
case 0x8A: return this->industry->produced_cargo_waiting[0];
case 0x8B: return GB(this->industry->produced_cargo_waiting[0], 8, 8);
case 0x8C: return this->industry->produced_cargo_waiting[1];
case 0x8D: return GB(this->industry->produced_cargo_waiting[1], 8, 8);
case 0x89: return this->industry->produced[variable - 0x88].cargo;
case 0x8A: return this->industry->produced[0].waiting;
case 0x8B: return GB(this->industry->produced[0].waiting, 8, 8);
case 0x8C: return this->industry->produced[1].waiting;
case 0x8D: return GB(this->industry->produced[1].waiting, 8, 8);
case 0x8E:
case 0x8F: return this->industry->production_rate[variable - 0x8E];
case 0x8F: return this->industry->produced[variable - 0x8E].rate;
case 0x90:
case 0x91:
case 0x92: return this->industry->accepts_cargo[variable - 0x90];
case 0x92: return this->industry->accepted[variable - 0x90].cargo;
case 0x93: return this->industry->prod_level;
/* amount of cargo produced so far THIS month. */
case 0x94: return this->industry->this_month_production[0];
case 0x95: return GB(this->industry->this_month_production[0], 8, 8);
case 0x96: return this->industry->this_month_production[1];
case 0x97: return GB(this->industry->this_month_production[1], 8, 8);
case 0x94: return this->industry->produced[0].history[THIS_MONTH].production;
case 0x95: return GB(this->industry->produced[0].history[THIS_MONTH].production, 8, 8);
case 0x96: return this->industry->produced[1].history[THIS_MONTH].production;
case 0x97: return GB(this->industry->produced[1].history[THIS_MONTH].production, 8, 8);
/* amount of cargo transported so far THIS month. */
case 0x98: return this->industry->this_month_transported[0];
case 0x99: return GB(this->industry->this_month_transported[0], 8, 8);
case 0x9A: return this->industry->this_month_transported[1];
case 0x9B: return GB(this->industry->this_month_transported[1], 8, 8);
case 0x98: return this->industry->produced[0].history[THIS_MONTH].transported;
case 0x99: return GB(this->industry->produced[0].history[THIS_MONTH].transported, 8, 8);
case 0x9A: return this->industry->produced[1].history[THIS_MONTH].transported;
case 0x9B: return GB(this->industry->produced[1].history[THIS_MONTH].transported, 8, 8);
/* fraction of cargo transported LAST month. */
case 0x9C:
case 0x9D: return this->industry->last_month_pct_transported[variable - 0x9C];
case 0x9D: return this->industry->produced[variable - 0x9C].history[LAST_MONTH].PctTransported();
/* amount of cargo produced LAST month. */
case 0x9E: return this->industry->last_month_production[0];
case 0x9F: return GB(this->industry->last_month_production[0], 8, 8);
case 0xA0: return this->industry->last_month_production[1];
case 0xA1: return GB(this->industry->last_month_production[1], 8, 8);
case 0x9E: return this->industry->produced[0].history[LAST_MONTH].production;
case 0x9F: return GB(this->industry->produced[0].history[LAST_MONTH].production, 8, 8);
case 0xA0: return this->industry->produced[1].history[LAST_MONTH].production;
case 0xA1: return GB(this->industry->produced[1].history[LAST_MONTH].production, 8, 8);
/* amount of cargo transported last month. */
case 0xA2: return this->industry->last_month_transported[0];
case 0xA3: return GB(this->industry->last_month_transported[0], 8, 8);
case 0xA4: return this->industry->last_month_transported[1];
case 0xA5: return GB(this->industry->last_month_transported[1], 8, 8);
case 0xA2: return this->industry->produced[0].history[LAST_MONTH].transported;
case 0xA3: return GB(this->industry->produced[0].history[LAST_MONTH].transported, 8, 8);
case 0xA4: return this->industry->produced[1].history[LAST_MONTH].transported;
case 0xA5: return GB(this->industry->produced[1].history[LAST_MONTH].transported, 8, 8);
case 0xA6: return indspec->grf_prop.local_id;
case 0xA7: return this->industry->founder;
@ -404,8 +404,8 @@ static uint32 GetCountAndDistanceOfClosestInstance(byte param_setID, byte layout
case 0xB0: return ClampTo<uint16_t>(this->industry->construction_date - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date when built since 1920 (in days)
case 0xB3: return this->industry->construction_type; // Construction type
case 0xB4: {
TimerGameCalendar::Date *latest = std::max_element(this->industry->last_cargo_accepted_at, endof(this->industry->last_cargo_accepted_at));
return ClampTo<uint16_t>((*latest) - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
auto it = std::max_element(std::begin(this->industry->accepted), std::end(this->industry->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
return ClampTo<uint16_t>(it->last_accepted - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days)
}
}
@ -643,22 +643,22 @@ void IndustryProductionCallback(Industry *ind, int reason)
if (group->version < 2) {
/* Callback parameters map directly to industry cargo slot indices */
for (uint i = 0; i < group->num_input; i++) {
ind->incoming_cargo_waiting[i] = ClampTo<uint16_t>(ind->incoming_cargo_waiting[i] - DerefIndProd(group->subtract_input[i], deref) * multiplier);
ind->accepted[i].waiting = ClampTo<uint16_t>(ind->accepted[i].waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier);
}
for (uint i = 0; i < group->num_output; i++) {
ind->produced_cargo_waiting[i] = ClampTo<uint16_t>(ind->produced_cargo_waiting[i] + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
ind->produced[i].waiting = ClampTo<uint16_t>(ind->produced[i].waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
}
} else {
/* Callback receives list of cargos to apply for, which need to have their cargo slots in industry looked up */
for (uint i = 0; i < group->num_input; i++) {
int cargo_index = ind->GetCargoAcceptedIndex(group->cargo_input[i]);
if (cargo_index < 0) continue;
ind->incoming_cargo_waiting[cargo_index] = ClampTo<uint16_t>(ind->incoming_cargo_waiting[cargo_index] - DerefIndProd(group->subtract_input[i], deref) * multiplier);
auto it = ind->GetCargoAccepted(group->cargo_input[i]);
if (it == std::end(ind->accepted)) continue;
it->waiting = ClampTo<uint16_t>(it->waiting - DerefIndProd(group->subtract_input[i], deref) * multiplier);
}
for (uint i = 0; i < group->num_output; i++) {
int cargo_index = ind->GetCargoProducedIndex(group->cargo_output[i]);
if (cargo_index < 0) continue;
ind->produced_cargo_waiting[cargo_index] = ClampTo<uint16_t>(ind->produced_cargo_waiting[cargo_index] + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
auto it = ind->GetCargoProduced(group->cargo_output[i]);
if (it == std::end(ind->produced)) continue;
it->waiting = ClampTo<uint16_t>(it->waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier);
}
}

@ -1700,11 +1700,11 @@ bool AfterLoadGame()
uint j;
for (Industry * i : Industry::Iterate()) {
const IndustrySpec *indsp = GetIndustrySpec(i->type);
for (j = 0; j < lengthof(i->produced_cargo); j++) {
i->produced_cargo[j] = indsp->produced_cargo[j];
for (j = 0; j < lengthof(i->produced); j++) {
i->produced[j].cargo = indsp->produced_cargo[j];
}
for (j = 0; j < lengthof(i->accepts_cargo); j++) {
i->accepts_cargo[j] = indsp->accepts_cargo[j];
for (j = 0; j < lengthof(i->accepted); j++) {
i->accepted[j].cargo = indsp->accepts_cargo[j];
}
}
}
@ -3006,27 +3006,23 @@ bool AfterLoadGame()
if (IsSavegameVersionBefore(SLV_EXTEND_INDUSTRY_CARGO_SLOTS)) {
/* Make sure added industry cargo slots are cleared */
for (Industry *i : Industry::Iterate()) {
for (size_t ci = 2; ci < lengthof(i->produced_cargo); ci++) {
i->produced_cargo[ci] = CT_INVALID;
i->produced_cargo_waiting[ci] = 0;
i->production_rate[ci] = 0;
i->last_month_production[ci] = 0;
i->last_month_transported[ci] = 0;
i->last_month_pct_transported[ci] = 0;
i->this_month_production[ci] = 0;
i->this_month_transported[ci] = 0;
}
for (size_t ci = 3; ci < lengthof(i->accepts_cargo); ci++) {
i->accepts_cargo[ci] = CT_INVALID;
i->incoming_cargo_waiting[ci] = 0;
for (auto it = std::begin(i->produced) + 2; it != std::end(i->produced); ++it) {
it->cargo = CT_INVALID;
it->waiting = 0;
it->rate = 0;
it->history = {};
}
for (auto it = std::begin(i->accepted) + 3; it != std::end(i->accepted); ++it) {
it->cargo = CT_INVALID;
it->waiting = 0;
}
/* Make sure last_cargo_accepted_at is copied to elements for every valid input cargo.
* The loading routine should put the original singular value into the first array element. */
for (size_t ci = 0; ci < lengthof(i->accepts_cargo); ci++) {
if (IsValidCargoID(i->accepts_cargo[ci])) {
i->last_cargo_accepted_at[ci] = i->last_cargo_accepted_at[0];
for (auto &a : i->accepted) {
if (IsValidCargoID(a.cargo)) {
a.last_accepted = i->accepted[0].last_accepted;
} else {
i->last_cargo_accepted_at[ci] = 0;
a.last_accepted = 0;
}
}
}

@ -12,6 +12,23 @@
#include "../saveload.h"
const SaveLoadCompat _industry_accepts_sl_compat[] = {
SLC_VAR("cargo"),
SLC_VAR("waiting"),
SLC_VAR("last_accepted"),
};
const SaveLoadCompat _industry_produced_history_sl_compat[] = {
SLC_VAR("production"),
SLC_VAR("transported"),
};
const SaveLoadCompat _industry_produced_sl_compat[] = {
SLC_VAR("cargo"),
SLC_VAR("waiting"),
SLC_VAR("rate"),
};
/** Original field order for _industry_desc. */
const SaveLoadCompat _industry_sl_compat[] = {
SLC_VAR("location.tile"),
@ -29,7 +46,8 @@ const SaveLoadCompat _industry_sl_compat[] = {
SLC_VAR("prod_level"),
SLC_VAR("this_month_production"),
SLC_VAR("this_month_transported"),
SLC_VAR("last_month_pct_transported"),
SLC_NULL(2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLC_NULL(16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLC_VAR("last_month_production"),
SLC_VAR("last_month_transported"),
SLC_VAR("counter"),

@ -19,6 +19,119 @@
static OldPersistentStorage _old_ind_persistent_storage;
class SlIndustryAccepted : public DefaultSaveLoadHandler<SlIndustryAccepted, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::AcceptedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::AcceptedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::AcceptedCargo, last_accepted, SLE_INT32),
};
inline const static SaveLoadCompatTable compat_description = _industry_accepts_sl_compat;
void Save(Industry *i) const override
{
SlSetStructListLength(i->accepted.size());
for (auto &a : i->accepted) {
SlObject(&a, this->GetDescription());
}
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(i->accepted.size());
for (auto &a : i->accepted) {
if (--len > i->accepted.size()) break; // unsigned so wraps after hitting zero.
SlObject(&a, this->GetDescription());
}
}
/* Old array structure used for savegames before SLV_INDUSTRY_CARGO_REORGANISE. */
static CargoID old_cargo[INDUSTRY_NUM_INPUTS];
static uint16_t old_waiting[INDUSTRY_NUM_INPUTS];
static TimerGameCalendar::Date old_last_accepted[INDUSTRY_NUM_INPUTS];
};
/* static */ CargoID SlIndustryAccepted::old_cargo[INDUSTRY_NUM_INPUTS];
/* static */ uint16_t SlIndustryAccepted::old_waiting[INDUSTRY_NUM_INPUTS];
/* static */ TimerGameCalendar::Date SlIndustryAccepted::old_last_accepted[INDUSTRY_NUM_INPUTS];
class SlIndustryProducedHistory : public DefaultSaveLoadHandler<SlIndustryProducedHistory, Industry::ProducedCargo> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::ProducedHistory, production, SLE_UINT16),
SLE_VAR(Industry::ProducedHistory, transported, SLE_UINT16),
};
inline const static SaveLoadCompatTable compat_description = _industry_produced_history_sl_compat;
void Save(Industry::ProducedCargo *p) const override
{
SlSetStructListLength(p->history.size());
for (auto &h : p->history) {
SlObject(&h, this->GetDescription());
}
}
void Load(Industry::ProducedCargo *p) const override
{
size_t len = SlGetStructListLength(p->history.size());
for (auto &h : p->history) {
if (--len > p->history.size()) break; // unsigned so wraps after hitting zero.
SlObject(&h, this->GetDescription());
}
}
};
class SlIndustryProduced : public DefaultSaveLoadHandler<SlIndustryProduced, Industry> {
public:
inline static const SaveLoad description[] = {
SLE_VAR(Industry::ProducedCargo, cargo, SLE_UINT8),
SLE_VAR(Industry::ProducedCargo, waiting, SLE_UINT16),
SLE_VAR(Industry::ProducedCargo, rate, SLE_UINT8),
SLEG_STRUCTLIST("history", SlIndustryProducedHistory),
};
inline const static SaveLoadCompatTable compat_description = _industry_produced_sl_compat;
void Save(Industry *i) const override
{
SlSetStructListLength(i->produced.size());
for (auto &p : i->produced) {
SlObject(&p, this->GetDescription());
}
}
void Load(Industry *i) const override
{
size_t len = SlGetStructListLength(i->produced.size());
for (auto &p : i->produced) {
if (--len > i->produced.size()) break; // unsigned so wraps after hitting zero.
SlObject(&p, this->GetDescription());
}
}
/* Old array structure used for savegames before SLV_INDUSTRY_CARGO_REORGANISE. */
static CargoID old_cargo[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_waiting[INDUSTRY_NUM_OUTPUTS];
static uint8_t old_rate[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_this_month_production[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_this_month_transported[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_last_month_production[INDUSTRY_NUM_OUTPUTS];
static uint16_t old_last_month_transported[INDUSTRY_NUM_OUTPUTS];
};
/* static */ CargoID SlIndustryProduced::old_cargo[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_waiting[INDUSTRY_NUM_OUTPUTS];
/* static */ uint8_t SlIndustryProduced::old_rate[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_this_month_production[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_this_month_transported[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_last_month_production[INDUSTRY_NUM_OUTPUTS];
/* static */ uint16_t SlIndustryProduced::old_last_month_transported[INDUSTRY_NUM_OUTPUTS];
static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, location.tile, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
SLE_CONDVAR(Industry, location.tile, SLE_UINT32, SLV_6, SL_MAX_VERSION),
@ -26,27 +139,25 @@ static const SaveLoad _industry_desc[] = {
SLE_VAR(Industry, location.h, SLE_FILE_U8 | SLE_VAR_U16),
SLE_REF(Industry, town, REF_TOWN),
SLE_CONDREF(Industry, neutral_station, REF_STATION, SLV_SERVE_NEUTRAL_INDUSTRIES, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, incoming_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, produced_cargo_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, production_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, accepts_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLEG_CONDARR("produced_cargo", SlIndustryProduced::old_cargo, SLE_UINT8, 2, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("produced_cargo", SlIndustryProduced::old_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("incoming_cargo_waiting", SlIndustryAccepted::old_waiting, SLE_UINT16, 3, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("incoming_cargo_waiting", SlIndustryAccepted::old_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("produced_cargo_waiting", SlIndustryProduced::old_waiting, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("produced_cargo_waiting", SlIndustryProduced::old_waiting, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("production_rate", SlIndustryProduced::old_rate, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("production_rate", SlIndustryProduced::old_rate, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("accepts_cargo", SlIndustryAccepted::old_cargo, SLE_UINT8, 3, SLV_78, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("accepts_cargo", SlIndustryAccepted::old_cargo, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, prod_level, SLE_UINT8),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_pct_transported, SLE_UINT8, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLE_CONDARR(Industry, last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SL_MAX_VERSION),
SLEG_CONDARR("this_month_production", SlIndustryProduced::old_this_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("this_month_production", SlIndustryProduced::old_this_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("this_month_transported", SlIndustryProduced::old_this_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("this_month_transported", SlIndustryProduced::old_this_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("last_month_production", SlIndustryProduced::old_last_month_production, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_month_production", SlIndustryProduced::old_last_month_production, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLEG_CONDARR("last_month_transported", SlIndustryProduced::old_last_month_transported, SLE_UINT16, 2, SL_MIN_VERSION, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_month_transported", SlIndustryProduced::old_last_month_transported, SLE_UINT16, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
SLE_VAR(Industry, counter, SLE_UINT16),
@ -61,8 +172,8 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, founder, SLE_UINT8, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_date, SLE_INT32, SLV_70, SL_MAX_VERSION),
SLE_CONDVAR(Industry, construction_type, SLE_UINT8, SLV_70, SL_MAX_VERSION),
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),
SLEG_CONDVAR("last_cargo_accepted_at[0]", SlIndustryAccepted::old_last_accepted[0], SLE_INT32, SLV_70, SLV_EXTEND_INDUSTRY_CARGO_SLOTS),
SLEG_CONDARR("last_cargo_accepted_at", SlIndustryAccepted::old_last_accepted, SLE_INT32, 16, SLV_EXTEND_INDUSTRY_CARGO_SLOTS, SLV_INDUSTRY_CARGO_REORGANISE),
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),
@ -72,6 +183,9 @@ static const SaveLoad _industry_desc[] = {
SLE_CONDVAR(Industry, random, SLE_UINT16, SLV_82, SL_MAX_VERSION),
SLE_CONDSSTR(Industry, text, SLE_STR | SLF_ALLOW_CONTROL, SLV_INDUSTRY_TEXT, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("accepted", SlIndustryAccepted, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
SLEG_CONDSTRUCTLIST("produced", SlIndustryProduced, SLV_INDUSTRY_CARGO_REORGANISE, SL_MAX_VERSION),
};
struct INDYChunkHandler : ChunkHandler {
@ -88,6 +202,27 @@ struct INDYChunkHandler : ChunkHandler {
}
}
void LoadMoveAcceptsProduced(Industry *i) const
{
for (uint j = 0; j != INDUSTRY_NUM_INPUTS; ++j) {
auto &a = i->accepted[j];
a.cargo = SlIndustryAccepted::old_cargo[j];
a.waiting = SlIndustryAccepted::old_waiting[j];
a.last_accepted = SlIndustryAccepted::old_last_accepted[j];
}
for (uint j = 0; j != INDUSTRY_NUM_OUTPUTS; ++j) {
auto &p = i->produced[j];
p.cargo = SlIndustryProduced::old_cargo[j];
p.waiting = SlIndustryProduced::old_waiting[j];
p.rate = SlIndustryProduced::old_rate[j];
p.history[THIS_MONTH].production = SlIndustryProduced::old_this_month_production[j];
p.history[THIS_MONTH].transported = SlIndustryProduced::old_this_month_transported[j];
p.history[LAST_MONTH].production = SlIndustryProduced::old_last_month_production[j];
p.history[LAST_MONTH].transported = SlIndustryProduced::old_last_month_transported[j];
}
}
void Load() const override
{
const std::vector<SaveLoad> slt = SlCompatTableHeader(_industry_desc, _industry_sl_compat);
@ -107,6 +242,7 @@ struct INDYChunkHandler : ChunkHandler {
i->psa = new PersistentStorage(0, 0, 0);
memcpy(i->psa->storage, _old_ind_persistent_storage.storage, sizeof(_old_ind_persistent_storage.storage));
}
if (IsSavegameVersionBefore(SLV_INDUSTRY_CARGO_REORGANISE)) LoadMoveAcceptsProduced(i);
Industry::IncIndustryTypeCount(i->type);
}
}

@ -795,30 +795,29 @@ static const OldChunks industry_chunk[] = {
OCL_SVAR( OC_FILE_U8 | OC_VAR_U16, Industry, location.h ),
OCL_NULL( 2 ), ///< used to be industry's produced_cargo
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[0] ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced_cargo_waiting[1] ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[0] ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced_cargo_waiting[1] ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[0].waiting ),
OCL_SVAR( OC_TTD | OC_UINT16, Industry, produced[1].waiting ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[0].waiting ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, produced[1].waiting ),
OCL_SVAR( OC_UINT8, Industry, production_rate[0] ),
OCL_SVAR( OC_UINT8, Industry, production_rate[1] ),
OCL_SVAR( OC_UINT8, Industry, produced[0].rate ),
OCL_SVAR( OC_UINT8, Industry, produced[1].rate ),
OCL_NULL( 3 ), ///< used to be industry's accepts_cargo
OCL_SVAR( OC_UINT8, Industry, prod_level ),
OCL_SVAR( OC_UINT16, Industry, this_month_production[0] ),
OCL_SVAR( OC_UINT16, Industry, this_month_production[1] ),
OCL_SVAR( OC_UINT16, Industry, this_month_transported[0] ),
OCL_SVAR( OC_UINT16, Industry, this_month_transported[1] ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[THIS_MONTH].transported ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[THIS_MONTH].transported ),
OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[0] ),
OCL_SVAR( OC_UINT8, Industry, last_month_pct_transported[1] ),
OCL_NULL( 2 ), ///< last_month_pct_transported, now computed on the fly
OCL_SVAR( OC_UINT16, Industry, last_month_production[0] ),
OCL_SVAR( OC_UINT16, Industry, last_month_production[1] ),
OCL_SVAR( OC_UINT16, Industry, last_month_transported[0] ),
OCL_SVAR( OC_UINT16, Industry, last_month_transported[1] ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].production ),
OCL_SVAR( OC_UINT16, Industry, produced[0].history[LAST_MONTH].transported ),
OCL_SVAR( OC_UINT16, Industry, produced[1].history[LAST_MONTH].transported ),
OCL_SVAR( OC_UINT8, Industry, type ),
OCL_SVAR( OC_TTO | OC_FILE_U8 | OC_VAR_U16, Industry, counter ),

@ -356,6 +356,8 @@ enum SaveLoadVersion : uint16 {
SLV_SAVEGAME_ID, ///< 313 PR#10719 Add an unique ID to every savegame (used to deduplicate surveys).
SLV_STRING_GAMELOG, ///< 314 PR#10801 Use std::string in gamelog.
SLV_INDUSTRY_CARGO_REORGANISE, ///< 315 PR#10853 Industry accepts/produced data reorganised.
SL_MAX_VERSION, ///< Highest possible saveload version
};

@ -29,10 +29,9 @@ ScriptCargoList_IndustryAccepting::ScriptCargoList_IndustryAccepting(IndustryID
if (!ScriptIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->accepts_cargo); i++) {
CargoID cargo_id = ind->accepts_cargo[i];
if (::IsValidCargoID(cargo_id)) {
this->AddItem(cargo_id);
for (const auto &a : ind->accepted) {
if (::IsValidCargoID(a.cargo)) {
this->AddItem(a.cargo);
}
}
}
@ -42,10 +41,9 @@ ScriptCargoList_IndustryProducing::ScriptCargoList_IndustryProducing(IndustryID
if (!ScriptIndustry::IsValidIndustry(industry_id)) return;
Industry *ind = ::Industry::Get(industry_id);
for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
CargoID cargo_id = ind->produced_cargo[i];
if (::IsValidCargoID(cargo_id)) {
this->AddItem(cargo_id);
for (const auto &p : ind->produced) {
if (::IsValidCargoID(p.cargo)) {
this->AddItem(p.cargo);
}
}
}

@ -80,10 +80,10 @@
Industry *i = ::Industry::Get(industry_id);
int j = i->GetCargoAcceptedIndex(cargo_id);
if (j < 0) return -1;
auto it = i->GetCargoAccepted(cargo_id);
if (it == std::end(i->accepted)) return -1;
return i->incoming_cargo_waiting[j];
return it->waiting;
}
/* static */ SQInteger ScriptIndustry::GetLastMonthProduction(IndustryID industry_id, CargoID cargo_id)
@ -91,12 +91,12 @@
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return i->last_month_production[j];
return it->history[LAST_MONTH].production;
}
/* static */ SQInteger ScriptIndustry::GetLastMonthTransported(IndustryID industry_id, CargoID cargo_id)
@ -104,12 +104,12 @@
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return i->last_month_transported[j];
return it->history[LAST_MONTH].transported;
}
/* static */ SQInteger ScriptIndustry::GetLastMonthTransportedPercentage(IndustryID industry_id, CargoID cargo_id)
@ -117,12 +117,12 @@
if (!IsValidIndustry(industry_id)) return -1;
if (!ScriptCargo::IsValidCargo(cargo_id)) return -1;
const Industry *i = ::Industry::Get(industry_id);
Industry *i = ::Industry::Get(industry_id);
int j = i->GetCargoProducedIndex(cargo_id);
if (j < 0) return -1;
auto it = i->GetCargoProduced(cargo_id);
if (it == std::end(i->produced)) return -1;
return ::ToPercent8(i->last_month_pct_transported[j]);
return ::ToPercent8(it->history[LAST_MONTH].PctTransported());
}
/* static */ TileIndex ScriptIndustry::GetLocation(IndustryID industry_id)
@ -225,11 +225,12 @@
if (i == nullptr) return ScriptDate::DATE_INVALID;
if (!::IsValidCargoID(cargo_type)) {
return (ScriptDate::Date)std::accumulate(std::begin(i->last_cargo_accepted_at), std::end(i->last_cargo_accepted_at), 0, [](TimerGameCalendar::Date a, TimerGameCalendar::Date b) { return std::max(a, b); });
auto it = std::max_element(std::begin(i->accepted), std::end(i->accepted), [](const auto &a, const auto &b) { return a.last_accepted < b.last_accepted; });
return (ScriptDate::Date)it->last_accepted;
} else {
int index = i->GetCargoAcceptedIndex(cargo_type);
if (index < 0) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)i->last_cargo_accepted_at[index];
auto it = i->GetCargoAccepted(cargo_type);
if (it == std::end(i->accepted)) return ScriptDate::DATE_INVALID;
return (ScriptDate::Date)it->last_accepted;
}
}

@ -95,13 +95,7 @@ ScriptTileList_IndustryAccepting::ScriptTileList_IndustryAccepting(IndustryID in
/* Only add the tile if it accepts the cargo (sometimes just 1 tile of an
* industry triggers the acceptance). */
CargoArray acceptance = ::GetAcceptanceAroundTiles(cur_tile, 1, 1, radius);
{
bool cargo_accepts = false;
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
if (::IsValidCargoID(i->accepts_cargo[j]) && acceptance[i->accepts_cargo[j]] != 0) cargo_accepts = true;
}
if (!cargo_accepts) continue;
}
if (std::none_of(std::begin(i->accepted), std::end(i->accepted), [&acceptance](const auto &a) { return ::IsValidCargoID(a.cargo) && acceptance[a.cargo] != 0; })) continue;
this->AddTile(cur_tile);
}

@ -170,11 +170,11 @@ static bool CMSAMine(TileIndex tile)
/* No extractive industry */
if ((GetIndustrySpec(ind->type)->life_type & INDUSTRYLIFE_EXTRACTIVE) == 0) return false;
for (uint i = 0; i < lengthof(ind->produced_cargo); i++) {
for (const auto &p : ind->produced) {
/* The industry extracts something non-liquid, i.e. no oil or plastic, so it is a mine.
* Also the production of passengers and mail is ignored. */
if (IsValidCargoID(ind->produced_cargo[i]) &&
(CargoSpec::Get(ind->produced_cargo[i])->classes & (CC_LIQUID | CC_PASSENGERS | CC_MAIL)) == 0) {
if (IsValidCargoID(p.cargo) &&
(CargoSpec::Get(p.cargo)->classes & (CC_LIQUID | CC_PASSENGERS | CC_MAIL)) == 0) {
return true;
}
}
@ -532,9 +532,8 @@ CargoArray GetProductionAroundTiles(TileIndex north_tile, int w, int h, int rad)
/* Skip industry with neutral station */
if (i->neutral_station != nullptr && !_settings_game.station.serve_neutral_industries) continue;
for (uint j = 0; j < lengthof(i->produced_cargo); j++) {
CargoID cargo = i->produced_cargo[j];
if (IsValidCargoID(cargo)) produced[cargo]++;
for (const auto &p : i->produced) {
if (IsValidCargoID(p.cargo)) produced[p.cargo]++;
}
}

@ -382,21 +382,20 @@ bool FindSubsidyIndustryCargoRoute()
CargoID cid;
/* Randomize cargo type */
int num_cargos = 0;
uint cargo_index;
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) {
if (IsValidCargoID(src_ind->produced_cargo[cargo_index])) num_cargos++;
}
int num_cargos = std::count_if(std::begin(src_ind->produced), std::end(src_ind->produced), [](const auto &p) { return IsValidCargoID(p.cargo); });
if (num_cargos == 0) return false; // industry produces nothing
int cargo_num = RandomRange(num_cargos) + 1;
for (cargo_index = 0; cargo_index < lengthof(src_ind->produced_cargo); cargo_index++) {
if (IsValidCargoID(src_ind->produced_cargo[cargo_index])) cargo_num--;
auto it = std::begin(src_ind->produced);
for (/* nothing */; it != std::end(src_ind->produced); ++it) {
if (IsValidCargoID(it->cargo)) cargo_num--;
if (cargo_num == 0) break;
}
assert(cargo_num == 0); // indicates loop didn't break as intended
cid = src_ind->produced_cargo[cargo_index];
trans = src_ind->last_month_pct_transported[cargo_index];
total = src_ind->last_month_production[cargo_index];
assert(it != std::end(src_ind->produced)); // indicates loop didn't end as intended
cid = it->cargo;
trans = it->history[LAST_MONTH].PctTransported();
total = it->history[LAST_MONTH].production;
/* Quit if no production in this industry
* or if the pct transported is already large enough

@ -275,38 +275,38 @@ static const NIFeature _nif_industrytile = {
/*** NewGRF industries ***/
static const NIProperty _nip_industries[] = {
NIP(0x25, Industry, produced_cargo[ 0], NIT_CARGO, "produced cargo 0"),
NIP(0x25, Industry, produced_cargo[ 1], NIT_CARGO, "produced cargo 1"),
NIP(0x25, Industry, produced_cargo[ 2], NIT_CARGO, "produced cargo 2"),
NIP(0x25, Industry, produced_cargo[ 3], NIT_CARGO, "produced cargo 3"),
NIP(0x25, Industry, produced_cargo[ 4], NIT_CARGO, "produced cargo 4"),
NIP(0x25, Industry, produced_cargo[ 5], NIT_CARGO, "produced cargo 5"),
NIP(0x25, Industry, produced_cargo[ 6], NIT_CARGO, "produced cargo 6"),
NIP(0x25, Industry, produced_cargo[ 7], NIT_CARGO, "produced cargo 7"),
NIP(0x25, Industry, produced_cargo[ 8], NIT_CARGO, "produced cargo 8"),
NIP(0x25, Industry, produced_cargo[ 9], NIT_CARGO, "produced cargo 9"),
NIP(0x25, Industry, produced_cargo[10], NIT_CARGO, "produced cargo 10"),
NIP(0x25, Industry, produced_cargo[11], NIT_CARGO, "produced cargo 11"),
NIP(0x25, Industry, produced_cargo[12], NIT_CARGO, "produced cargo 12"),
NIP(0x25, Industry, produced_cargo[13], NIT_CARGO, "produced cargo 13"),
NIP(0x25, Industry, produced_cargo[14], NIT_CARGO, "produced cargo 14"),
NIP(0x25, Industry, produced_cargo[15], NIT_CARGO, "produced cargo 15"),
NIP(0x26, Industry, accepts_cargo[ 0], NIT_CARGO, "accepted cargo 0"),
NIP(0x26, Industry, accepts_cargo[ 1], NIT_CARGO, "accepted cargo 1"),
NIP(0x26, Industry, accepts_cargo[ 2], NIT_CARGO, "accepted cargo 2"),
NIP(0x26, Industry, accepts_cargo[ 3], NIT_CARGO, "accepted cargo 3"),
NIP(0x26, Industry, accepts_cargo[ 4], NIT_CARGO, "accepted cargo 4"),
NIP(0x26, Industry, accepts_cargo[ 5], NIT_CARGO, "accepted cargo 5"),
NIP(0x26, Industry, accepts_cargo[ 6], NIT_CARGO, "accepted cargo 6"),
NIP(0x26, Industry, accepts_cargo[ 7], NIT_CARGO, "accepted cargo 7"),
NIP(0x26, Industry, accepts_cargo[ 8], NIT_CARGO, "accepted cargo 8"),
NIP(0x26, Industry, accepts_cargo[ 9], NIT_CARGO, "accepted cargo 9"),
NIP(0x26, Industry, accepts_cargo[10], NIT_CARGO, "accepted cargo 10"),
NIP(0x26, Industry, accepts_cargo[11], NIT_CARGO, "accepted cargo 11"),
NIP(0x26, Industry, accepts_cargo[12], NIT_CARGO, "accepted cargo 12"),
NIP(0x26, Industry, accepts_cargo[13], NIT_CARGO, "accepted cargo 13"),
NIP(0x26, Industry, accepts_cargo[14], NIT_CARGO, "accepted cargo 14"),
NIP(0x26, Industry, accepts_cargo[15], NIT_CARGO, "accepted cargo 15"),
NIP(0x25, Industry, produced[ 0].cargo, NIT_CARGO, "produced cargo 0"),
NIP(0x25, Industry, produced[ 1].cargo, NIT_CARGO, "produced cargo 1"),
NIP(0x25, Industry, produced[ 2].cargo, NIT_CARGO, "produced cargo 2"),
NIP(0x25, Industry, produced[ 3].cargo, NIT_CARGO, "produced cargo 3"),
NIP(0x25, Industry, produced[ 4].cargo, NIT_CARGO, "produced cargo 4"),
NIP(0x25, Industry, produced[ 5].cargo, NIT_CARGO, "produced cargo 5"),
NIP(0x25, Industry, produced[ 6].cargo, NIT_CARGO, "produced cargo 6"),
NIP(0x25, Industry, produced[ 7].cargo, NIT_CARGO, "produced cargo 7"),
NIP(0x25, Industry, produced[ 8].cargo, NIT_CARGO, "produced cargo 8"),
NIP(0x25, Industry, produced[ 9].cargo, NIT_CARGO, "produced cargo 9"),
NIP(0x25, Industry, produced[10].cargo, NIT_CARGO, "produced cargo 10"),
NIP(0x25, Industry, produced[11].cargo, NIT_CARGO, "produced cargo 11"),
NIP(0x25, Industry, produced[12].cargo, NIT_CARGO, "produced cargo 12"),
NIP(0x25, Industry, produced[13].cargo, NIT_CARGO, "produced cargo 13"),
NIP(0x25, Industry, produced[14].cargo, NIT_CARGO, "produced cargo 14"),
NIP(0x25, Industry, produced[15].cargo, NIT_CARGO, "produced cargo 15"),
NIP(0x26, Industry, accepted[ 0].cargo, NIT_CARGO, "accepted cargo 0"),
NIP(0x26, Industry, accepted[ 1].cargo, NIT_CARGO, "accepted cargo 1"),
NIP(0x26, Industry, accepted[ 2].cargo, NIT_CARGO, "accepted cargo 2"),
NIP(0x26, Industry, accepted[ 3].cargo, NIT_CARGO, "accepted cargo 3"),
NIP(0x26, Industry, accepted[ 4].cargo, NIT_CARGO, "accepted cargo 4"),
NIP(0x26, Industry, accepted[ 5].cargo, NIT_CARGO, "accepted cargo 5"),
NIP(0x26, Industry, accepted[ 6].cargo, NIT_CARGO, "accepted cargo 6"),
NIP(0x26, Industry, accepted[ 7].cargo, NIT_CARGO, "accepted cargo 7"),
NIP(0x26, Industry, accepted[ 8].cargo, NIT_CARGO, "accepted cargo 8"),
NIP(0x26, Industry, accepted[ 9].cargo, NIT_CARGO, "accepted cargo 9"),
NIP(0x26, Industry, accepted[10].cargo, NIT_CARGO, "accepted cargo 10"),
NIP(0x26, Industry, accepted[11].cargo, NIT_CARGO, "accepted cargo 11"),
NIP(0x26, Industry, accepted[12].cargo, NIT_CARGO, "accepted cargo 12"),
NIP(0x26, Industry, accepted[13].cargo, NIT_CARGO, "accepted cargo 13"),
NIP(0x26, Industry, accepted[14].cargo, NIT_CARGO, "accepted cargo 14"),
NIP(0x26, Industry, accepted[15].cargo, NIT_CARGO, "accepted cargo 15"),
NIP_END()
};

Loading…
Cancel
Save