Merge branch 'master' into jgrpp-beta
# Conflicts: # .github/workflows/commit-checker.yml # src/company_cmd.cpp # src/console_cmds.cpp # src/crashlog.cpp # src/lang/english.txt # src/lang/german.txt # src/lang/indonesian.txt # src/lang/japanese.txt # src/lang/korean.txt # src/lang/swedish.txt # src/linkgraph/linkgraphjob.cpp # src/linkgraph/mcf.cpp # src/network/core/tcp.cpp # src/network/core/tcp.h # src/network/core/tcp_game.h # src/network/core/udp.h # src/network/network.cpp # src/network/network_admin.cpp # src/network/network_admin.h # src/network/network_chat_gui.cpp # src/network/network_client.cpp # src/network/network_client.h # src/network/network_func.h # src/network/network_internal.h # src/network/network_server.cpp # src/network/network_server.h # src/newgrf.cpp # src/newgrf_station.cpp # src/order_gui.cpp # src/rail_cmd.cpp # src/saveload/saveload.cpp # src/settings.cpp # src/settings_gui.cpp # src/settings_internal.h # src/settings_type.h # src/station_cmd.cpp # src/stdafx.h # src/table/currency_settings.ini # src/table/misc_settings.ini # src/table/settings.h.preamble # src/table/settings.ini # src/terraform_cmd.cpp # src/timetable_gui.cpp # src/train_cmd.cpp # src/tree_cmd.cpp # src/water_cmd.cpp
This commit is contained in:
186
src/newgrf.cpp
186
src/newgrf.cpp
@@ -2667,6 +2667,22 @@ static ChangeInfoResult LoadTranslationTable(uint gvid, int numinfo, ByteReader
|
||||
return CIR_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to read a DWord worth of bytes from the reader
|
||||
* and to return it as a valid string.
|
||||
* @param reader The source of the DWord.
|
||||
* @return The read DWord as string.
|
||||
*/
|
||||
static std::string ReadDWordAsString(ByteReader *reader)
|
||||
{
|
||||
char output[5];
|
||||
for (int i = 0; i < 4; i++) output[i] = reader->ReadByte();
|
||||
output[4] = '\0';
|
||||
str_validate(output, lastof(output));
|
||||
|
||||
return std::string(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define properties for global variables
|
||||
* @param gvid ID of the global variable.
|
||||
@@ -2754,11 +2770,10 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, co
|
||||
|
||||
case 0x0D: { // Currency prefix symbol
|
||||
uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
|
||||
uint32 tempfix = buf->ReadDWord();
|
||||
std::string prefix = ReadDWordAsString(buf);
|
||||
|
||||
if (curidx < CURRENCY_END) {
|
||||
memcpy(_currency_specs[curidx].prefix, &tempfix, 4);
|
||||
_currency_specs[curidx].prefix[4] = 0;
|
||||
_currency_specs[curidx].prefix = prefix;
|
||||
} else {
|
||||
grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
|
||||
}
|
||||
@@ -2767,11 +2782,10 @@ static ChangeInfoResult GlobalVarChangeInfo(uint gvid, int numinfo, int prop, co
|
||||
|
||||
case 0x0E: { // Currency suffix symbol
|
||||
uint curidx = GetNewgrfCurrencyIdConverted(gvid + i);
|
||||
uint32 tempfix = buf->ReadDWord();
|
||||
std::string suffix = ReadDWordAsString(buf);
|
||||
|
||||
if (curidx < CURRENCY_END) {
|
||||
memcpy(&_currency_specs[curidx].suffix, &tempfix, 4);
|
||||
_currency_specs[curidx].suffix[4] = 0;
|
||||
_currency_specs[curidx].suffix = suffix;
|
||||
} else {
|
||||
grfmsg(1, "GlobalVarChangeInfo: Currency symbol %d out of range, ignoring", curidx);
|
||||
}
|
||||
@@ -3268,7 +3282,7 @@ static ChangeInfoResult IndustrytilesChangeInfo(uint indtid, int numinfo, int pr
|
||||
|
||||
/* A copied tile should not have the animation infos copied too.
|
||||
* The anim_state should be left untouched, though
|
||||
* It is up to the author to animate them himself */
|
||||
* It is up to the author to animate them */
|
||||
tsp->anim_production = INDUSTRYTILE_NOANIM;
|
||||
tsp->anim_next = INDUSTRYTILE_NOANIM;
|
||||
|
||||
@@ -4960,6 +4974,7 @@ static void FeatureChangeInfo(ByteReader *buf)
|
||||
/* GSF_ROADTYPES */ RoadTypeChangeInfo,
|
||||
/* GSF_TRAMTYPES */ TramTypeChangeInfo,
|
||||
};
|
||||
static_assert(GSF_END == lengthof(handler));
|
||||
static_assert(lengthof(handler) == lengthof(_cur.grffile->action0_property_remaps), "Action 0 feature list length mismatch");
|
||||
|
||||
uint8 feature = buf->ReadByte();
|
||||
@@ -4975,7 +4990,7 @@ static void FeatureChangeInfo(ByteReader *buf)
|
||||
grfmsg(6, "FeatureChangeInfo: Feature 0x%02X, %d properties, to apply to %d+%d",
|
||||
feature, numprops, engine, numinfo);
|
||||
|
||||
if (feature >= lengthof(handler) || handler[feature] == nullptr) {
|
||||
if (handler[feature] == nullptr) {
|
||||
if (feature != GSF_CARGOES) grfmsg(1, "FeatureChangeInfo: Unsupported feature 0x%02X, skipping", feature);
|
||||
return;
|
||||
}
|
||||
@@ -8036,9 +8051,7 @@ static void TranslateGRFStrings(ByteReader *buf)
|
||||
* and disable this file. */
|
||||
GRFError *error = DisableGrf(STR_NEWGRF_ERROR_LOAD_AFTER);
|
||||
|
||||
char tmp[256];
|
||||
GetString(tmp, STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE, lastof(tmp));
|
||||
error->data = tmp;
|
||||
error->data = GetString(STR_NEWGRF_ERROR_AFTER_TRANSLATED_FILE);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -9481,59 +9494,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
|
||||
|
||||
/* Did the newgrf specify any refitting? If not, use defaults. */
|
||||
if (_gted[engine].refittability != GRFTempEngineData::UNSET) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@@ -9548,26 +9618,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) */
|
||||
|
Reference in New Issue
Block a user