mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-09 15:41:15 +00:00
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.
This commit is contained in:
parent
e60c5f30a3
commit
51bd344f10
@ -41,6 +41,20 @@ CargoTypes _standard_cargo_mask;
|
|||||||
*/
|
*/
|
||||||
static std::vector<CargoLabel> _default_cargo_labels;
|
static std::vector<CargoLabel> _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<CargoLabel, 12> _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<CargoLabel, 32> _v8_cargo_labels;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the default cargo types for the given landscape type.
|
* Set up the default cargo types for the given landscape type.
|
||||||
* @param l Landscape
|
* @param l Landscape
|
||||||
@ -51,6 +65,8 @@ void SetupCargoForClimate(LandscapeID l)
|
|||||||
|
|
||||||
_cargo_mask = 0;
|
_cargo_mask = 0;
|
||||||
_default_cargo_labels.clear();
|
_default_cargo_labels.clear();
|
||||||
|
_v7_cargo_labels.fill(CT_INVALID);
|
||||||
|
_v8_cargo_labels.fill(CT_INVALID);
|
||||||
|
|
||||||
/* Copy from default cargo by label or index. */
|
/* Copy from default cargo by label or index. */
|
||||||
auto insert = std::begin(CargoSpec::array);
|
auto insert = std::begin(CargoSpec::array);
|
||||||
@ -75,6 +91,8 @@ void SetupCargoForClimate(LandscapeID l)
|
|||||||
if (insert->IsValid()) {
|
if (insert->IsValid()) {
|
||||||
SetBit(_cargo_mask, insert->Index());
|
SetBit(_cargo_mask, insert->Index());
|
||||||
_default_cargo_labels.push_back(insert->label);
|
_default_cargo_labels.push_back(insert->label);
|
||||||
|
_v7_cargo_labels[insert->Index()] = insert->label;
|
||||||
|
_v8_cargo_labels[insert->bitnum] = insert->label;
|
||||||
}
|
}
|
||||||
++insert;
|
++insert;
|
||||||
}
|
}
|
||||||
@ -85,6 +103,17 @@ void SetupCargoForClimate(LandscapeID l)
|
|||||||
BuildCargoLabelMap();
|
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<const CargoLabel> GetDefaultCargoTranslationTable(uint8_t grf_version)
|
||||||
|
{
|
||||||
|
if (grf_version < 8) return _v7_cargo_labels;
|
||||||
|
return _v8_cargo_labels;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build cargo label map.
|
* Build cargo label map.
|
||||||
* This is called multiple times during NewGRF initialization as cargos are defined, so that TranslateRefitMask() and
|
* This is called multiple times during NewGRF initialization as cargos are defined, so that TranslateRefitMask() and
|
||||||
@ -130,23 +159,6 @@ Dimension GetLargestCargoIconSize()
|
|||||||
return size;
|
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.
|
* Get sprite for showing cargo of this type.
|
||||||
* @return Sprite number to use.
|
* @return Sprite number to use.
|
||||||
|
@ -208,7 +208,6 @@ extern CargoTypes _standard_cargo_mask;
|
|||||||
void SetupCargoForClimate(LandscapeID l);
|
void SetupCargoForClimate(LandscapeID l);
|
||||||
bool IsDefaultCargo(CargoID cid);
|
bool IsDefaultCargo(CargoID cid);
|
||||||
void BuildCargoLabelMap();
|
void BuildCargoLabelMap();
|
||||||
CargoID GetCargoIDByBitnum(uint8_t bitnum);
|
|
||||||
|
|
||||||
inline CargoID GetCargoIDByLabel(CargoLabel label)
|
inline CargoID GetCargoIDByLabel(CargoLabel label)
|
||||||
{
|
{
|
||||||
|
@ -1155,15 +1155,10 @@ static ChangeInfoResult RailVehicleChangeInfo(uint engine, int numinfo, int prop
|
|||||||
if (ctype == 0xFF) {
|
if (ctype == 0xFF) {
|
||||||
/* 0xFF is specified as 'use first refittable' */
|
/* 0xFF is specified as 'use first refittable' */
|
||||||
ei->cargo_type = INVALID_CARGO;
|
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. */
|
/* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
|
||||||
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
||||||
} else if (ctype < NUM_CARGO) {
|
if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
||||||
/* Use untranslated cargo. */
|
|
||||||
ei->cargo_type = ctype;
|
|
||||||
} else {
|
|
||||||
ei->cargo_type = INVALID_CARGO;
|
|
||||||
GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
|
||||||
}
|
}
|
||||||
ei->cargo_label = CT_INVALID;
|
ei->cargo_label = CT_INVALID;
|
||||||
break;
|
break;
|
||||||
@ -1417,15 +1412,10 @@ static ChangeInfoResult RoadVehicleChangeInfo(uint engine, int numinfo, int prop
|
|||||||
if (ctype == 0xFF) {
|
if (ctype == 0xFF) {
|
||||||
/* 0xFF is specified as 'use first refittable' */
|
/* 0xFF is specified as 'use first refittable' */
|
||||||
ei->cargo_type = INVALID_CARGO;
|
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. */
|
/* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
|
||||||
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
||||||
} else if (ctype < NUM_CARGO) {
|
if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "RoadVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
||||||
/* Use untranslated cargo. */
|
|
||||||
ei->cargo_type = ctype;
|
|
||||||
} else {
|
|
||||||
ei->cargo_type = INVALID_CARGO;
|
|
||||||
GrfMsg(2, "RailVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
|
||||||
}
|
}
|
||||||
ei->cargo_label = CT_INVALID;
|
ei->cargo_label = CT_INVALID;
|
||||||
break;
|
break;
|
||||||
@ -1613,15 +1603,10 @@ static ChangeInfoResult ShipVehicleChangeInfo(uint engine, int numinfo, int prop
|
|||||||
if (ctype == 0xFF) {
|
if (ctype == 0xFF) {
|
||||||
/* 0xFF is specified as 'use first refittable' */
|
/* 0xFF is specified as 'use first refittable' */
|
||||||
ei->cargo_type = INVALID_CARGO;
|
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. */
|
/* Use translated cargo. Might result in INVALID_CARGO (first refittable), if cargo is not defined. */
|
||||||
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
ei->cargo_type = GetCargoTranslation(ctype, _cur.grffile);
|
||||||
} else if (ctype < NUM_CARGO) {
|
if (ei->cargo_type == INVALID_CARGO) GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
||||||
/* Use untranslated cargo. */
|
|
||||||
ei->cargo_type = ctype;
|
|
||||||
} else {
|
|
||||||
ei->cargo_type = INVALID_CARGO;
|
|
||||||
GrfMsg(2, "ShipVehicleChangeInfo: Invalid cargo type {}, using first refittable", ctype);
|
|
||||||
}
|
}
|
||||||
ei->cargo_label = CT_INVALID;
|
ei->cargo_label = CT_INVALID;
|
||||||
break;
|
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 ((feature == GSF_STATIONS || feature == GSF_ROADSTOPS) && ctype == 0xFE) return SpriteGroupCargo::SG_DEFAULT_NA;
|
||||||
if (ctype == 0xFF) return SpriteGroupCargo::SG_PURCHASE;
|
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 */
|
/* Check if the cargo type is out of bounds of the cargo translation table */
|
||||||
if (ctype >= _cur.grffile->cargo_list.size()) {
|
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);
|
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.grffile->grf_version = version;
|
||||||
_cur.grfconfig->status = _cur.stage < GLS_RESERVE ? GCS_INITIALISED : GCS_ACTIVATED;
|
_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 */
|
/* 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);
|
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,16 +8872,11 @@ static void BuildCargoTranslationMap()
|
|||||||
for (const CargoSpec *cs : CargoSpec::Iterate()) {
|
for (const CargoSpec *cs : CargoSpec::Iterate()) {
|
||||||
if (!cs->IsValid()) continue;
|
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 */
|
/* Check the translation table for this cargo's label */
|
||||||
int idx = find_index(_cur.grffile->cargo_list, {cs->label});
|
int idx = find_index(_cur.grffile->cargo_list, {cs->label});
|
||||||
if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx;
|
if (idx >= 0) _cur.grffile->cargo_map[cs->Index()] = idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare loading a NewGRF file with its config
|
* Prepare loading a NewGRF file with its config
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "newgrf_cargo.h"
|
||||||
#include "newgrf_spritegroup.h"
|
#include "newgrf_spritegroup.h"
|
||||||
|
|
||||||
#include "safeguards.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)
|
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 */
|
/* Pre-version 7 uses the bitnum lookup from (standard in v8) instead of climate dependent in some places.. */
|
||||||
if (grffile->grf_version < 7 && !usebit) {
|
if (grffile->grf_version < 7 && usebit) {
|
||||||
if (cargo >= CargoSpec::GetArraySize() || !CargoSpec::Get(cargo)->IsValid()) return INVALID_CARGO;
|
auto default_table = GetDefaultCargoTranslationTable(8);
|
||||||
return cargo;
|
if (cargo < default_table.size()) return GetCargoIDByLabel(default_table[cargo]);
|
||||||
}
|
return INVALID_CARGO;
|
||||||
|
}
|
||||||
/* Other cases use (possibly translated) cargobits */
|
|
||||||
|
/* Look in translation table. */
|
||||||
if (!grffile->cargo_list.empty()) {
|
if (cargo < grffile->cargo_list.size()) return GetCargoIDByLabel(grffile->cargo_list[cargo]);
|
||||||
/* ...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);
|
|
||||||
}
|
|
||||||
return INVALID_CARGO;
|
return INVALID_CARGO;
|
||||||
}
|
}
|
||||||
|
@ -33,4 +33,6 @@ SpriteID GetCustomCargoSprite(const CargoSpec *cs);
|
|||||||
uint16_t GetCargoCallback(CallbackID callback, uint32_t param1, uint32_t param2, 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);
|
CargoID GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit = false);
|
||||||
|
|
||||||
|
std::span<const CargoLabel> GetDefaultCargoTranslationTable(uint8_t grf_version);
|
||||||
|
|
||||||
#endif /* NEWGRF_CARGO_H */
|
#endif /* NEWGRF_CARGO_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user