|
@@ -935,25 +935,25 @@ static bool ReadSpriteLayout(ByteReader
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Translate the refit mask. refit_mask is uint32 as it has not been mapped to CargoTypes.
|
|
|
*/
|
|
|
static CargoTypes TranslateRefitMask(uint32 refit_mask)
|
|
|
{
|
|
|
CargoTypes result = 0;
|
|
|
for (uint8 bit : SetBitIterator(refit_mask)) {
|
|
|
CargoID cargo = GetCargoTranslation(bit, _cur.grffile, true);
|
|
|
if (cargo != CT_INVALID) SetBit(result, cargo);
|
|
|
if (IsValidCargoID(cargo)) SetBit(result, cargo);
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Converts TTD(P) Base Price pointers into the enum used by OTTD
|
|
|
* See http://wiki.ttdpatch.net/tiki-index.php?page=BaseCosts
|
|
|
* @param base_pointer TTD(P) Base Price Pointer
|
|
|
* @param error_location Function name for grf error messages
|
|
|
* @param[out] index If \a base_pointer is valid, \a index is assigned to the matching price; else it is left unchanged
|
|
|
*/
|
|
|
static void ConvertTTDBasePrice(uint32 base_pointer, const char *error_location, Price *index)
|
|
@@ -1297,26 +1297,25 @@ static ChangeInfoResult RailVehicleChang
|
|
|
ei->cargo_age_period = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x2C: // CTT refit include list
|
|
|
case 0x2D: { // CTT refit exclude list
|
|
|
uint8 count = buf->ReadByte();
|
|
|
_gted[e->index].UpdateRefittability(prop == 0x2C && count != 0);
|
|
|
if (prop == 0x2C) _gted[e->index].defaultcargo_grf = _cur.grffile;
|
|
|
CargoTypes &ctt = prop == 0x2C ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
|
|
|
ctt = 0;
|
|
|
while (count--) {
|
|
|
CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
SetBit(ctt, ctype);
|
|
|
if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case PROP_TRAIN_CURVE_SPEED_MOD: // 0x2E Curve speed modifier
|
|
|
rvi->curve_speed_mod = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x2F: // Engine variant
|
|
|
ei->variant_id = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
@@ -1507,26 +1506,25 @@ static ChangeInfoResult RoadVehicleChang
|
|
|
rvi->shorten_factor = buf->ReadByte();
|
|
|
break;
|
|
|
|
|
|
case 0x24: // CTT refit include list
|
|
|
case 0x25: { // CTT refit exclude list
|
|
|
uint8 count = buf->ReadByte();
|
|
|
_gted[e->index].UpdateRefittability(prop == 0x24 && count != 0);
|
|
|
if (prop == 0x24) _gted[e->index].defaultcargo_grf = _cur.grffile;
|
|
|
CargoTypes &ctt = prop == 0x24 ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
|
|
|
ctt = 0;
|
|
|
while (count--) {
|
|
|
CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
SetBit(ctt, ctype);
|
|
|
if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case 0x26: // Engine variant
|
|
|
ei->variant_id = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x27: // Extra miscellaneous flags
|
|
|
ei->extra_flags = static_cast<ExtraEngineFlags>(buf->ReadDWord());
|
|
|
break;
|
|
|
|
|
@@ -1691,26 +1689,25 @@ static ChangeInfoResult ShipVehicleChang
|
|
|
ei->cargo_age_period = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x1E: // CTT refit include list
|
|
|
case 0x1F: { // CTT refit exclude list
|
|
|
uint8 count = buf->ReadByte();
|
|
|
_gted[e->index].UpdateRefittability(prop == 0x1E && count != 0);
|
|
|
if (prop == 0x1E) _gted[e->index].defaultcargo_grf = _cur.grffile;
|
|
|
CargoTypes &ctt = prop == 0x1E ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
|
|
|
ctt = 0;
|
|
|
while (count--) {
|
|
|
CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
SetBit(ctt, ctype);
|
|
|
if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case 0x20: // Engine variant
|
|
|
ei->variant_id = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x21: // Extra miscellaneous flags
|
|
|
ei->extra_flags = static_cast<ExtraEngineFlags>(buf->ReadDWord());
|
|
|
break;
|
|
|
|
|
@@ -1853,26 +1850,25 @@ static ChangeInfoResult AircraftVehicleC
|
|
|
ei->cargo_age_period = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x1D: // CTT refit include list
|
|
|
case 0x1E: { // CTT refit exclude list
|
|
|
uint8 count = buf->ReadByte();
|
|
|
_gted[e->index].UpdateRefittability(prop == 0x1D && count != 0);
|
|
|
if (prop == 0x1D) _gted[e->index].defaultcargo_grf = _cur.grffile;
|
|
|
CargoTypes &ctt = prop == 0x1D ? _gted[e->index].ctt_include_mask : _gted[e->index].ctt_exclude_mask;
|
|
|
ctt = 0;
|
|
|
while (count--) {
|
|
|
CargoID ctype = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
SetBit(ctt, ctype);
|
|
|
if (IsValidCargoID(ctype)) SetBit(ctt, ctype);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case PROP_AIRCRAFT_RANGE: // 0x1F Max aircraft range
|
|
|
avi->max_range = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x20: // Engine variant
|
|
|
ei->variant_id = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
@@ -2538,43 +2534,43 @@ static ChangeInfoResult TownHouseChangeI
|
|
|
|
|
|
case 0x1E: { // Accepted cargo types
|
|
|
uint32 cargotypes = buf->ReadDWord();
|
|
|
|
|
|
/* Check if the cargo types should not be changed */
|
|
|
if (cargotypes == 0xFFFFFFFF) break;
|
|
|
|
|
|
for (uint j = 0; j < 3; j++) {
|
|
|
/* Get the cargo number from the 'list' */
|
|
|
uint8 cargo_part = GB(cargotypes, 8 * j, 8);
|
|
|
CargoID cargo = GetCargoTranslation(cargo_part, _cur.grffile);
|
|
|
|
|
|
if (cargo == CT_INVALID) {
|
|
|
if (!IsValidCargoID(cargo)) {
|
|
|
/* Disable acceptance of invalid cargo type */
|
|
|
housespec->cargo_acceptance[j] = 0;
|
|
|
} else {
|
|
|
housespec->accepts_cargo[j] = cargo;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case 0x1F: // Minimum life span
|
|
|
housespec->minimum_life = buf->ReadByte();
|
|
|
break;
|
|
|
|
|
|
case 0x20: { // Cargo acceptance watch list
|
|
|
byte count = buf->ReadByte();
|
|
|
for (byte j = 0; j < count; j++) {
|
|
|
CargoID cargo = GetCargoTranslation(buf->ReadByte(), _cur.grffile);
|
|
|
if (cargo != CT_INVALID) SetBit(housespec->watched_cargoes, cargo);
|
|
|
if (IsValidCargoID(cargo)) SetBit(housespec->watched_cargoes, cargo);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case 0x21: // long introduction year
|
|
|
housespec->min_year = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
|
case 0x22: // long maximum year
|
|
|
housespec->max_year = buf->ReadWord();
|
|
|
break;
|
|
|
|
|
@@ -5448,47 +5444,47 @@ static void NewSpriteGroup(ByteReader *b
|
|
|
}
|
|
|
group->again = buf->ReadByte();
|
|
|
} else if (type == 2) {
|
|
|
group->num_input = buf->ReadByte();
|
|
|
if (group->num_input > lengthof(group->subtract_input)) {
|
|
|
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
|
|
|
error->data = "too many inputs (max 16)";
|
|
|
return;
|
|
|
}
|
|
|
for (uint i = 0; i < group->num_input; i++) {
|
|
|
byte rawcargo = buf->ReadByte();
|
|
|
CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
|
|
|
if (cargo == CT_INVALID) {
|
|
|
if (!IsValidCargoID(cargo)) {
|
|
|
/* The mapped cargo is invalid. This is permitted at this point,
|
|
|
* as long as the result is not used. Mark it invalid so this
|
|
|
* can be tested later. */
|
|
|
group->version = 0xFF;
|
|
|
} else if (std::find(group->cargo_input, group->cargo_input + i, cargo) != group->cargo_input + i) {
|
|
|
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
|
|
|
error->data = "duplicate input cargo";
|
|
|
return;
|
|
|
}
|
|
|
group->cargo_input[i] = cargo;
|
|
|
group->subtract_input[i] = buf->ReadByte();
|
|
|
}
|
|
|
group->num_output = buf->ReadByte();
|
|
|
if (group->num_output > lengthof(group->add_output)) {
|
|
|
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
|
|
|
error->data = "too many outputs (max 16)";
|
|
|
return;
|
|
|
}
|
|
|
for (uint i = 0; i < group->num_output; i++) {
|
|
|
byte rawcargo = buf->ReadByte();
|
|
|
CargoID cargo = GetCargoTranslation(rawcargo, _cur.grffile);
|
|
|
if (cargo == CT_INVALID) {
|
|
|
if (!IsValidCargoID(cargo)) {
|
|
|
/* Mark this result as invalid to use */
|
|
|
group->version = 0xFF;
|
|
|
} else if (std::find(group->cargo_output, group->cargo_output + i, cargo) != group->cargo_output + i) {
|
|
|
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_INDPROD_CALLBACK);
|
|
|
error->data = "duplicate output cargo";
|
|
|
return;
|
|
|
}
|
|
|
group->cargo_output[i] = cargo;
|
|
|
group->add_output[i] = buf->ReadByte();
|
|
|
}
|
|
|
group->again = buf->ReadByte();
|
|
|
} else {
|
|
@@ -5544,25 +5540,25 @@ static CargoID TranslateCargo(uint8 feat
|
|
|
GrfMsg(1, "TranslateCargo: Cargo type {} out of range (max {}), skipping.", ctype, (unsigned int)_cur.grffile->cargo_list.size() - 1);
|
|
|
return CT_INVALID;
|
|
|
}
|
|
|
|
|
|
/* Look up the cargo label from the translation table */
|
|
|
CargoLabel cl = _cur.grffile->cargo_list[ctype];
|
|
|
if (cl == 0) {
|
|
|
GrfMsg(5, "TranslateCargo: Cargo type {} not available in this climate, skipping.", ctype);
|
|
|
return CT_INVALID;
|
|
|
}
|
|
|
|
|
|
ctype = GetCargoIDByLabel(cl);
|
|
|
if (ctype == CT_INVALID) {
|
|
|
if (!IsValidCargoID(ctype)) {
|
|
|
GrfMsg(5, "TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' unsupported, skipping.", GB(cl, 24, 8), GB(cl, 16, 8), GB(cl, 8, 8), GB(cl, 0, 8));
|
|
|
return CT_INVALID;
|
|
|
}
|
|
|
|
|
|
GrfMsg(6, "TranslateCargo: Cargo '{:c}{:c}{:c}{:c}' mapped to cargo type {}.", GB(cl, 24, 8), GB(cl, 16, 8), GB(cl, 8, 8), GB(cl, 0, 8), ctype);
|
|
|
return ctype;
|
|
|
}
|
|
|
|
|
|
|
|
|
static bool IsValidGroupID(uint16 groupid, const char *function)
|
|
|
{
|
|
|
if (groupid > MAX_SPRITEGROUP || _cur.spritegroups[groupid] == nullptr) {
|
|
@@ -5614,25 +5610,25 @@ static void VehicleMapSpriteGroup(ByteRe
|
|
|
if (!wagover) last_engines[i] = engines[i];
|
|
|
}
|
|
|
|
|
|
uint8 cidcount = buf->ReadByte();
|
|
|
for (uint c = 0; c < cidcount; c++) {
|
|
|
uint8 ctype = buf->ReadByte();
|
|
|
uint16 groupid = buf->ReadWord();
|
|
|
if (!IsValidGroupID(groupid, "VehicleMapSpriteGroup")) continue;
|
|
|
|
|
|
GrfMsg(8, "VehicleMapSpriteGroup: * [{}] Cargo type 0x{:X}, group id 0x{:02X}", c, ctype, groupid);
|
|
|
|
|
|
ctype = TranslateCargo(feature, ctype);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(ctype)) continue;
|
|
|
|
|
|
for (uint i = 0; i < idcount; i++) {
|
|
|
EngineID engine = engines[i];
|
|
|
|
|
|
GrfMsg(7, "VehicleMapSpriteGroup: [{}] Engine {}...", i, engine);
|
|
|
|
|
|
if (wagover) {
|
|
|
SetWagonOverrideSprites(engine, ctype, _cur.spritegroups[groupid], last_engines, last_engines_count);
|
|
|
} else {
|
|
|
SetCustomEngineSprites(engine, ctype, _cur.spritegroups[groupid]);
|
|
|
}
|
|
|
}
|
|
@@ -5693,25 +5689,25 @@ static void StationMapSpriteGroup(ByteRe
|
|
|
stations.reserve(idcount);
|
|
|
for (uint i = 0; i < idcount; i++) {
|
|
|
stations.push_back(buf->ReadExtendedByte());
|
|
|
}
|
|
|
|
|
|
uint8 cidcount = buf->ReadByte();
|
|
|
for (uint c = 0; c < cidcount; c++) {
|
|
|
uint8 ctype = buf->ReadByte();
|
|
|
uint16 groupid = buf->ReadWord();
|
|
|
if (!IsValidGroupID(groupid, "StationMapSpriteGroup")) continue;
|
|
|
|
|
|
ctype = TranslateCargo(GSF_STATIONS, ctype);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(ctype)) continue;
|
|
|
|
|
|
for (auto &station : stations) {
|
|
|
StationSpec *statspec = station >= _cur.grffile->stations.size() ? nullptr : _cur.grffile->stations[station].get();
|
|
|
|
|
|
if (statspec == nullptr) {
|
|
|
GrfMsg(1, "StationMapSpriteGroup: Station {} undefined, skipping", station);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
statspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
|
|
|
}
|
|
|
}
|
|
@@ -5874,25 +5870,25 @@ static void ObjectMapSpriteGroup(ByteRea
|
|
|
objects.reserve(idcount);
|
|
|
for (uint i = 0; i < idcount; i++) {
|
|
|
objects.push_back(buf->ReadExtendedByte());
|
|
|
}
|
|
|
|
|
|
uint8 cidcount = buf->ReadByte();
|
|
|
for (uint c = 0; c < cidcount; c++) {
|
|
|
uint8 ctype = buf->ReadByte();
|
|
|
uint16 groupid = buf->ReadWord();
|
|
|
if (!IsValidGroupID(groupid, "ObjectMapSpriteGroup")) continue;
|
|
|
|
|
|
ctype = TranslateCargo(GSF_OBJECTS, ctype);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(ctype)) continue;
|
|
|
|
|
|
for (auto &object : objects) {
|
|
|
ObjectSpec *spec = object >= _cur.grffile->objectspec.size() ? nullptr : _cur.grffile->objectspec[object].get();
|
|
|
|
|
|
if (spec == nullptr) {
|
|
|
GrfMsg(1, "ObjectMapSpriteGroup: Object {} undefined, skipping", object);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
spec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
|
|
|
}
|
|
|
}
|
|
@@ -6060,25 +6056,25 @@ static void RoadStopMapSpriteGroup(ByteR
|
|
|
roadstops.reserve(idcount);
|
|
|
for (uint i = 0; i < idcount; i++) {
|
|
|
roadstops.push_back(buf->ReadExtendedByte());
|
|
|
}
|
|
|
|
|
|
uint8 cidcount = buf->ReadByte();
|
|
|
for (uint c = 0; c < cidcount; c++) {
|
|
|
uint8 ctype = buf->ReadByte();
|
|
|
uint16 groupid = buf->ReadWord();
|
|
|
if (!IsValidGroupID(groupid, "RoadStopMapSpriteGroup")) continue;
|
|
|
|
|
|
ctype = TranslateCargo(GSF_ROADSTOPS, ctype);
|
|
|
if (ctype == CT_INVALID) continue;
|
|
|
if (!IsValidCargoID(ctype)) continue;
|
|
|
|
|
|
for (auto &roadstop : roadstops) {
|
|
|
RoadStopSpec *roadstopspec = roadstop >= _cur.grffile->roadstops.size() ? nullptr : _cur.grffile->roadstops[roadstop].get();
|
|
|
|
|
|
if (roadstopspec == nullptr) {
|
|
|
GrfMsg(1, "RoadStopMapSpriteGroup: Road stop {} undefined, skipping", roadstop);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
roadstopspec->grf_prop.spritegroup[ctype] = _cur.spritegroups[groupid];
|
|
|
}
|
|
|
}
|
|
@@ -6835,27 +6831,27 @@ static void SkipIf(ByteReader *buf)
|
|
|
GrfMsg(7, "SkipIf: Param {} undefined, skipping test", param);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
GrfMsg(7, "SkipIf: Test condtype {}, param 0x{:02X}, condval 0x{:08X}", condtype, param, cond_val);
|
|
|
|
|
|
/* condtypes that do not use 'param' are always valid.
|
|
|
* condtypes that use 'param' are either not valid for param 0x88, or they are only valid for param 0x88.
|
|
|
*/
|
|
|
if (condtype >= 0x0B) {
|
|
|
/* Tests that ignore 'param' */
|
|
|
switch (condtype) {
|
|
|
case 0x0B: result = GetCargoIDByLabel(BSWAP32(cond_val)) == CT_INVALID;
|
|
|
break;
|
|
|
case 0x0C: result = GetCargoIDByLabel(BSWAP32(cond_val)) != CT_INVALID;
|
|
|
case 0x0B: result = !IsValidCargoID(GetCargoIDByLabel(BSWAP32(cond_val)));
|
|
|
break;
|
|
|
case 0x0C: result = IsValidCargoID(GetCargoIDByLabel(BSWAP32(cond_val)));
|
|
|
break;
|
|
|
case 0x0D: result = GetRailTypeByLabel(BSWAP32(cond_val)) == INVALID_RAILTYPE;
|
|
|
break;
|
|
|
case 0x0E: result = GetRailTypeByLabel(BSWAP32(cond_val)) != INVALID_RAILTYPE;
|
|
|
break;
|
|
|
case 0x0F: {
|
|
|
RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
|
|
|
result = rt == INVALID_ROADTYPE || !RoadTypeIsRoad(rt);
|
|
|
break;
|
|
|
}
|
|
|
case 0x10: {
|
|
|
RoadType rt = GetRoadTypeByLabel(BSWAP32(cond_val));
|
|
@@ -8936,25 +8932,25 @@ GRFFile::~GRFFile()
|
|
|
delete[] this->language_map;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 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);
|
|
|
if (IsValidCargoID(cid)) 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 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;
|
|
@@ -9026,25 +9022,25 @@ static void CalculateRefitMasks()
|
|
|
_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);
|
|
|
if (IsValidCargoID(ei->cargo_type)) ClrBit(_gted[engine].ctt_exclude_mask, ei->cargo_type);
|
|
|
}
|
|
|
|
|
|
/* 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::NONEMPTY;
|
|
|
|
|
@@ -9055,63 +9051,63 @@ static void CalculateRefitMasks()
|
|
|
if (_gted[engine].cargo_disallowed & cs->classes) SetBit(not_mask, cs->Index());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
ei->refit_mask = ((mask & ~not_mask) ^ xor_mask) & _cargo_mask;
|
|
|
|
|
|
/* Apply explicit refit includes/excludes. */
|
|
|
ei->refit_mask |= _gted[engine].ctt_include_mask;
|
|
|
ei->refit_mask &= ~_gted[engine].ctt_exclude_mask;
|
|
|
}
|
|
|
|
|
|
/* Clear invalid cargoslots (from default vehicles or pre-NewCargo GRFs) */
|
|
|
if (ei->cargo_type != CT_INVALID && !HasBit(_cargo_mask, ei->cargo_type)) ei->cargo_type = CT_INVALID;
|
|
|
if (IsValidCargoID(ei->cargo_type) && !HasBit(_cargo_mask, ei->cargo_type)) ei->cargo_type = CT_INVALID;
|
|
|
|
|
|
/* Ensure that the vehicle is either not refittable, or that the default cargo is one of the refittable cargoes.
|
|
|
* Note: Vehicles refittable to no cargo are handle differently to vehicle refittable to a single cargo. The latter might have subtypes. */
|
|
|
if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && ei->cargo_type != CT_INVALID && !HasBit(ei->refit_mask, ei->cargo_type)) {
|
|
|
if (!only_defaultcargo && (e->type != VEH_SHIP || e->u.ship.old_refittable) && IsValidCargoID(ei->cargo_type) && !HasBit(ei->refit_mask, ei->cargo_type)) {
|
|
|
ei->cargo_type = CT_INVALID;
|
|
|
}
|
|
|
|
|
|
/* Check if this engine's cargo type is valid. If not, set to the first refittable
|
|
|
* cargo type. Finally disable the vehicle, if there is still no cargo. */
|
|
|
if (ei->cargo_type == CT_INVALID && ei->refit_mask != 0) {
|
|
|
if (!IsValidCargoID(ei->cargo_type) && ei->refit_mask != 0) {
|
|
|
/* Figure out which CTT to use for the default cargo, if it is 'first refittable'. */
|
|
|
const uint8 *cargo_map_for_first_refittable = nullptr;
|
|
|
{
|
|
|
const GRFFile *file = _gted[engine].defaultcargo_grf;
|
|
|
if (file == nullptr) file = e->GetGRF();
|
|
|
if (file != nullptr && file->grf_version >= 8 && file->cargo_list.size() != 0) {
|
|
|
cargo_map_for_first_refittable = file->cargo_map;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (cargo_map_for_first_refittable != nullptr) {
|
|
|
/* Use first refittable cargo from cargo translation table */
|
|
|
byte best_local_slot = 0xFF;
|
|
|
for (CargoID cargo_type : SetCargoBitIterator(ei->refit_mask)) {
|
|
|
byte local_slot = cargo_map_for_first_refittable[cargo_type];
|
|
|
if (local_slot < best_local_slot) {
|
|
|
best_local_slot = local_slot;
|
|
|
ei->cargo_type = cargo_type;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (ei->cargo_type == CT_INVALID) {
|
|
|
if (!IsValidCargoID(ei->cargo_type)) {
|
|
|
/* Use first refittable cargo slot */
|
|
|
ei->cargo_type = (CargoID)FindFirstBit(ei->refit_mask);
|
|
|
}
|
|
|
}
|
|
|
if (ei->cargo_type == CT_INVALID) ei->climates = 0;
|
|
|
if (!IsValidCargoID(ei->cargo_type)) ei->climates = 0;
|
|
|
|
|
|
/* Clear refit_mask for not refittable ships */
|
|
|
if (e->type == VEH_SHIP && !e->u.ship.old_refittable) {
|
|
|
ei->refit_mask = 0;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** Set to use the correct action0 properties for each canal feature */
|
|
|
static void FinaliseCanals()
|
|
|
{
|
|
|
for (uint i = 0; i < CF_END; i++) {
|