Feature: Define refittability of default vehicles using cargo classes.

This ensures that default vehicles can transport any NewGRF defined cargos, albeit with weird graphics and vehicle names.
This also changes the refittability of default vehicles with default industries.
This commit is contained in:
frosch 2021-04-30 21:15:27 +02:00 committed by frosch
parent 9f8d0b1bee
commit 1da0ba95b2
1 changed files with 89 additions and 58 deletions

View File

@ -8724,65 +8724,116 @@ GRFFile::~GRFFile()
}
/**
* List of what cargo labels are refittable for the given the vehicle-type.
* Only currently active labels are applied.
*/
static const CargoLabel _default_refitmasks_rail[] = {
'PASS', 'COAL', 'MAIL', 'LVST', 'GOOD', 'GRAI', 'WHEA', 'MAIZ', 'WOOD',
'IORE', 'STEL', 'VALU', 'GOLD', 'DIAM', 'PAPR', 'FOOD', 'FRUT', 'CORE',
'WATR', 'SUGR', 'TOYS', 'BATT', 'SWET', 'TOFF', 'COLA', 'CTCD', 'BUBL',
'PLST', 'FZDR',
0 };
static const CargoLabel _default_refitmasks_road[] = {
0 };
static const CargoLabel _default_refitmasks_ships[] = {
'COAL', 'MAIL', 'LVST', 'GOOD', 'GRAI', 'WHEA', 'MAIZ', 'WOOD', 'IORE',
'STEL', 'VALU', 'GOLD', 'DIAM', 'PAPR', 'FOOD', 'FRUT', 'CORE', 'WATR',
'RUBR', 'SUGR', 'TOYS', 'BATT', 'SWET', 'TOFF', 'COLA', 'CTCD', 'BUBL',
'PLST', 'FZDR',
0 };
static const CargoLabel _default_refitmasks_aircraft[] = {
'PASS', 'MAIL', 'GOOD', 'VALU', 'GOLD', 'DIAM', 'FOOD', 'FRUT', 'SUGR',
'TOYS', 'BATT', 'SWET', 'TOFF', 'COLA', 'CTCD', 'BUBL', 'PLST', 'FZDR',
0 };
static const CargoLabel * const _default_refitmasks[] = {
_default_refitmasks_rail,
_default_refitmasks_road,
_default_refitmasks_ships,
_default_refitmasks_aircraft,
};
/**
* Precalculate refit masks from cargo classes for all vehicles.
*/
static void CalculateRefitMasks()
{
CargoTypes original_known_cargoes = 0;
for (int ct = 0; ct != NUM_ORIGINAL_CARGO; ++ct) {
CargoID cid = GetDefaultCargoID(_settings_game.game_creation.landscape, static_cast<CargoType>(ct));
if (cid != CT_INVALID) SetBit(original_known_cargoes, cid);
}
for (Engine *e : Engine::Iterate()) {
EngineID engine = e->index;
EngineInfo *ei = &e->info;
bool only_defaultcargo; ///< Set if the vehicle shall carry only the default cargo
/* If the NewGRF did not set any cargo properties, we apply default cargo translation. */
/* If the NewGRF did not set any cargo properties, we apply default values. */
if (_gted[engine].defaultcargo_grf == nullptr) {
/* If the vehicle has any capacity, apply the default refit masks */
if (e->type != VEH_TRAIN || e->u.rail.capacity != 0) {
static constexpr byte T = 1 << LT_TEMPERATE;
static constexpr byte A = 1 << LT_ARCTIC;
static constexpr byte S = 1 << LT_TROPIC;
static constexpr byte Y = 1 << LT_TOYLAND;
static const struct DefaultRefitMasks {
byte climate;
CargoType cargo_type;
CargoTypes cargo_allowed;
CargoTypes cargo_disallowed;
} _default_refit_masks[] = {
{T | A | S | Y, CT_PASSENGERS, CC_PASSENGERS, 0},
{T | A | S , CT_MAIL, CC_MAIL, 0},
{T | A | S , CT_VALUABLES, CC_ARMOURED, CC_LIQUID},
{ Y, CT_MAIL, CC_MAIL | CC_ARMOURED, CC_LIQUID},
{T | A , CT_COAL, CC_BULK, 0},
{ S , CT_COPPER_ORE, CC_BULK, 0},
{ Y, CT_SUGAR, CC_BULK, 0},
{T | A | S , CT_OIL, CC_LIQUID, 0},
{ Y, CT_COLA, CC_LIQUID, 0},
{T , CT_GOODS, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
{ A | S , CT_GOODS, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS | CC_REFRIGERATED},
{ A | S , CT_FOOD, CC_REFRIGERATED, 0},
{ Y, CT_CANDY, CC_PIECE_GOODS | CC_EXPRESS, CC_LIQUID | CC_PASSENGERS},
};
if (e->type == VEH_AIRCRAFT) {
/* Aircraft default to "light" cargoes */
_gted[engine].cargo_allowed = CC_PASSENGERS | CC_MAIL | CC_ARMOURED | CC_EXPRESS;
_gted[engine].cargo_disallowed = CC_LIQUID;
} else if (e->type == VEH_SHIP) {
switch (ei->cargo_type) {
case CT_PASSENGERS:
/* Ferries */
_gted[engine].cargo_allowed = CC_PASSENGERS;
_gted[engine].cargo_disallowed = 0;
break;
case CT_OIL:
/* Tankers */
_gted[engine].cargo_allowed = CC_LIQUID;
_gted[engine].cargo_disallowed = 0;
break;
default:
/* Cargo ships */
if (_settings_game.game_creation.landscape == LT_TOYLAND) {
/* No tanker in toyland :( */
_gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS | CC_LIQUID;
_gted[engine].cargo_disallowed = CC_PASSENGERS;
} else {
_gted[engine].cargo_allowed = CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS;
_gted[engine].cargo_disallowed = CC_LIQUID | CC_PASSENGERS;
}
break;
}
e->u.ship.old_refittable = true;
} else if (e->type == VEH_TRAIN && e->u.rail.railveh_type != RAILVEH_WAGON) {
/* Train engines default to all cargoes, so you can build single-cargo consists with fast engines.
* Trains loading multiple cargoes may start stations accepting unwanted cargoes. */
_gted[engine].cargo_allowed = CC_PASSENGERS | CC_MAIL | CC_ARMOURED | CC_EXPRESS | CC_BULK | CC_PIECE_GOODS | CC_LIQUID;
_gted[engine].cargo_disallowed = 0;
} else {
/* Train wagons and road vehicles are classified by their default cargo type */
for (const auto &drm : _default_refit_masks) {
if (!HasBit(drm.climate, _settings_game.game_creation.landscape)) continue;
if (drm.cargo_type != ei->cargo_type) continue;
_gted[engine].cargo_allowed = drm.cargo_allowed;
_gted[engine].cargo_disallowed = drm.cargo_disallowed;
break;
}
/* All original cargoes have specialised vehicles, so exclude them */
_gted[engine].ctt_exclude_mask = original_known_cargoes;
}
}
_gted[engine].UpdateRefittability(_gted[engine].cargo_allowed != 0);
/* Translate cargo_type using the original climate-specific cargo table. */
ei->cargo_type = GetDefaultCargoID(_settings_game.game_creation.landscape, static_cast<CargoType>(ei->cargo_type));
if (ei->cargo_type != CT_INVALID) ClrBit(_gted[engine].ctt_exclude_mask, ei->cargo_type);
}
/* Did the newgrf specify any refitting? If not, use defaults. */
if (_gted[engine].refittability != GRFTempEngineData::UNSET) {
/* Compute refittability */
{
CargoTypes mask = 0;
CargoTypes not_mask = 0;
CargoTypes xor_mask = ei->refit_mask;
/* If the original masks set by the grf are zero, the vehicle shall only carry the default cargo.
* Note: After applying the translations, the vehicle may end up carrying no defined cargo. It becomes unavailable in that case. */
only_defaultcargo = _gted[engine].refittability == GRFTempEngineData::EMPTY;
only_defaultcargo = _gted[engine].refittability != GRFTempEngineData::NONEMPTY;
if (_gted[engine].cargo_allowed != 0) {
/* Build up the list of cargo types from the set cargo classes. */
@ -8797,26 +8848,6 @@ static void CalculateRefitMasks()
/* Apply explicit refit includes/excludes. */
ei->refit_mask |= _gted[engine].ctt_include_mask;
ei->refit_mask &= ~_gted[engine].ctt_exclude_mask;
} else {
CargoTypes xor_mask = 0;
/* Don't apply default refit mask to wagons nor engines with no capacity */
if (e->type != VEH_TRAIN || (e->u.rail.capacity != 0 && e->u.rail.railveh_type != RAILVEH_WAGON)) {
const CargoLabel *cl = _default_refitmasks[e->type];
for (uint i = 0;; i++) {
if (cl[i] == 0) break;
CargoID cargo = GetCargoIDByLabel(cl[i]);
if (cargo == CT_INVALID) continue;
SetBit(xor_mask, cargo);
}
}
ei->refit_mask = xor_mask & _cargo_mask;
/* If the mask is zero, the vehicle shall only carry the default cargo */
only_defaultcargo = (ei->refit_mask == 0);
}
/* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */