From 51bd344f10fb495b8f01f2becddcf59c6eec1fde Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Mon, 23 Sep 2024 23:48:03 +0100 Subject: [PATCH] Change: Use default NewGRF cargo translation table. (#12646) Instead of falling back to bitnum lookup or climate-dependent cargo types, install a default cargo translation table that performs either of these functions instead. This allows better mapping of climate-dependent or bitnum cargo slots, falling back to INVALID_CARGO if they are not defined, and reduces special-casing. --- src/cargotype.cpp | 46 ++++++++++++++++++++------------ src/cargotype.h | 1 - src/newgrf.cpp | 63 +++++++++++--------------------------------- src/newgrf_cargo.cpp | 22 ++++++---------- src/newgrf_cargo.h | 2 ++ 5 files changed, 55 insertions(+), 79 deletions(-) diff --git a/src/cargotype.cpp b/src/cargotype.cpp index 870369dbbd..f91a0006cb 100644 --- a/src/cargotype.cpp +++ b/src/cargotype.cpp @@ -41,6 +41,20 @@ CargoTypes _standard_cargo_mask; */ static std::vector _default_cargo_labels; +/** + * Default cargo translation for upto version 7 NewGRFs. + * This maps the original 12 cargo slots to their original label. If a climate dependent cargo is not present it will + * map to CT_INVALID. For default cargoes this ends up as a 1:1 mapping via climate slot -> label -> cargo ID. + */ +static std::array _v7_cargo_labels; + +/** + * Default cargo translation for version 8+ NewGRFs. + * This maps the 32 "bitnum" cargo slots to their original label. If a bitnum is not present it will + * map to CT_INVALID. + */ +static std::array _v8_cargo_labels; + /** * Set up the default cargo types for the given landscape type. * @param l Landscape @@ -51,6 +65,8 @@ void SetupCargoForClimate(LandscapeID l) _cargo_mask = 0; _default_cargo_labels.clear(); + _v7_cargo_labels.fill(CT_INVALID); + _v8_cargo_labels.fill(CT_INVALID); /* Copy from default cargo by label or index. */ auto insert = std::begin(CargoSpec::array); @@ -75,6 +91,8 @@ void SetupCargoForClimate(LandscapeID l) if (insert->IsValid()) { SetBit(_cargo_mask, insert->Index()); _default_cargo_labels.push_back(insert->label); + _v7_cargo_labels[insert->Index()] = insert->label; + _v8_cargo_labels[insert->bitnum] = insert->label; } ++insert; } @@ -85,6 +103,17 @@ void SetupCargoForClimate(LandscapeID l) BuildCargoLabelMap(); } +/** + * Get default cargo translation table for a NewGRF, used if the NewGRF does not provide its own. + * @param grf_version GRF version of translation table. + * @return Default translation table for GRF version. + */ +std::span GetDefaultCargoTranslationTable(uint8_t grf_version) +{ + if (grf_version < 8) return _v7_cargo_labels; + return _v8_cargo_labels; +} + /** * Build cargo label map. * This is called multiple times during NewGRF initialization as cargos are defined, so that TranslateRefitMask() and @@ -130,23 +159,6 @@ Dimension GetLargestCargoIconSize() return size; } -/** - * Find the CargoID of a 'bitnum' value. - * @param bitnum 'bitnum' to find. - * @return First CargoID with the given bitnum, or #INVALID_CARGO if not found or if the provided \a bitnum is invalid. - */ -CargoID GetCargoIDByBitnum(uint8_t bitnum) -{ - if (bitnum == INVALID_CARGO_BITNUM) return INVALID_CARGO; - - for (const CargoSpec *cs : CargoSpec::Iterate()) { - if (cs->bitnum == bitnum) return cs->Index(); - } - - /* No matching label was found, so it is invalid */ - return INVALID_CARGO; -} - /** * Get sprite for showing cargo of this type. * @return Sprite number to use. diff --git a/src/cargotype.h b/src/cargotype.h index c53404d3be..4d7d92c764 100644 --- a/src/cargotype.h +++ b/src/cargotype.h @@ -208,7 +208,6 @@ extern CargoTypes _standard_cargo_mask; void SetupCargoForClimate(LandscapeID l); bool IsDefaultCargo(CargoID cid); void BuildCargoLabelMap(); -CargoID GetCargoIDByBitnum(uint8_t bitnum); inline CargoID GetCargoIDByLabel(CargoLabel label) { diff --git a/src/newgrf.cpp b/src/newgrf.cpp index 019e50cf2c..7ffb998885 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -1155,15 +1155,10 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; - } else if (_cur.grffile->grf_version >= 8) { + } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); - } else if (ctype < NUM_CARGO) { - /* Use untranslated cargo. */ - ei->cargo_type = ctype; - } else { - ei->cargo_type = INVALID_CARGO; - GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); + if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; break; @@ -1417,15 +1412,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; - } else if (_cur.grffile->grf_version >= 8) { + } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); - } else if (ctype < NUM_CARGO) { - /* Use untranslated cargo. */ - ei->cargo_type = ctype; - } else { - ei->cargo_type = INVALID_CARGO; - GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); + if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RoadVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; break; @@ -1613,15 +1603,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop if (ctype == 0xFF) { /* 0xFF is specified as 'use first refittable' */ ei->cargo_type = INVALID_CARGO; - } else if (_cur.grffile->grf_version >= 8) { + } else { /* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */ ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile); - } else if (ctype < NUM_CARGO) { - /* Use untranslated cargo. */ - ei->cargo_type = ctype; - } else { - ei->cargo_type = INVALID_CARGO; - GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); + if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype); } ei->cargo_label = CT_INVALID; break; @@ -5548,24 +5533,6 @@ static CargoID TranslateCargo(uint8_t feature, uint8_t ctype) if ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA; if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE; - if (_cur.grffile->cargo_list.empty()) { - /* No cargo table, so use bitnum values */ - if (ctype >= 32) { - GrfMsg(1, "TranslateCargo: Cargo bitnum {} out of range (max 31), skipping.", ctype); - return INVALID_CARGO; - } - - for (const CargoSpec *cs : CargoSpec::Iterate()) { - if (cs->bitnum == ctype) { - GrfMsg(6, "TranslateCargo: Cargo bitnum {} mapped to cargo type {}.", ctype, cs->Index()); - return cs->Index(); - } - } - - GrfMsg(5, "TranslateCargo: Cargo bitnum {} not available in this climate, skipping.", ctype); - return INVALID_CARGO; - } - /* Check if the cargo type is out of bounds of the cargo translation table */ if (ctype >= _cur.grffile->cargo_list.size()) { GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1); @@ -7057,6 +7024,13 @@ static void GRFInfo(ByteReader &buf) _cur.grffile->grf_version = version; _cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED; + /* Install the default cargo translation table. */ + if (_cur.stage < GLS_RESERVE && _cur.grffile->cargo_list.empty()) { + auto default_table = GetDefaultCargoTranslationTable(version); + _cur.grffile->cargo_list.assign(default_table.begin(), default_table.end()); + GrfMsg(3, "GRFInfo: Installing default GRFv{} translation table for {:08X}", version, BSWAP32(grfid)); + } + /* Do swap the GRFID for displaying purposes since people expect that */ Debug(grf, 1, "GRFInfo: Loaded GRFv{} set {:08X} - {} (palette: {}, version: {})", version, BSWAP32(grfid), StrMakeValid(name), (_cur.grfconfig->palette & GRFP_USE_MASK) ? "Windows" : "DOS", _cur.grfconfig->version); } @@ -8898,14 +8872,9 @@ static void BuildCargoTranslationMap() for (const CargoSpec *cs : CargoSpec::Iterate()) { if (!cs->IsValid()) continue; - if (_cur.grffile->cargo_list.empty()) { - /* Default translation table, so just a straight mapping to bitnum */ - _cur.grffile->cargo_map[cs->Index()] = cs->bitnum; - } else { - /* Check the translation table for this cargo's label */ - int idx = find_index(_cur.grffile->cargo_list, {cs->label}); - if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx; - } + /* Check the translation table for this cargo's label */ + int idx = find_index(_cur.grffile->cargo_list, {cs->label}); + if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx; } } diff --git a/src/newgrf_cargo.cpp b/src/newgrf_cargo.cpp index 97eaebec87..8c75c84835 100644 --- a/src/newgrf_cargo.cpp +++ b/src/newgrf_cargo.cpp @@ -9,6 +9,7 @@ #include "stdafx.h" #include "debug.h" +#include "newgrf_cargo.h" #include "newgrf_spritegroup.h" #include "safeguards.h" @@ -78,21 +79,14 @@ uint16_t GetCargoCallback(CallbackID callback, uint32_t param1, uint32_t param2, */ CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit) { - /* Pre-version 7 uses the 'climate dependent' ID in callbacks and properties, i.e. cargo is the cargo ID */ - if (grffile->grf_version < 7 && !usebit) { - if (cargo >= CargoSpec::GetArraySize() || !CargoSpec::Get(cargo)->IsValid()) return INVALID_CARGO; - return cargo; + /* Pre-version 7 uses the bitnum lookup from (standard in v8) instead of climate dependent in some places.. */ + if (grffile->grf_version < 7 && usebit) { + auto default_table = GetDefaultCargoTranslationTable(8); + if (cargo < default_table.size()) return GetCargoIDByLabel(default_table[cargo]); + return INVALID_CARGO; } - /* Other cases use (possibly translated) cargobits */ - - if (!grffile->cargo_list.empty()) { - /* ...and the cargo is in bounds, then get the cargo ID for - * the label */ - if (cargo < grffile->cargo_list.size()) return GetCargoIDByLabel(grffile->cargo_list[cargo]); - } else { - /* Else the cargo value is a 'climate independent' 'bitnum' */ - return GetCargoIDByBitnum(cargo); - } + /* Look in translation table. */ + if (cargo < grffile->cargo_list.size()) return GetCargoIDByLabel(grffile->cargo_list[cargo]); return INVALID_CARGO; } diff --git a/src/newgrf_cargo.h b/src/newgrf_cargo.h index d65a06a5b1..b590a5d98e 100644 --- a/src/newgrf_cargo.h +++ b/src/newgrf_cargo.h @@ -33,4 +33,6 @@ SpriteID GetCustomCargoSprite(const CargoSpec *cs); uint16_t GetCargoCallback(CallbackID callback, uint32_t param1, uint32_t param2, const CargoSpec *cs); CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit = false); +std::span GetDefaultCargoTranslationTable(uint8_t grf_version); + #endif /* NEWGRF_CARGO_H */