diff --git a/src/industry.h b/src/industry.h index 4a8f41bbcf..2747001aea 100644 --- a/src/industry.h +++ b/src/industry.h @@ -139,6 +139,28 @@ struct Industry : IndustryPool::PoolItem<&_industry_pool> { return IsTileType(tile, MP_INDUSTRY) && GetIndustryIndex(tile) == this->index; } + /** + * Safely get a produced cargo slot, or an empty data if the slot does not exist. + * @param slot produced cargo slot to retrieve. + * @return the real slot, or an empty slot. + */ + inline const ProducedCargo &GetProduced(size_t slot) const + { + static const ProducedCargo empty{INVALID_CARGO, 0, 0, {}}; + return slot < this->produced.size() ? this->produced[slot] : empty; + } + + /** + * Safely get an accepted cargo slot, or an empty data if the slot does not exist. + * @param slot accepted cargo slot to retrieve. + * @return the real slot, or an empty slot. + */ + inline const AcceptedCargo &GetAccepted(size_t slot) const + { + static const AcceptedCargo empty{INVALID_CARGO, 0, {}}; + return slot < this->accepted.size() ? this->accepted[slot] : empty; + } + /** * Get produced cargo slot for a specific cargo type. * @param cargo CargoID to find. diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index 46e3d79b08..4f1f448ca1 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1125,8 +1125,9 @@ static bool SearchLumberMillTrees(TileIndex tile, void *) */ static void ChopLumberMillTrees(Industry *i) { - /* Skip production if cargo slot is invalid. */ - if (!IsValidCargoID(i->produced[0].cargo)) return; + /* Don't process lumber mill if cargo is not set up correctly. */ + auto itp = std::begin(i->produced); + if (itp == std::end(i->produced) || !IsValidCargoID(itp->cargo)) return; /* We only want to cut trees if all tiles are completed. */ for (TileIndex tile_cur : i->location) { @@ -1137,7 +1138,7 @@ static void ChopLumberMillTrees(Industry *i) TileIndex tile = i->location.tile; if (CircularTileSearch(&tile, 40, SearchLumberMillTrees, nullptr)) { // 40x40 tiles to search. - i->produced[0].waiting = ClampTo(i->produced[0].waiting + ScaleByCargoScale(45, false)); // Found a tree, add according value to waiting cargo. + itp->waiting = ClampTo(itp->waiting + ScaleByCargoScale(45, false)); // Found a tree, add according value to waiting cargo. } } @@ -2847,7 +2848,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->produced[0].history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) { + if (!only_decrease && (i->GetProduced(0).history[LAST_MONTH].PctTransported() > PERCENT_TRANSPORTED_60) != Chance16(1, 3)) { mul = 1; // Increase production } else { div = 1; // Decrease production diff --git a/src/newgrf_industries.cpp b/src/newgrf_industries.cpp index ed68d35a01..7f574fb9b9 100644 --- a/src/newgrf_industries.cpp +++ b/src/newgrf_industries.cpp @@ -214,9 +214,9 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_ 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->accepted[variable - 0x40].waiting / this->industry->prod_level); + return ClampTo(this->industry->GetAccepted(variable - 0x40).waiting / this->industry->prod_level); } else { - return ClampTo(this->industry->accepted[variable - 0x40].waiting); + return ClampTo(this->industry->GetAccepted(variable - 0x40).waiting); } } else { return 0; @@ -358,40 +358,40 @@ static uint32_t GetCountAndDistanceOfClosestInstance(uint8_t param_setID, uint8_ case 0x87: return this->industry->location.h;// xy dimensions case 0x88: - 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 0x89: return this->industry->GetProduced(variable - 0x88).cargo; + case 0x8A: return this->industry->GetProduced(0).waiting; + case 0x8B: return GB(this->industry->GetProduced(0).waiting, 8, 8); + case 0x8C: return this->industry->GetProduced(1).waiting; + case 0x8D: return GB(this->industry->GetProduced(1).waiting, 8, 8); case 0x8E: - case 0x8F: return this->industry->produced[variable - 0x8E].rate; + case 0x8F: return this->industry->GetProduced(variable - 0x8E).rate; case 0x90: case 0x91: - case 0x92: return this->industry->accepted[variable - 0x90].cargo; + case 0x92: return this->industry->GetAccepted(variable - 0x90).cargo; case 0x93: return this->industry->prod_level; /* amount of cargo produced so far THIS month. */ - 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); + case 0x94: return this->industry->GetProduced(0).history[THIS_MONTH].production; + case 0x95: return GB(this->industry->GetProduced(0).history[THIS_MONTH].production, 8, 8); + case 0x96: return this->industry->GetProduced(1).history[THIS_MONTH].production; + case 0x97: return GB(this->industry->GetProduced(1).history[THIS_MONTH].production, 8, 8); /* amount of cargo transported so far THIS month. */ - 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); + case 0x98: return this->industry->GetProduced(0).history[THIS_MONTH].transported; + case 0x99: return GB(this->industry->GetProduced(0).history[THIS_MONTH].transported, 8, 8); + case 0x9A: return this->industry->GetProduced(1).history[THIS_MONTH].transported; + case 0x9B: return GB(this->industry->GetProduced(1).history[THIS_MONTH].transported, 8, 8); /* fraction of cargo transported LAST month. */ case 0x9C: - case 0x9D: return this->industry->produced[variable - 0x9C].history[LAST_MONTH].PctTransported(); + case 0x9D: return this->industry->GetProduced(variable - 0x9C).history[LAST_MONTH].PctTransported(); /* amount of cargo produced LAST month. */ - 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); + case 0x9E: return this->industry->GetProduced(0).history[LAST_MONTH].production; + case 0x9F: return GB(this->industry->GetProduced(0).history[LAST_MONTH].production, 8, 8); + case 0xA0: return this->industry->GetProduced(1).history[LAST_MONTH].production; + case 0xA1: return GB(this->industry->GetProduced(1).history[LAST_MONTH].production, 8, 8); /* amount of cargo transported last month. */ - 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 0xA2: return this->industry->GetProduced(0).history[LAST_MONTH].transported; + case 0xA3: return GB(this->industry->GetProduced(0).history[LAST_MONTH].transported, 8, 8); + case 0xA4: return this->industry->GetProduced(1).history[LAST_MONTH].transported; + case 0xA5: return GB(this->industry->GetProduced(1).history[LAST_MONTH].transported, 8, 8); case 0xA6: return indspec->grf_prop.local_id; case 0xA7: return this->industry->founder; @@ -642,11 +642,11 @@ 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++) { + for (uint i = 0; i < group->num_input && i < ind->accepted.size(); i++) { if (!IsValidCargoID(ind->accepted[i].cargo)) continue; 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++) { + for (uint i = 0; i < group->num_output && i < ind->produced.size(); i++) { if (!IsValidCargoID(ind->produced[i].cargo)) continue; ind->produced[i].waiting = ClampTo(ind->produced[i].waiting + std::max(DerefIndProd(group->add_output[i], deref), 0) * multiplier); } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index f8b9202e6e..34a9f36d27 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -3058,7 +3058,7 @@ bool AfterLoadGame() * The loading routine should put the original singular value into the first array element. */ for (auto &a : i->accepted) { if (IsValidCargoID(a.cargo)) { - a.last_accepted = i->accepted[0].last_accepted; + a.last_accepted = i->GetAccepted(0).last_accepted; } else { a.last_accepted = 0; } diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h index f11a1110a7..127a948635 100644 --- a/src/table/newgrf_debug_data.h +++ b/src/table/newgrf_debug_data.h @@ -274,43 +274,48 @@ static const NIFeature _nif_industrytile = { /*** NewGRF industries ***/ +#define NIP_PRODUCED_CARGO(prop, base, slot, type, name) { name, [] (const void *b) -> const void * { return std::addressof(static_cast(b)->GetProduced(slot).cargo); }, sizeof(CargoID), prop, type } +#define NIP_ACCEPTED_CARGO(prop, base, slot, type, name) { name, [] (const void *b) -> const void * { return std::addressof(static_cast(b)->GetAccepted(slot).cargo); }, sizeof(CargoID), prop, type } static const NIProperty _nip_industries[] = { - 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_PRODUCED_CARGO(0x25, Industry, 0, NIT_CARGO, "produced cargo 0"), + NIP_PRODUCED_CARGO(0x25, Industry, 1, NIT_CARGO, "produced cargo 1"), + NIP_PRODUCED_CARGO(0x25, Industry, 2, NIT_CARGO, "produced cargo 2"), + NIP_PRODUCED_CARGO(0x25, Industry, 3, NIT_CARGO, "produced cargo 3"), + NIP_PRODUCED_CARGO(0x25, Industry, 4, NIT_CARGO, "produced cargo 4"), + NIP_PRODUCED_CARGO(0x25, Industry, 5, NIT_CARGO, "produced cargo 5"), + NIP_PRODUCED_CARGO(0x25, Industry, 6, NIT_CARGO, "produced cargo 6"), + NIP_PRODUCED_CARGO(0x25, Industry, 7, NIT_CARGO, "produced cargo 7"), + NIP_PRODUCED_CARGO(0x25, Industry, 8, NIT_CARGO, "produced cargo 8"), + NIP_PRODUCED_CARGO(0x25, Industry, 9, NIT_CARGO, "produced cargo 9"), + NIP_PRODUCED_CARGO(0x25, Industry, 10, NIT_CARGO, "produced cargo 10"), + NIP_PRODUCED_CARGO(0x25, Industry, 11, NIT_CARGO, "produced cargo 11"), + NIP_PRODUCED_CARGO(0x25, Industry, 12, NIT_CARGO, "produced cargo 12"), + NIP_PRODUCED_CARGO(0x25, Industry, 13, NIT_CARGO, "produced cargo 13"), + NIP_PRODUCED_CARGO(0x25, Industry, 14, NIT_CARGO, "produced cargo 14"), + NIP_PRODUCED_CARGO(0x25, Industry, 15, NIT_CARGO, "produced cargo 15"), + NIP_ACCEPTED_CARGO(0x26, Industry, 0, NIT_CARGO, "accepted cargo 0"), + NIP_ACCEPTED_CARGO(0x26, Industry, 1, NIT_CARGO, "accepted cargo 1"), + NIP_ACCEPTED_CARGO(0x26, Industry, 2, NIT_CARGO, "accepted cargo 2"), + NIP_ACCEPTED_CARGO(0x26, Industry, 3, NIT_CARGO, "accepted cargo 3"), + NIP_ACCEPTED_CARGO(0x26, Industry, 4, NIT_CARGO, "accepted cargo 4"), + NIP_ACCEPTED_CARGO(0x26, Industry, 5, NIT_CARGO, "accepted cargo 5"), + NIP_ACCEPTED_CARGO(0x26, Industry, 6, NIT_CARGO, "accepted cargo 6"), + NIP_ACCEPTED_CARGO(0x26, Industry, 7, NIT_CARGO, "accepted cargo 7"), + NIP_ACCEPTED_CARGO(0x26, Industry, 8, NIT_CARGO, "accepted cargo 8"), + NIP_ACCEPTED_CARGO(0x26, Industry, 9, NIT_CARGO, "accepted cargo 9"), + NIP_ACCEPTED_CARGO(0x26, Industry, 10, NIT_CARGO, "accepted cargo 10"), + NIP_ACCEPTED_CARGO(0x26, Industry, 11, NIT_CARGO, "accepted cargo 11"), + NIP_ACCEPTED_CARGO(0x26, Industry, 12, NIT_CARGO, "accepted cargo 12"), + NIP_ACCEPTED_CARGO(0x26, Industry, 13, NIT_CARGO, "accepted cargo 13"), + NIP_ACCEPTED_CARGO(0x26, Industry, 14, NIT_CARGO, "accepted cargo 14"), + NIP_ACCEPTED_CARGO(0x26, Industry, 15, NIT_CARGO, "accepted cargo 15"), NIP_END() }; +#undef NIP_PRODUCED_CARGO +#undef NIP_ACCEPTED_CARGO + #define NICI(cb_id, bit) NIC(cb_id, IndustrySpec, callback_mask, bit) static const NICallback _nic_industries[] = { NICI(CBID_INDUSTRY_PROBABILITY, CBM_IND_PROBABILITY),