mirror of https://github.com/OpenTTD/OpenTTD
Merge 1fec42024c
into ebc74c8905
commit
c3b3c2ebf9
|
@ -363,7 +363,7 @@ void AddArticulatedParts(Vehicle *first)
|
|||
|
||||
t->subtype = 0;
|
||||
t->track = front->track;
|
||||
t->railtype = front->railtype;
|
||||
t->railtypes = front->railtypes;
|
||||
|
||||
t->spritenum = e_artic->u.rail.image_index;
|
||||
if (e_artic->CanCarryCargo()) {
|
||||
|
|
|
@ -71,7 +71,7 @@ bool CheckAutoreplaceValidity(EngineID from, EngineID to, CompanyID company)
|
|||
switch (type) {
|
||||
case VEH_TRAIN: {
|
||||
/* make sure the railtypes are compatible */
|
||||
if (!GetRailTypeInfo(e_from->u.rail.railtype)->compatible_railtypes.Any(GetRailTypeInfo(e_to->u.rail.railtype)->compatible_railtypes)) return false;
|
||||
if (!GetAllCompatibleRailTypes(e_from->u.rail.railtypes).Any(GetAllCompatibleRailTypes(e_to->u.rail.railtypes))) return false;
|
||||
|
||||
/* make sure we do not replace wagons with engines or vice versa */
|
||||
if ((e_from->u.rail.railveh_type == RAILVEH_WAGON) != (e_to->u.rail.railveh_type == RAILVEH_WAGON)) return false;
|
||||
|
|
|
@ -111,7 +111,7 @@ class ReplaceVehicleWindow : public Window {
|
|||
|
||||
if (draw_left && this->sel_railtype != INVALID_RAILTYPE) {
|
||||
/* Ensure that the railtype is specific to the selected one */
|
||||
if (rvi->railtype != this->sel_railtype) return false;
|
||||
if (!rvi->railtypes.Test(this->sel_railtype)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -632,14 +632,31 @@ static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engin
|
|||
}
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
|
||||
/* Supported rail types */
|
||||
std::string railtypes{};
|
||||
std::string_view list_separator = GetListSeparator();
|
||||
|
||||
for (RailType rt : rvi->railtypes) {
|
||||
if (!railtypes.empty()) railtypes += list_separator;
|
||||
AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
|
||||
}
|
||||
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_RAILTYPES, railtypes));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
|
||||
/* Max speed - Engine power */
|
||||
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_SPEED_POWER, PackVelocity(e->GetDisplayMaxSpeed(), e->type), e->GetPower()));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
|
||||
/* Max tractive effort - not applicable if old acceleration or maglev */
|
||||
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
|
||||
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) {
|
||||
bool is_maglev = true;
|
||||
for (RailType rt : rvi->railtypes) {
|
||||
is_maglev &= GetRailTypeInfo(rt)->acceleration_type == VehicleAccelerationModel::Maglev;
|
||||
}
|
||||
if (!is_maglev) {
|
||||
DrawString(left, right, y, GetString(STR_PURCHASE_INFO_MAX_TE, e->GetDisplayMaxTractiveEffort()));
|
||||
y += GetCharacterHeight(FS_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Running cost */
|
||||
|
@ -1378,7 +1395,7 @@ struct BuildVehicleWindow : Window {
|
|||
EngineID eid = e->index;
|
||||
const RailVehicleInfo *rvi = &e->u.rail;
|
||||
|
||||
if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
|
||||
if (this->filter.railtype != INVALID_RAILTYPE && !HasPowerOnRail(rvi->railtypes, this->filter.railtype)) continue;
|
||||
if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
|
||||
|
||||
/* Filter now! So num_engines and num_wagons is valid */
|
||||
|
|
|
@ -602,15 +602,13 @@ void SettingsDisableElrail(int32_t new_value)
|
|||
|
||||
void UpdateDisableElrailSettingState(bool disable, bool update_vehicles)
|
||||
{
|
||||
/* pick appropriate railtype for elrail engines depending on setting */
|
||||
const RailType new_railtype = disable ? RAILTYPE_RAIL : RAILTYPE_ELECTRIC;
|
||||
|
||||
/* walk through all train engines */
|
||||
for (Engine *e : Engine::IterateType(VEH_TRAIN)) {
|
||||
RailVehicleInfo *rv_info = &e->u.rail;
|
||||
/* update railtype of engines intended to use elrail */
|
||||
if (rv_info->intended_railtype == RAILTYPE_ELECTRIC) {
|
||||
rv_info->railtype = new_railtype;
|
||||
if (rv_info->intended_railtypes.Test(RAILTYPE_ELECTRIC)) {
|
||||
rv_info->railtypes.Set(RAILTYPE_ELECTRIC, !disable);
|
||||
rv_info->railtypes.Set(RAILTYPE_RAIL, disable);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -618,11 +616,12 @@ void UpdateDisableElrailSettingState(bool disable, bool update_vehicles)
|
|||
* normal rail too */
|
||||
if (disable) {
|
||||
for (Train *t : Train::Iterate()) {
|
||||
if (t->railtype == RAILTYPE_ELECTRIC) {
|
||||
if (t->railtypes.Test(RAILTYPE_ELECTRIC)) {
|
||||
/* this railroad vehicle is now compatible only with elrail,
|
||||
* so add there also normal rail compatibility */
|
||||
t->compatible_railtypes.Set(RAILTYPE_RAIL);
|
||||
t->railtype = RAILTYPE_RAIL;
|
||||
t->railtypes.Reset(RAILTYPE_ELECTRIC);
|
||||
t->railtypes.Set(RAILTYPE_RAIL);
|
||||
t->flags.Set(VehicleRailFlag::AllowedOnNormalRail);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1107,8 +1107,12 @@ static void NewVehicleAvailable(Engine *e)
|
|||
|
||||
if (e->type == VEH_TRAIN) {
|
||||
/* maybe make another rail type available */
|
||||
assert(e->u.rail.railtype < RAILTYPE_END);
|
||||
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes, TimerGameCalendar::date);
|
||||
assert(e->u.rail.railtypes != RailTypes{});
|
||||
RailTypes introduced{};
|
||||
for (RailType rt : e->u.rail.railtypes) {
|
||||
introduced |= GetRailTypeInfo(rt)->introduces_railtypes;
|
||||
}
|
||||
for (Company *c : Company::Iterate()) c->avail_railtypes = AddDateIntroducedRailTypes(c->avail_railtypes | introduced, TimerGameCalendar::date);
|
||||
} else if (e->type == VEH_ROAD) {
|
||||
/* maybe make another road type available */
|
||||
assert(e->u.road.roadtype < ROADTYPE_END);
|
||||
|
@ -1267,7 +1271,7 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company)
|
|||
if (type == VEH_TRAIN && company != OWNER_DEITY) {
|
||||
/* Check if the rail type is available to this company */
|
||||
const Company *c = Company::Get(company);
|
||||
if (!GetRailTypeInfo(e->u.rail.railtype)->compatible_railtypes.Any(c->avail_railtypes)) return false;
|
||||
if (!GetAllCompatibleRailTypes(e->u.rail.railtypes).Any(c->avail_railtypes)) return false;
|
||||
}
|
||||
if (type == VEH_ROAD && company != OWNER_DEITY) {
|
||||
/* Check if the road type is available to this company */
|
||||
|
|
|
@ -47,7 +47,8 @@ StringID GetEngineCategoryName(EngineID engine)
|
|||
case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT;
|
||||
case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP;
|
||||
case VEH_TRAIN:
|
||||
return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco;
|
||||
assert(e->u.rail.railtypes.Any());
|
||||
return GetRailTypeInfo(e->u.rail.railtypes.GetNthSetBit(0).value())->strings.new_loco;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,7 +182,24 @@ static std::string GetTrainEngineInfoString(const Engine &e)
|
|||
res << GetString(STR_ENGINE_PREVIEW_COST_WEIGHT, e.GetCost(), e.GetDisplayWeight());
|
||||
res << '\n';
|
||||
|
||||
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e.u.rail.railtype)->acceleration_type != 2) {
|
||||
if (e.u.rail.railtypes.Count() > 1) {
|
||||
std::string railtypes{};
|
||||
std::string_view list_separator = GetListSeparator();
|
||||
|
||||
for (RailType rt : e.u.rail.railtypes) {
|
||||
if (!railtypes.empty()) railtypes += list_separator;
|
||||
AppendStringInPlace(railtypes, GetRailTypeInfo(rt)->strings.name);
|
||||
}
|
||||
res << GetString(STR_ENGINE_PREVIEW_RAILTYPES, railtypes);
|
||||
res << '\n';
|
||||
}
|
||||
|
||||
bool is_maglev = true;
|
||||
for (RailType rt : e.u.rail.railtypes) {
|
||||
is_maglev &= GetRailTypeInfo(rt)->acceleration_type == VehicleAccelerationModel::Maglev;
|
||||
}
|
||||
|
||||
if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && !is_maglev) {
|
||||
res << GetString(STR_ENGINE_PREVIEW_SPEED_POWER_MAX_TE, PackVelocity(e.GetDisplayMaxSpeed(), e.type), e.GetPower(), e.GetDisplayMaxTractiveEffort());
|
||||
res << '\n';
|
||||
} else {
|
||||
|
|
|
@ -43,13 +43,20 @@ enum EngineClass : uint8_t {
|
|||
EC_MAGLEV, ///< Maglev engine.
|
||||
};
|
||||
|
||||
/** Acceleration model of a vehicle. */
|
||||
enum class VehicleAccelerationModel : uint8_t {
|
||||
Normal, ///< Default acceleration model.
|
||||
Monorail, ///< Monorail acceleration model.
|
||||
Maglev, ///< Maglev acceleration model.
|
||||
};
|
||||
|
||||
/** Information about a rail vehicle. */
|
||||
struct RailVehicleInfo {
|
||||
uint8_t image_index = 0;
|
||||
RailVehicleTypes railveh_type{};
|
||||
uint8_t cost_factor = 0; ///< Purchase cost factor; For multiheaded engines the sum of both engine prices.
|
||||
RailType railtype{}; ///< Railtype, mangled if elrail is disabled.
|
||||
RailType intended_railtype{}; ///< Intended railtype, regardless of elrail being enabled or disabled.
|
||||
RailTypes railtypes{}; ///< Railtypes, mangled if elrail is disabled.
|
||||
RailTypes intended_railtypes{}; ///< Intended railtypes, regardless of elrail being enabled or disabled.
|
||||
uint8_t ai_passenger_only = 0; ///< Bit value to tell AI that this engine is for passenger use only
|
||||
uint16_t max_speed = 0; ///< Maximum speed (1 unit = 1/1.6 mph = 1 km-ish/h)
|
||||
uint16_t power = 0; ///< Power of engine (hp); For multiheaded engines the sum of both engine powers.
|
||||
|
|
|
@ -131,7 +131,7 @@ int GroundVehicle<T, Type>::GetAcceleration() const
|
|||
*/
|
||||
int64_t resistance = 0;
|
||||
|
||||
bool maglev = v->GetAccelerationType() == 2;
|
||||
bool maglev = v->GetAccelerationType() == VehicleAccelerationModel::Maglev;
|
||||
|
||||
const int area = v->GetAirDragArea();
|
||||
if (!maglev) {
|
||||
|
|
|
@ -4173,6 +4173,7 @@ STR_PURCHASE_INFO_ALL_BUT :All but {CARGO_
|
|||
STR_PURCHASE_INFO_MAX_TE :{BLACK}Max. Tractive Effort: {GOLD}{FORCE}
|
||||
STR_PURCHASE_INFO_AIRCRAFT_RANGE :{BLACK}Range: {GOLD}{COMMA} tiles
|
||||
STR_PURCHASE_INFO_AIRCRAFT_TYPE :{BLACK}Aircraft type: {GOLD}{STRING}
|
||||
STR_PURCHASE_INFO_RAILTYPES :{BLACK}Rail types: {GOLD}{RAW_STRING}
|
||||
|
||||
###length 3
|
||||
STR_CARGO_TYPE_FILTER_ALL :All cargo types
|
||||
|
@ -4356,6 +4357,7 @@ STR_ENGINE_PREVIEW_RUNCOST_YEAR :Running Cost: {
|
|||
STR_ENGINE_PREVIEW_RUNCOST_PERIOD :Running Cost: {CURRENCY_LONG}/period
|
||||
STR_ENGINE_PREVIEW_CAPACITY :Capacity: {CARGO_LONG}
|
||||
STR_ENGINE_PREVIEW_CAPACITY_2 :Capacity: {CARGO_LONG}, {CARGO_LONG}
|
||||
STR_ENGINE_PREVIEW_RAILTYPES :Rail types: {RAW_STRING}
|
||||
|
||||
# Autoreplace window
|
||||
STR_REPLACE_VEHICLES_WHITE :{WHITE}Replace {STRING} - {STRING1}
|
||||
|
|
|
@ -270,7 +270,8 @@ Engine *GetNewEngine(const GRFFile *file, VehicleType type, uint16_t internal_id
|
|||
_gted.resize(Engine::GetPoolSize());
|
||||
}
|
||||
if (type == VEH_TRAIN) {
|
||||
_gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label;
|
||||
_gted[e->index].railtypelabels.clear();
|
||||
for (RailType rt : e->u.rail.railtypes) _gted[e->index].railtypelabels.push_back(GetRailTypeInfo(rt)->label);
|
||||
}
|
||||
|
||||
GrfMsg(5, "Created new engine at index {} for GRFID {:x}, type {}, index {}", e->index, std::byteswap(file->grfid), type, internal_id);
|
||||
|
@ -424,7 +425,8 @@ void ResetNewGRFData()
|
|||
|
||||
/* Fill rail type label temporary data for default trains */
|
||||
for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
|
||||
_gted[e->index].railtypelabel = GetRailTypeInfo(e->u.rail.railtype)->label;
|
||||
_gted[e->index].railtypelabels.clear();
|
||||
for (RailType rt : e->u.rail.railtypes) _gted[e->index].railtypelabels.push_back(GetRailTypeInfo(rt)->label);
|
||||
}
|
||||
|
||||
/* Reset GRM reservations */
|
||||
|
@ -861,7 +863,11 @@ static void FinaliseEngineArray()
|
|||
if (!e->info.climates.Test(_settings_game.game_creation.landscape)) continue;
|
||||
|
||||
switch (e->type) {
|
||||
case VEH_TRAIN: AppendCopyableBadgeList(e->badges, GetRailTypeInfo(e->u.rail.railtype)->badges, GSF_TRAINS); break;
|
||||
case VEH_TRAIN:
|
||||
for (RailType rt : e->u.rail.railtypes) {
|
||||
AppendCopyableBadgeList(e->badges, GetRailTypeInfo(rt)->badges, GSF_TRAINS);
|
||||
}
|
||||
break;
|
||||
case VEH_ROAD: AppendCopyableBadgeList(e->badges, GetRoadTypeInfo(e->u.road.roadtype)->badges, GSF_ROADVEHICLES); break;
|
||||
default: break;
|
||||
}
|
||||
|
@ -1708,13 +1714,18 @@ static void AfterLoadGRFs()
|
|||
}
|
||||
|
||||
for (Engine *e : Engine::IterateType(VEH_TRAIN)) {
|
||||
RailType railtype = GetRailTypeByLabel(_gted[e->index].railtypelabel);
|
||||
if (railtype == INVALID_RAILTYPE) {
|
||||
RailTypes railtypes{};
|
||||
for (RailTypeLabel label : _gted[e->index].railtypelabels) {
|
||||
auto rt = GetRailTypeByLabel(label);
|
||||
if (rt != INVALID_RAILTYPE) railtypes.Set(rt);
|
||||
}
|
||||
|
||||
if (railtypes.Any()) {
|
||||
e->u.rail.railtypes = railtypes;
|
||||
e->u.rail.intended_railtypes = railtypes;
|
||||
} else {
|
||||
/* Rail type is not available, so disable this engine */
|
||||
e->info.climates = {};
|
||||
} else {
|
||||
e->u.rail.railtype = railtype;
|
||||
e->u.rail.intended_railtype = railtype;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ static ChangeInfoResult RailTypeChangeInfo(uint first, uint last, int prop, Byte
|
|||
break;
|
||||
|
||||
case 0x15: // Acceleration model
|
||||
rti->acceleration_type = Clamp(buf.ReadByte(), 0, 2);
|
||||
rti->acceleration_type = static_cast<VehicleAccelerationModel>(Clamp(buf.ReadByte(), 0, 2));
|
||||
break;
|
||||
|
||||
case 0x16: // Map colour
|
||||
|
|
|
@ -41,15 +41,16 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead
|
|||
case 0x05: { // Track type
|
||||
uint8_t tracktype = buf.ReadByte();
|
||||
|
||||
_gted[e->index].railtypelabels.clear();
|
||||
if (tracktype < _cur_gps.grffile->railtype_list.size()) {
|
||||
_gted[e->index].railtypelabel = _cur_gps.grffile->railtype_list[tracktype];
|
||||
_gted[e->index].railtypelabels.push_back(_cur_gps.grffile->railtype_list[tracktype]);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tracktype) {
|
||||
case 0: _gted[e->index].railtypelabel = rvi->engclass >= 2 ? RAILTYPE_LABEL_ELECTRIC : RAILTYPE_LABEL_RAIL; break;
|
||||
case 1: _gted[e->index].railtypelabel = RAILTYPE_LABEL_MONO; break;
|
||||
case 2: _gted[e->index].railtypelabel = RAILTYPE_LABEL_MAGLEV; break;
|
||||
case 0: _gted[e->index].railtypelabels.push_back(rvi->engclass >= 2 ? RAILTYPE_LABEL_ELECTRIC : RAILTYPE_LABEL_RAIL); break;
|
||||
case 1: _gted[e->index].railtypelabels.push_back(RAILTYPE_LABEL_MONO); break;
|
||||
case 2: _gted[e->index].railtypelabels.push_back(RAILTYPE_LABEL_MAGLEV); break;
|
||||
default:
|
||||
GrfMsg(1, "RailVehicleChangeInfo: Invalid track type {} specified, ignoring", tracktype);
|
||||
break;
|
||||
|
@ -179,11 +180,11 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead
|
|||
break;
|
||||
}
|
||||
|
||||
if (_cur_gps.grffile->railtype_list.empty()) {
|
||||
if (_cur_gps.grffile->railtype_list.empty() && !_gted[e->index].railtypelabels.empty()) {
|
||||
/* Use traction type to select between normal and electrified
|
||||
* rail only when no translation list is in place. */
|
||||
if (_gted[e->index].railtypelabel == RAILTYPE_LABEL_RAIL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_LABEL_ELECTRIC;
|
||||
if (_gted[e->index].railtypelabel == RAILTYPE_LABEL_ELECTRIC && engclass < EC_ELECTRIC) _gted[e->index].railtypelabel = RAILTYPE_LABEL_RAIL;
|
||||
if (_gted[e->index].railtypelabels[0] == RAILTYPE_LABEL_RAIL && engclass >= EC_ELECTRIC) _gted[e->index].railtypelabels[0] = RAILTYPE_LABEL_ELECTRIC;
|
||||
if (_gted[e->index].railtypelabels[0] == RAILTYPE_LABEL_ELECTRIC && engclass < EC_ELECTRIC) _gted[e->index].railtypelabels[0] = RAILTYPE_LABEL_RAIL;
|
||||
}
|
||||
|
||||
rvi->engclass = engclass;
|
||||
|
@ -327,6 +328,22 @@ ChangeInfoResult RailVehicleChangeInfo(uint first, uint last, int prop, ByteRead
|
|||
e->badges = ReadBadgeList(buf, GSF_TRAINS);
|
||||
break;
|
||||
|
||||
case 0x34: { // List of track types
|
||||
uint8_t count = buf.ReadByte();
|
||||
|
||||
_gted[e->index].railtypelabels.clear();
|
||||
while (count--) {
|
||||
uint8_t tracktype = buf.ReadByte();
|
||||
|
||||
if (tracktype < _cur_gps.grffile->railtype_list.size()) {
|
||||
_gted[e->index].railtypelabels.push_back(_cur_gps.grffile->railtype_list[tracktype]);
|
||||
} else {
|
||||
GrfMsg(1, "RailVehicleChangeInfo: Invalid track type {} specified, ignoring", tracktype);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ret = CommonVehicleChangeInfo(ei, prop, buf);
|
||||
break;
|
||||
|
|
|
@ -27,7 +27,7 @@ struct GRFTempEngineData {
|
|||
CargoClasses cargo_allowed; ///< Bitmask of cargo classes that are allowed as a refit.
|
||||
CargoClasses cargo_allowed_required; ///< Bitmask of cargo classes that are required to be all present to allow a cargo as a refit.
|
||||
CargoClasses cargo_disallowed; ///< Bitmask of cargo classes that are disallowed as a refit.
|
||||
RailTypeLabel railtypelabel;
|
||||
std::vector<RailTypeLabel> railtypelabels;
|
||||
uint8_t roadtramtype;
|
||||
const GRFFile *defaultcargo_grf; ///< GRF defining the cargo translation table to use if the default cargo is the 'first refittable'.
|
||||
Refittability refittability; ///< Did the newgrf set any refittability property? If not, default refittability will be applied.
|
||||
|
|
|
@ -565,7 +565,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
|
|||
RailType rt = GetTileRailType(v->tile);
|
||||
const RailTypeInfo *rti = GetRailTypeInfo(rt);
|
||||
return (rti->flags.Test(RailTypeFlag::Catenary) ? 0x200 : 0) |
|
||||
(HasPowerOnRail(Train::From(v)->railtype, rt) ? 0x100 : 0) |
|
||||
(HasPowerOnRail(Train::From(v)->railtypes, rt) ? 0x100 : 0) |
|
||||
GetReverseRailTypeTranslation(rt, object->ro.grffile);
|
||||
}
|
||||
|
||||
|
@ -721,7 +721,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
|
|||
const Train *u = is_powered_wagon ? t->First() : t; // for powered wagons the engine defines the type of engine (i.e. railtype)
|
||||
RailType railtype = GetRailType(v->tile);
|
||||
bool powered = t->IsEngine() || is_powered_wagon;
|
||||
bool has_power = HasPowerOnRail(u->railtype, railtype);
|
||||
bool has_power = HasPowerOnRail(u->railtypes, railtype);
|
||||
|
||||
if (powered && has_power) SetBit(modflags, 5);
|
||||
if (powered && !has_power) SetBit(modflags, 6);
|
||||
|
@ -904,7 +904,7 @@ static uint32_t VehicleGetVariable(Vehicle *v, const VehicleScopeResolver *objec
|
|||
Train *t = Train::From(v);
|
||||
switch (variable - 0x80) {
|
||||
case 0x62: return t->track;
|
||||
case 0x66: return t->railtype;
|
||||
case 0x66: return t->railtypes.GetNthSetBit(0).value_or(RailType::INVALID_RAILTYPE);
|
||||
case 0x73: return 0x80 + VEHICLE_LENGTH - t->gcache.cached_veh_length;
|
||||
case 0x74: return t->gcache.cached_power;
|
||||
case 0x75: return GB(t->gcache.cached_power, 8, 24);
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
void SetDestination(const Train *v, bool override_rail_type = false)
|
||||
{
|
||||
this->compatible_railtypes = v->compatible_railtypes;
|
||||
if (override_rail_type) this->compatible_railtypes.Set(GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
||||
if (override_rail_type) this->compatible_railtypes.Set(GetAllCompatibleRailTypes(v->railtypes));
|
||||
}
|
||||
|
||||
bool IsCompatibleRailType(RailType rt)
|
||||
|
|
|
@ -296,7 +296,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
|
|||
if (IsRailDepotTile(tile) && !GetDepotReservationTrackBits(tile)) return PBSTileInfo(tile, trackdir, false);
|
||||
|
||||
FindTrainOnTrackInfo ftoti;
|
||||
ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->railtype)->compatible_railtypes, tile, trackdir);
|
||||
ftoti.res = FollowReservation(v->owner, GetAllCompatibleRailTypes(v->railtypes), tile, trackdir);
|
||||
ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg);
|
||||
if (train_on_res != nullptr) {
|
||||
CheckTrainsOnTrack(ftoti, ftoti.res.tile);
|
||||
|
@ -388,7 +388,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
|||
}
|
||||
|
||||
/* Check next tile. For performance reasons, we check for 90 degree turns ourself. */
|
||||
CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
||||
CFollowTrackRail ft(v, GetAllCompatibleRailTypes(v->railtypes));
|
||||
|
||||
/* End of track? */
|
||||
if (!ft.Follow(tile, trackdir)) {
|
||||
|
|
16
src/rail.cpp
16
src/rail.cpp
|
@ -262,11 +262,13 @@ RailTypes GetCompanyRailTypes(CompanyID company, bool introduces)
|
|||
const RailVehicleInfo *rvi = &e->u.rail;
|
||||
|
||||
if (rvi->railveh_type != RAILVEH_WAGON) {
|
||||
assert(rvi->railtype < RAILTYPE_END);
|
||||
assert(rvi->railtypes.Any());
|
||||
if (introduces) {
|
||||
rts.Set(GetRailTypeInfo(rvi->railtype)->introduces_railtypes);
|
||||
for (RailType rt : rvi->railtypes) {
|
||||
rts.Set(GetRailTypeInfo(rt)->introduces_railtypes);
|
||||
}
|
||||
} else {
|
||||
rts.Set(rvi->railtype);
|
||||
rts.Set(rvi->railtypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -291,11 +293,13 @@ RailTypes GetRailTypes(bool introduces)
|
|||
|
||||
const RailVehicleInfo *rvi = &e->u.rail;
|
||||
if (rvi->railveh_type != RAILVEH_WAGON) {
|
||||
assert(rvi->railtype < RAILTYPE_END);
|
||||
assert(rvi->railtypes.Any());
|
||||
if (introduces) {
|
||||
rts.Set(GetRailTypeInfo(rvi->railtype)->introduces_railtypes);
|
||||
for (RailType rt : rvi->railtypes) {
|
||||
rts.Set(GetRailTypeInfo(rt)->introduces_railtypes);
|
||||
}
|
||||
} else {
|
||||
rts.Set(rvi->railtype);
|
||||
rts.Set(rvi->railtypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
src/rail.h
50
src/rail.h
|
@ -214,7 +214,7 @@ public:
|
|||
/**
|
||||
* Acceleration type of this rail type
|
||||
*/
|
||||
uint8_t acceleration_type;
|
||||
VehicleAccelerationModel acceleration_type;
|
||||
|
||||
/**
|
||||
* Maximum speed for vehicles travelling on this rail type
|
||||
|
@ -317,6 +317,30 @@ inline RailType GetRailTypeInfoIndex(const RailTypeInfo *rti)
|
|||
return static_cast<RailType>(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all compatible railtypes for a set of railtypes.
|
||||
* @param railtypes Set of railtypes to get the compatible railtypes from.
|
||||
* @return Union of all compatible railtypes.
|
||||
*/
|
||||
inline RailTypes GetAllCompatibleRailTypes(RailTypes railtypes)
|
||||
{
|
||||
RailTypes compatible{};
|
||||
for (RailType rt : railtypes) compatible |= GetRailTypeInfo(rt)->compatible_railtypes;
|
||||
return compatible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all powered railtypes for a set of railtypes.
|
||||
* @param railtypes Set of railtypes to get the powered railtypes from.
|
||||
* @return Union of all powered railtypes.
|
||||
*/
|
||||
inline RailTypes GetAllPoweredRailTypes(RailTypes railtypes)
|
||||
{
|
||||
RailTypes powered{};
|
||||
for (RailType rt : railtypes) powered |= GetRailTypeInfo(rt)->powered_railtypes;
|
||||
return powered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an engine of the given RailType can drive on a tile with a given
|
||||
* RailType. This would normally just be an equality check, but for electric
|
||||
|
@ -330,6 +354,18 @@ inline bool IsCompatibleRail(RailType enginetype, RailType tiletype)
|
|||
return GetRailTypeInfo(enginetype)->compatible_railtypes.Test(tiletype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an engine of the given RailTypes can drive on a tile with a given
|
||||
* RailType.
|
||||
* @param enginetype The RailTypes of the engine we are considering.
|
||||
* @param tiletype The RailType of the tile we are considering.
|
||||
* @return Whether the engine can drive on this tile.
|
||||
*/
|
||||
inline bool IsCompatibleRail(RailTypes enginetype, RailType tiletype)
|
||||
{
|
||||
return GetAllCompatibleRailTypes(enginetype).Test(tiletype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an engine of the given RailType got power on a tile with a given
|
||||
* RailType. This would normally just be an equality check, but for electric
|
||||
|
@ -343,6 +379,18 @@ inline bool HasPowerOnRail(RailType enginetype, RailType tiletype)
|
|||
return GetRailTypeInfo(enginetype)->powered_railtypes.Test(tiletype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an engine of the given RailTypes got power on a tile with a given
|
||||
* RailType.
|
||||
* @param enginetype The RailTypes of the engine we are considering.
|
||||
* @param tiletype The RailType of the tile we are considering.
|
||||
* @return Whether the engine got power on this tile.
|
||||
*/
|
||||
inline bool HasPowerOnRail(RailTypes enginetype, RailType tiletype)
|
||||
{
|
||||
return GetAllPoweredRailTypes(enginetype).Test(tiletype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a RailType disallows build of level crossings.
|
||||
* @param rt The RailType to check.
|
||||
|
|
|
@ -1605,7 +1605,7 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
|
|||
Track track;
|
||||
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) {
|
||||
if (v != nullptr && !HasPowerOnRail(v->railtypes, totype)) {
|
||||
/* No power on new rail type, reroute. */
|
||||
FreeTrainTrackReservation(v);
|
||||
vehicles_affected.push_back(v);
|
||||
|
@ -1691,7 +1691,7 @@ CommandCost CmdConvertRail(DoCommandFlags flags, TileIndex tile, TileIndex area_
|
|||
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
|
||||
if (HasTunnelBridgeReservation(tile)) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != nullptr && !HasPowerOnRail(v->railtype, totype)) {
|
||||
if (v != nullptr && !HasPowerOnRail(v->railtypes, totype)) {
|
||||
/* No power on new rail type, reroute. */
|
||||
FreeTrainTrackReservation(v);
|
||||
vehicles_affected.push_back(v);
|
||||
|
|
|
@ -250,11 +250,11 @@ protected: // These functions should not be called outside acceleration code.
|
|||
|
||||
/**
|
||||
* Allows to know the acceleration type of a vehicle.
|
||||
* @return Zero, road vehicles always use a normal acceleration method.
|
||||
* @return \c VehicleAccelerationModel::Normal, road vehicles always use a normal acceleration method.
|
||||
*/
|
||||
inline int GetAccelerationType() const
|
||||
inline VehicleAccelerationModel GetAccelerationType() const
|
||||
{
|
||||
return 0;
|
||||
return VehicleAccelerationModel::Normal;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1333,10 +1333,10 @@ bool AfterLoadGame()
|
|||
RailType min_rail = RAILTYPE_ELECTRIC;
|
||||
|
||||
for (Train *v : Train::Iterate()) {
|
||||
RailType rt = RailVehInfo(v->engine_type)->railtype;
|
||||
RailTypes rts = RailVehInfo(v->engine_type)->railtypes;
|
||||
|
||||
v->railtype = rt;
|
||||
if (rt == RAILTYPE_ELECTRIC) min_rail = RAILTYPE_RAIL;
|
||||
v->railtypes = rts;
|
||||
if (rts.Test(RAILTYPE_ELECTRIC)) min_rail = RAILTYPE_RAIL;
|
||||
}
|
||||
|
||||
/* .. so we convert the entire map from normal to elrail (so maintain "fairness") */
|
||||
|
|
|
@ -1050,12 +1050,13 @@ static bool LoadOldCompany(LoadgameState &ls, int num)
|
|||
static uint32_t _old_order_ptr;
|
||||
static uint16_t _old_next_ptr;
|
||||
static typename VehicleID::BaseType _current_vehicle_id;
|
||||
static RailType _old_railtype;
|
||||
|
||||
static const OldChunks vehicle_train_chunk[] = {
|
||||
OCL_SVAR( OC_UINT8, Train, track ),
|
||||
OCL_SVAR( OC_UINT8, Train, force_proceed ),
|
||||
OCL_SVAR( OC_UINT16, Train, crash_anim_pos ),
|
||||
OCL_SVAR( OC_UINT8, Train, railtype ),
|
||||
OCL_VAR ( OC_UINT8, 1, &_old_railtype),
|
||||
|
||||
OCL_NULL( 5 ), ///< Junk
|
||||
|
||||
|
@ -1296,7 +1297,7 @@ bool LoadOldVehicle(LoadgameState &ls, int num)
|
|||
if (v->spritenum / 2 >= lengthof(spriteset_rail)) return false;
|
||||
v->spritenum = spriteset_rail[v->spritenum / 2]; // adjust railway sprite set offset
|
||||
/* Should be the original values for monorail / rail, can't use RailType constants */
|
||||
Train::From(v)->railtype = static_cast<RailType>(type == 0x25 ? 1 : 0);
|
||||
Train::From(v)->railtypes = RailTypes(static_cast<RailType>(type == 0x25 ? 1 : 0));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1357,6 +1358,10 @@ bool LoadOldVehicle(LoadgameState &ls, int num)
|
|||
Debug(oldloader, 0, "Loading failed - vehicle-array is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (v->type == VEH_TRAIN) {
|
||||
Train::From(v)->railtypes = RailTypes(_old_railtype);
|
||||
}
|
||||
}
|
||||
|
||||
if (_old_order_ptr != 0 && _old_order_ptr != 0xFFFFFFFF) {
|
||||
|
|
|
@ -403,6 +403,8 @@ enum SaveLoadVersion : uint16_t {
|
|||
SLV_FIX_SCC_ENCODED_NEGATIVE, ///< 353 PR#14049 Fix encoding of negative parameters.
|
||||
SLV_ORDERS_OWNED_BY_ORDERLIST, ///< 354 PR#13948 Orders stored in OrderList, pool removed.
|
||||
|
||||
SLV_ENGINE_MULTI_RAILTYPE, ///< 355 PR#14357 Train engines can have multiple railtypes.
|
||||
|
||||
SL_MAX_VERSION, ///< Highest possible saveload version
|
||||
};
|
||||
|
||||
|
|
|
@ -793,13 +793,16 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static RailType _old_railtype;
|
||||
|
||||
class SlVehicleTrain : public DefaultSaveLoadHandler<SlVehicleTrain, Vehicle> {
|
||||
public:
|
||||
static inline const SaveLoad description[] = {
|
||||
SLEG_STRUCT("common", SlVehicleCommon),
|
||||
SLE_VAR(Train, crash_anim_pos, SLE_UINT16),
|
||||
SLE_VAR(Train, force_proceed, SLE_UINT8),
|
||||
SLE_VAR(Train, railtype, SLE_UINT8),
|
||||
SLEG_CONDVAR("railtype", _old_railtype, SLE_UINT8, SL_MIN_VERSION, SLV_ENGINE_MULTI_RAILTYPE),
|
||||
SLE_VAR(Train, railtypes, SLE_UINT64),
|
||||
SLE_VAR(Train, track, SLE_UINT8),
|
||||
|
||||
SLE_CONDVAR(Train, flags, SLE_FILE_U8 | SLE_VAR_U16, SLV_2, SLV_100),
|
||||
|
@ -819,6 +822,10 @@ public:
|
|||
{
|
||||
if (v->type != VEH_TRAIN) return;
|
||||
SlObject(v, this->GetLoadDescription());
|
||||
|
||||
if (IsSavegameVersionBefore(SLV_ENGINE_MULTI_RAILTYPE)) {
|
||||
Train::From(v)->railtypes = RailTypes(_old_railtype);
|
||||
}
|
||||
}
|
||||
|
||||
void FixPointers(Vehicle *v) const override
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
* \li AICargo::CC_POTABLE
|
||||
* \li AICargo::CC_NON_POTABLE
|
||||
* \li AIVehicleList_Waypoint
|
||||
* \li AIRail::GetAllRailTypes
|
||||
*
|
||||
* Other changes:
|
||||
* \li AIBridge::GetBridgeID renamed to AIBridge::GetBridgeType
|
||||
|
@ -35,6 +36,7 @@
|
|||
* \li AIList instances can now be saved
|
||||
* \li AIVehicleList_Station accepts an optional AIVehicle::VehicleType parameter
|
||||
* \li AIList instances can now be cloned
|
||||
* \li AIRail::GetRailType will only return the first RailType of an engine, use AIRail::GetAllRailTypes instead
|
||||
*
|
||||
* \b 14.0
|
||||
*
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
* \li GSCargo::CC_NON_POTABLE
|
||||
* \li GSVehicleList_Waypoint
|
||||
* \li GSBaseStation::GetOwner
|
||||
* \li GSRail::GetAllRailTypes
|
||||
*
|
||||
* Other changes:
|
||||
* \li GSBridge::GetBridgeID renamed to GSBridge::GetBridgeType
|
||||
|
@ -36,6 +37,7 @@
|
|||
* \li GSList instances can now be saved
|
||||
* \li GSVehicleList_Station accepts an optional GSVehicle::VehicleType parameter
|
||||
* \li GSList instances can now be cloned
|
||||
* \li GSRail::GetRailType will only return the first RailType of an engine, use GSRail::GetAllRailTypes instead
|
||||
*
|
||||
* \b 14.0
|
||||
*
|
||||
|
|
|
@ -203,7 +203,7 @@
|
|||
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
||||
if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
|
||||
|
||||
return ::IsCompatibleRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
|
||||
return ::IsCompatibleRail(::RailVehInfo(engine_id)->railtypes, (::RailType)track_rail_type);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptEngine::HasPowerOnRail(EngineID engine_id, ScriptRail::RailType track_rail_type)
|
||||
|
@ -212,7 +212,7 @@
|
|||
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return false;
|
||||
if (!ScriptRail::IsRailTypeAvailable(track_rail_type)) return false;
|
||||
|
||||
return ::HasPowerOnRail((::RailType)::RailVehInfo(engine_id)->railtype, (::RailType)track_rail_type);
|
||||
return ::HasPowerOnRail(::RailVehInfo(engine_id)->railtypes, (::RailType)track_rail_type);
|
||||
}
|
||||
|
||||
/* static */ bool ScriptEngine::CanRunOnRoad(EngineID engine_id, ScriptRoad::RoadType road_type)
|
||||
|
@ -242,7 +242,15 @@
|
|||
if (!IsValidEngine(engine_id)) return ScriptRail::RAILTYPE_INVALID;
|
||||
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return ScriptRail::RAILTYPE_INVALID;
|
||||
|
||||
return (ScriptRail::RailType)(uint)::RailVehInfo(engine_id)->railtype;
|
||||
return static_cast<ScriptRail::RailType>(::RailVehInfo(engine_id)->railtypes.GetNthSetBit(0).value_or(::RailType::INVALID_RAILTYPE));
|
||||
}
|
||||
|
||||
/* static */ ScriptRail::RailTypes ScriptEngine::GetAllRailTypes(EngineID engine_id)
|
||||
{
|
||||
if (!IsValidEngine(engine_id)) return ScriptRail::INVALID_RAILTYPES;
|
||||
if (GetVehicleType(engine_id) != ScriptVehicle::VT_RAIL) return ScriptRail::INVALID_RAILTYPES;
|
||||
|
||||
return static_cast<ScriptRail::RailTypes>(::RailVehInfo(engine_id)->railtypes.base());
|
||||
}
|
||||
|
||||
/* static */ bool ScriptEngine::IsArticulated(EngineID engine_id)
|
||||
|
|
|
@ -248,14 +248,24 @@ public:
|
|||
static ScriptRoad::RoadType GetRoadType(EngineID engine_id);
|
||||
|
||||
/**
|
||||
* Get the RailType of the engine.
|
||||
* Get the first RailType of the engine.
|
||||
* @note This will only return the first RailType of a multi-system engine. Use GetAllRailTypes to get all rail types of the engine.
|
||||
* @param engine_id The engine to get the RailType of.
|
||||
* @pre IsValidEngine(engine_id).
|
||||
* @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL.
|
||||
* @return The RailType the engine has.
|
||||
* @return The first RailType the engine has.
|
||||
*/
|
||||
static ScriptRail::RailType GetRailType(EngineID engine_id);
|
||||
|
||||
/**
|
||||
* Get all RailType's of the engine.
|
||||
* @param engine_id The engine to get all RailTypes of.
|
||||
* @pre IsValidEngine(engine_id).
|
||||
* @pre GetVehicleType(engine_id) == ScriptVehicle::VT_RAIL.
|
||||
* @return All rail types of the engine.
|
||||
*/
|
||||
static ScriptRail::RailTypes GetAllRailTypes(EngineID engine_id);
|
||||
|
||||
/**
|
||||
* Check if the engine is articulated.
|
||||
* @param engine_id The engine to check.
|
||||
|
|
|
@ -49,6 +49,14 @@ public:
|
|||
RAILTYPE_INVALID = ::INVALID_RAILTYPE, ///< Invalid RailType.
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitmap with all possible rail types.
|
||||
*/
|
||||
enum RailTypes : int64_t {
|
||||
/* Note: these values represent part of the in-game RailTypes enum */
|
||||
INVALID_RAILTYPES = INT64_MAX, ///< Invalid RailTypes.
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitmap with all possible rail tracks on a tile.
|
||||
*/
|
||||
|
|
|
@ -270,7 +270,7 @@ void Squirrel::AddMethod(std::string_view method_name, SQFUNCTION proc, std::str
|
|||
sq_newslot(this->vm, -3, SQFalse);
|
||||
}
|
||||
|
||||
void Squirrel::AddConst(std::string_view var_name, int value)
|
||||
void Squirrel::AddConst(std::string_view var_name, SQInteger value)
|
||||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
|
|
|
@ -104,15 +104,21 @@ public:
|
|||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(std::string_view var_name, int value);
|
||||
void AddConst(std::string_view var_name, SQInteger value);
|
||||
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(std::string_view var_name, uint value) { this->AddConst(var_name, (int)value); }
|
||||
void AddConst(std::string_view var_name, uint value) { this->AddConst(var_name, (SQInteger)value); }
|
||||
|
||||
void AddConst(std::string_view var_name, const ConvertibleThroughBase auto &value) { this->AddConst(var_name, static_cast<int>(value.base())); }
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
* either a const to a class or to the global space.
|
||||
*/
|
||||
void AddConst(std::string_view var_name, int value) { this->AddConst(var_name, (SQInteger)value); }
|
||||
|
||||
void AddConst(std::string_view var_name, const ConvertibleThroughBase auto &value) { this->AddConst(var_name, static_cast<SQInteger>(value.base())); }
|
||||
|
||||
/**
|
||||
* Adds a const to the stack. Depending on the current state this means
|
||||
|
|
|
@ -86,7 +86,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
|||
8,
|
||||
|
||||
/* acceleration type */
|
||||
0,
|
||||
VehicleAccelerationModel::Normal,
|
||||
|
||||
/* max speed */
|
||||
0,
|
||||
|
@ -188,7 +188,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
|||
12,
|
||||
|
||||
/* acceleration type */
|
||||
0,
|
||||
VehicleAccelerationModel::Normal,
|
||||
|
||||
/* max speed */
|
||||
0,
|
||||
|
@ -286,7 +286,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
|||
16,
|
||||
|
||||
/* acceleration type */
|
||||
1,
|
||||
VehicleAccelerationModel::Monorail,
|
||||
|
||||
/* max speed */
|
||||
0,
|
||||
|
@ -384,7 +384,7 @@ static const RailTypeInfo _original_railtypes[] = {
|
|||
24,
|
||||
|
||||
/* acceleration type */
|
||||
2,
|
||||
VehicleAccelerationModel::Maglev,
|
||||
|
||||
/* max speed */
|
||||
0,
|
||||
|
|
24
src/train.h
24
src/train.h
|
@ -99,7 +99,7 @@ struct Train final : public GroundVehicle<Train, VEH_TRAIN> {
|
|||
Train *other_multiheaded_part = nullptr;
|
||||
|
||||
RailTypes compatible_railtypes{};
|
||||
RailType railtype = INVALID_RAILTYPE;
|
||||
RailTypes railtypes{};
|
||||
|
||||
TrackBits track{};
|
||||
TrainForceProceeding force_proceed{};
|
||||
|
@ -180,6 +180,15 @@ struct Train final : public GroundVehicle<Train, VEH_TRAIN> {
|
|||
return this->gcache.cached_veh_length / 2 + (this->Next() != nullptr ? this->Next()->gcache.cached_veh_length + 1 : 0) / 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to know the acceleration type of a vehicle.
|
||||
* @return Acceleration type of the vehicle.
|
||||
*/
|
||||
inline VehicleAccelerationModel GetAccelerationType() const
|
||||
{
|
||||
return GetRailTypeInfo(GetRailType(this->tile))->acceleration_type;
|
||||
}
|
||||
|
||||
protected: // These functions should not be called outside acceleration code.
|
||||
|
||||
/**
|
||||
|
@ -189,7 +198,7 @@ protected: // These functions should not be called outside acceleration code.
|
|||
inline uint16_t GetPower() const
|
||||
{
|
||||
/* Power is not added for articulated parts */
|
||||
if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtype, GetRailType(this->tile))) {
|
||||
if (!this->IsArticulatedPart() && HasPowerOnRail(this->railtypes, GetRailType(this->tile))) {
|
||||
uint16_t power = GetVehicleProperty(this, PROP_TRAIN_POWER, RailVehInfo(this->engine_type)->power);
|
||||
/* Halve power for multiheaded parts */
|
||||
if (this->IsMultiheaded()) power /= 2;
|
||||
|
@ -206,7 +215,7 @@ protected: // These functions should not be called outside acceleration code.
|
|||
inline uint16_t GetPoweredPartPower(const Train *head) const
|
||||
{
|
||||
/* For powered wagons the engine defines the type of engine (i.e. railtype) */
|
||||
if (this->flags.Test(VehicleRailFlag::PoweredWagon) && HasPowerOnRail(head->railtype, GetRailType(this->tile))) {
|
||||
if (this->flags.Test(VehicleRailFlag::PoweredWagon) && HasPowerOnRail(head->railtypes, GetRailType(this->tile))) {
|
||||
return RailVehInfo(this->gcache.first_engine)->pow_wag_power;
|
||||
}
|
||||
|
||||
|
@ -298,15 +307,6 @@ protected: // These functions should not be called outside acceleration code.
|
|||
return 15 * (512 + this->GetCurrentSpeed()) / 512;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to know the acceleration type of a vehicle.
|
||||
* @return Acceleration type of the vehicle.
|
||||
*/
|
||||
inline int GetAccelerationType() const
|
||||
{
|
||||
return GetRailTypeInfo(this->railtype)->acceleration_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the slope steepness used by this vehicle.
|
||||
* @return Slope steepness used by the vehicle.
|
||||
|
|
|
@ -127,7 +127,7 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes)
|
|||
|
||||
/* update the 'first engine' */
|
||||
u->gcache.first_engine = this == u ? EngineID::Invalid() : first_engine;
|
||||
u->railtype = rvi_u->railtype;
|
||||
u->railtypes = rvi_u->railtypes;
|
||||
|
||||
if (u->IsEngine()) first_engine = u->engine_type;
|
||||
|
||||
|
@ -172,13 +172,13 @@ void Train::ConsistChanged(ConsistChangeFlags allowed_changes)
|
|||
/* Do not count powered wagons for the compatible railtypes, as wagons always
|
||||
have railtype normal */
|
||||
if (rvi_u->power > 0) {
|
||||
this->compatible_railtypes.Set(GetRailTypeInfo(u->railtype)->powered_railtypes);
|
||||
this->compatible_railtypes.Set(GetAllPoweredRailTypes(u->railtypes));
|
||||
}
|
||||
|
||||
/* Some electric engines can be allowed to run on normal rail. It happens to all
|
||||
* existing electric engines when elrails are disabled and then re-enabled */
|
||||
if (u->flags.Test(VehicleRailFlag::AllowedOnNormalRail)) {
|
||||
u->railtype = RAILTYPE_RAIL;
|
||||
u->railtypes.Set(RAILTYPE_RAIL);
|
||||
u->compatible_railtypes.Set(RAILTYPE_RAIL);
|
||||
}
|
||||
|
||||
|
@ -639,7 +639,7 @@ static CommandCost CmdBuildRailWagon(DoCommandFlags flags, TileIndex tile, const
|
|||
const RailVehicleInfo *rvi = &e->u.rail;
|
||||
|
||||
/* Check that the wagon can drive on the track in question */
|
||||
if (!IsCompatibleRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
|
||||
if (!IsCompatibleRail(rvi->railtypes, GetRailType(tile))) return CMD_ERROR;
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
Train *v = new Train();
|
||||
|
@ -674,7 +674,7 @@ static CommandCost CmdBuildRailWagon(DoCommandFlags flags, TileIndex tile, const
|
|||
v->cargo_cap = rvi->capacity;
|
||||
v->refit_cap = 0;
|
||||
|
||||
v->railtype = rvi->railtype;
|
||||
v->railtypes = rvi->railtypes;
|
||||
|
||||
v->date_of_last_service = TimerGameEconomy::date;
|
||||
v->date_of_last_service_newgrf = TimerGameCalendar::date;
|
||||
|
@ -741,7 +741,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
|
|||
u->cargo_subtype = v->cargo_subtype;
|
||||
u->cargo_cap = v->cargo_cap;
|
||||
u->refit_cap = v->refit_cap;
|
||||
u->railtype = v->railtype;
|
||||
u->railtypes = v->railtypes;
|
||||
u->engine_type = v->engine_type;
|
||||
u->date_of_last_service = v->date_of_last_service;
|
||||
u->date_of_last_service_newgrf = v->date_of_last_service_newgrf;
|
||||
|
@ -776,7 +776,7 @@ CommandCost CmdBuildRailVehicle(DoCommandFlags flags, TileIndex tile, const Engi
|
|||
|
||||
/* Check if depot and new engine uses the same kind of tracks *
|
||||
* We need to see if the engine got power on the tile to avoid electric engines in non-electric depots */
|
||||
if (!HasPowerOnRail(rvi->railtype, GetRailType(tile))) return CMD_ERROR;
|
||||
if (!HasPowerOnRail(rvi->railtypes, GetRailType(tile))) return CMD_ERROR;
|
||||
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
DiagDirection dir = GetRailDepotDirection(tile);
|
||||
|
@ -808,7 +808,7 @@ CommandCost CmdBuildRailVehicle(DoCommandFlags flags, TileIndex tile, const Engi
|
|||
v->reliability_spd_dec = e->reliability_spd_dec;
|
||||
v->max_age = e->GetLifeLengthInDays();
|
||||
|
||||
v->railtype = rvi->railtype;
|
||||
v->railtypes = rvi->railtypes;
|
||||
|
||||
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
|
||||
v->date_of_last_service = TimerGameEconomy::date;
|
||||
|
@ -2427,7 +2427,7 @@ void FreeTrainTrackReservation(const Train *v)
|
|||
/* Don't free reservation if it's not ours. */
|
||||
if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return;
|
||||
|
||||
CFollowTrackRail ft(v, GetRailTypeInfo(v->railtype)->compatible_railtypes);
|
||||
CFollowTrackRail ft(v, GetAllCompatibleRailTypes(v->railtypes));
|
||||
while (ft.Follow(tile, td)) {
|
||||
tile = ft.new_tile;
|
||||
TrackdirBits bits = ft.new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile));
|
||||
|
@ -3083,7 +3083,7 @@ static inline void AffectSpeedByZChange(Train *v, int old_z)
|
|||
{
|
||||
if (old_z == v->z_pos || _settings_game.vehicle.train_acceleration_model != AM_ORIGINAL) return;
|
||||
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[static_cast<int>(v->GetAccelerationType())];
|
||||
|
||||
if (old_z < v->z_pos) {
|
||||
v->cur_speed -= (v->cur_speed * asp->z_up >> 8);
|
||||
|
@ -3490,7 +3490,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||
|
||||
if (chosen_dir != v->direction) {
|
||||
if (prev == nullptr && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[static_cast<int>(v->GetAccelerationType())];
|
||||
DirDiff diff = DirDifference(v->direction, chosen_dir);
|
||||
v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
|
||||
}
|
||||
|
|
|
@ -2810,7 +2810,7 @@ void Vehicle::ShowVisualEffect() const
|
|||
IsDepotTile(v->tile) ||
|
||||
IsTunnelTile(v->tile) ||
|
||||
(v->type == VEH_TRAIN &&
|
||||
!HasPowerOnRail(Train::From(v)->railtype, GetTileRailType(v->tile)))) {
|
||||
!HasPowerOnRail(Train::From(v)->railtypes, GetTileRailType(v->tile)))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -2596,7 +2596,7 @@ struct VehicleDetailsWindow : Window {
|
|||
(v->type == VEH_ROAD && _settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL)) {
|
||||
const GroundVehicleCache *gcache = v->GetGroundVehicleCache();
|
||||
if (v->type == VEH_TRAIN && (_settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ||
|
||||
GetRailTypeInfo(Train::From(v)->railtype)->acceleration_type == 2)) {
|
||||
Train::From(v)->GetAccelerationType() == VehicleAccelerationModel::Maglev)) {
|
||||
DrawString(tr, GetString(STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, gcache->cached_weight, gcache->cached_power, max_speed));
|
||||
} else {
|
||||
DrawString(tr, GetString(STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE, gcache->cached_weight, gcache->cached_power, max_speed, gcache->cached_max_te));
|
||||
|
|
Loading…
Reference in New Issue