# HG changeset patch # User PeterN # Date 2023-05-25 20:25:46 # Node ID 22e72ba90974dbe3acd10b6fc3b5fd13b67dac09 # Parent c8c76aa89930091be2edcb4111d84f442d94a988 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. diff --git a/src/economy.cpp b/src/economy.cpp --- a/src/economy.cpp +++ b/src/economy.cpp @@ -1017,9 +1017,9 @@ static uint DeliverGoodsToIndustry(const 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 /* 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(In 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(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(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; } } diff --git a/src/industry.h b/src/industry.h --- a/src/industry.h +++ b/src/industry.h @@ -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(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 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; + using AcceptedCargoArray = std::array; + 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 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 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 diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -420,13 +420,13 @@ static void AddAcceptedCargo_Industry(Ti 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(TileI const IndustrySpec *indspec = GetIndustrySpec(i->type); bool moved_cargo = false; - for (uint j = 0; j < lengthof(i->produced_cargo_waiting); j++) { - uint cw = ClampTo(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(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; - - uint am = MoveGoodsToStation(i->produced_cargo[j], cw, SourceType::Industry, i->index, &i->stations_near, i->exclusive_consumer); - i->this_month_transported[j] += am; + p.history[THIS_MONTH].production += cw; + + 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 TileIndex tile = i->location.tile; if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search. - i->produced_cargo_waiting[0] = ClampTo(i->produced_cargo_waiting[0] + 45); // Found a tree, add according value to waiting cargo. + i->produced[0].waiting = ClampTo(i->produced[0].waiting + 45); // Found a tree, add according value to waiting cargo. } } @@ -1146,14 +1141,11 @@ static void ProduceIndustryGoods(Industr 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(Industr 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(i->produced_cargo_waiting[j] + i->production_rate[j]); + for (auto &p : i->produced) { + p.waiting = ClampTo(p.waiting + p.rate); } if ((indbehav & INDUSTRYBEH_PLANT_FIELDS) != 0) { @@ -1762,22 +1754,21 @@ static void DoCreateNewIndustry(Industry 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)); - - 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->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]; + } + + 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((RandomRange(256) + 128) * i->production_rate[ci] >> 8); + for (auto &p : i->produced) { + p.rate = ClampTo((RandomRange(256) + 128) * p.rate >> 8); } } @@ -1824,14 +1815,14 @@ static void DoCreateNewIndustry(Industry 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 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(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 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(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 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(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; - - i->last_month_transported[j] = i->this_month_transported[j]; - i->this_month_transported[j] = 0; + for (auto &p : i->produced) { + if (IsValidCargoID(p.cargo)) { + if (p.history[THIS_MONTH].production != 0) i->last_prod_year = TimerGameCalendar::year; + + /* 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::RecomputeProductionMultip 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(CeilDiv(indspec->production_rate[i] * this->prod_level, PRODLEVEL_DEFAULT)); + for (auto &p : this->produced) { + p.rate = ClampTo(CeilDiv(indspec->production_rate[&p - this->produced.data()] * this->prod_level, PRODLEVEL_DEFAULT)); } } @@ -2773,7 +2758,7 @@ static void ChangeIndustryProduction(Ind 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(Ind } } 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; - - new_prod = old_prod = i->production_rate[j]; + int mult = (p.history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) ? 1 : -1; + + 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(Ind 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(Ind /* 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(Ind } 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); } } } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -189,6 +189,33 @@ static inline void GetAllCargoSuffixes(C } } +/** + * 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 _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(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(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(Ind 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 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(this->industries.SortType())) { diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -214,9 +214,9 @@ static uint32 GetCountAndDistanceOfClose 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(this->industry->incoming_cargo_waiting[variable - 0x40] / this->industry->prod_level); + return ClampTo(this->industry->accepted[variable - 0x40].waiting / this->industry->prod_level); } else { - return ClampTo(this->industry->incoming_cargo_waiting[variable - 0x40]); + return ClampTo(this->industry->accepted[variable - 0x40].waiting); } } else { return 0; @@ -317,16 +317,16 @@ static uint32 GetCountAndDistanceOfClose 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 GetCountAndDistanceOfClose 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 GetCountAndDistanceOfClose 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 GetCountAndDistanceOfClose case 0xB0: return ClampTo(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((*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(it->last_accepted - DAYS_TILL_ORIGINAL_BASE_YEAR); // Date last cargo accepted since 1920 (in days) } } @@ -643,22 +643,22 @@ void IndustryProductionCallback(Industry 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(ind->incoming_cargo_waiting[i] - DerefIndProd(group->subtract_input[i], deref) * multiplier); + ind->accepted[i].waiting = ClampTo(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(ind->produced_cargo_waiting[i] + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier); + ind->produced[i].waiting = ClampTo(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(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(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(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(it->waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier); } } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -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 (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 (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->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; } } } diff --git a/src/saveload/compat/industry_sl_compat.h b/src/saveload/compat/industry_sl_compat.h --- a/src/saveload/compat/industry_sl_compat.h +++ b/src/saveload/compat/industry_sl_compat.h @@ -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"), diff --git a/src/saveload/industry_sl.cpp b/src/saveload/industry_sl.cpp --- a/src/saveload/industry_sl.cpp +++ b/src/saveload/industry_sl.cpp @@ -19,6 +19,119 @@ static OldPersistentStorage _old_ind_persistent_storage; +class SlIndustryAccepted : public DefaultSaveLoadHandler { +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 { +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 { +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 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); } } diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -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 ), diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -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 }; diff --git a/src/script/api/script_cargolist.cpp b/src/script/api/script_cargolist.cpp --- a/src/script/api/script_cargolist.cpp +++ b/src/script/api/script_cargolist.cpp @@ -29,10 +29,9 @@ ScriptCargoList_IndustryAccepting::Scrip 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::Scrip 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); } } } diff --git a/src/script/api/script_industry.cpp b/src/script/api/script_industry.cpp --- a/src/script/api/script_industry.cpp +++ b/src/script/api/script_industry.cpp @@ -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; } } diff --git a/src/script/api/script_tilelist.cpp b/src/script/api/script_tilelist.cpp --- a/src/script/api/script_tilelist.cpp +++ b/src/script/api/script_tilelist.cpp @@ -95,13 +95,7 @@ ScriptTileList_IndustryAccepting::Script /* 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); } diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -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(Tile /* 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]++; } } diff --git a/src/subsidy.cpp b/src/subsidy.cpp --- a/src/subsidy.cpp +++ b/src/subsidy.cpp @@ -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 diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -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() };