mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-02-01 20:03:26 +00:00
(svn r16393) -Codechange: move VehicleRail to Train.
This commit is contained in:
parent
c4b627af42
commit
da5661a0c8
@ -49,7 +49,7 @@
|
||||
}
|
||||
return total_length;
|
||||
}
|
||||
case VEH_TRAIN: return v->u.rail.cached_total_length;
|
||||
case VEH_TRAIN: return ((Train *)v)->tcache.cached_total_length;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +314,7 @@ void AddArticulatedParts(Vehicle *first, VehicleType type)
|
||||
previous->SetNext(t);
|
||||
t->track = front->track;
|
||||
t->railtype = front->railtype;
|
||||
t->u.rail.first_engine = front->engine_type;
|
||||
t->tcache.first_engine = front->engine_type;
|
||||
|
||||
t->spritenum = e_artic->u.rail.image_index;
|
||||
if (e_artic->CanCarryCargo()) {
|
||||
|
@ -403,7 +403,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
|
||||
if (old_head->type == VEH_TRAIN) {
|
||||
/* Store the length of the old vehicle chain, rounded up to whole tiles */
|
||||
uint16 old_total_length = (old_head->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE;
|
||||
uint16 old_total_length = (((Train *)old_head)->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE * TILE_SIZE;
|
||||
|
||||
int num_units = 0; ///< Number of units in the chain
|
||||
for (Train *w = (Train *)old_head; w != NULL; w = GetNextUnit(w)) num_units++;
|
||||
@ -455,7 +455,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
}
|
||||
|
||||
/* When wagon removal is enabled and the new engines without any wagons are already longer than the old, we have to fail */
|
||||
if (cost.Succeeded() && wagon_removal && new_head->u.rail.cached_total_length > old_total_length) cost = CommandCost(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
|
||||
if (cost.Succeeded() && wagon_removal && new_head->tcache.cached_total_length > old_total_length) cost = CommandCost(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT);
|
||||
|
||||
/* Append/insert wagons into the new vehicle chain
|
||||
* We do this from back to front, so we can stop when wagon removal or maximum train length (i.e. from mammoth-train setting) is triggered.
|
||||
@ -469,7 +469,7 @@ static CommandCost ReplaceChain(Vehicle **chain, DoCommandFlag flags, bool wagon
|
||||
/* Insert wagon after 'last_engine' */
|
||||
CommandCost res = MoveVehicle(append, last_engine, DC_EXEC, false);
|
||||
|
||||
if (res.Succeeded() && wagon_removal && new_head->u.rail.cached_total_length > old_total_length) {
|
||||
if (res.Succeeded() && wagon_removal && new_head->tcache.cached_total_length > old_total_length) {
|
||||
MoveVehicle(append, NULL, DC_EXEC | DC_AUTOREPLACE, false);
|
||||
break;
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ struct DepotWindow : Window {
|
||||
DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
|
||||
|
||||
/* Number of wagons relative to a standard length wagon (rounded up) */
|
||||
SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
|
||||
SetDParam(0, (((Train *)v)->tcache.cached_total_length + 7) / 8);
|
||||
DrawString(this->widget[DEPOT_WIDGET_MATRIX].left, this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING, SA_RIGHT); // Draw the counter
|
||||
break;
|
||||
|
||||
@ -328,7 +328,7 @@ struct DepotWindow : Window {
|
||||
hnum = 8;
|
||||
for (uint num = 0; num < this->vehicle_list.Length(); num++) {
|
||||
const Vehicle *v = this->vehicle_list[num];
|
||||
hnum = max(hnum, v->u.rail.cached_total_length);
|
||||
hnum = max(hnum, ((Train *)v)->tcache.cached_total_length);
|
||||
}
|
||||
/* Always have 1 empty row, so people can change the setting of the train */
|
||||
SetVScrollCount(w, this->vehicle_list.Length() + this->wagon_list.Length() + 1);
|
||||
@ -450,7 +450,7 @@ struct DepotWindow : Window {
|
||||
x += skip;
|
||||
|
||||
/* find the vehicle in this row that was clicked */
|
||||
while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
|
||||
while (v != NULL && (x -= ((Train *)v)->tcache.cached_veh_length) >= 0) v = v->Next();
|
||||
|
||||
/* if an articulated part was selected, find its parent */
|
||||
while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
|
||||
@ -514,7 +514,7 @@ struct DepotWindow : Window {
|
||||
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN:
|
||||
_cursor.short_vehicle_offset = 16 - v->u.rail.cached_veh_length * 2;
|
||||
_cursor.short_vehicle_offset = 16 - ((Train *)v)->tcache.cached_veh_length * 2;
|
||||
break;
|
||||
|
||||
case VEH_ROAD:
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "vehicle_gui.h"
|
||||
#include "ai/ai.hpp"
|
||||
#include "aircraft.h"
|
||||
#include "train.h"
|
||||
#include "newgrf_engine.h"
|
||||
#include "newgrf_sound.h"
|
||||
#include "newgrf_industries.h"
|
||||
@ -1650,7 +1651,7 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
/* update stats */
|
||||
int t;
|
||||
switch (u->type) {
|
||||
case VEH_TRAIN: t = u->u.rail.cached_max_speed; break;
|
||||
case VEH_TRAIN: t = ((Train *)u)->tcache.cached_max_speed; break;
|
||||
case VEH_ROAD: t = u->max_speed / 2; break;
|
||||
default: t = u->max_speed; break;
|
||||
}
|
||||
@ -1759,7 +1760,7 @@ static void LoadUnloadVehicle(Vehicle *v, int *cargo_left)
|
||||
|
||||
if (v->type == VEH_TRAIN) {
|
||||
/* Each platform tile is worth 2 rail vehicles. */
|
||||
int overhang = v->u.rail.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
|
||||
int overhang = ((Train *)v)->tcache.cached_total_length - st->GetPlatformLength(v->tile) * TILE_SIZE;
|
||||
if (overhang > 0) {
|
||||
unloading_time <<= 1;
|
||||
unloading_time += (overhang * unloading_time) / 8;
|
||||
|
@ -434,7 +434,7 @@ static uint8 LiveryHelper(EngineID engine, const Vehicle *v)
|
||||
if (!Company::IsValidID(_current_company)) return 0;
|
||||
l = GetEngineLivery(engine, _current_company, INVALID_ENGINE, NULL);
|
||||
} else if (v->type == VEH_TRAIN) {
|
||||
l = GetEngineLivery(v->engine_type, v->owner, v->u.rail.first_engine, v);
|
||||
l = GetEngineLivery(v->engine_type, v->owner, ((Train *)v)->tcache.first_engine, v);
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
l = GetEngineLivery(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
|
||||
} else {
|
||||
@ -536,7 +536,7 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
|
||||
memset(common_subtypes, 0, sizeof(common_subtypes));
|
||||
|
||||
for (u = v; u != NULL; u = u->Next()) {
|
||||
if (v->type == VEH_TRAIN) user_def_data |= u->u.rail.user_def_data;
|
||||
if (v->type == VEH_TRAIN) user_def_data |= ((Train *)u)->tcache.user_def_data;
|
||||
|
||||
/* Skip empty engines */
|
||||
if (u->cargo_cap == 0) continue;
|
||||
@ -772,11 +772,11 @@ static uint32 VehicleGetVariable(const ResolverObject *object, byte variable, by
|
||||
switch (variable - 0x80) {
|
||||
case 0x62: return t->track;
|
||||
case 0x66: return t->railtype;
|
||||
case 0x73: return t->u.rail.cached_veh_length;
|
||||
case 0x74: return t->u.rail.cached_power;
|
||||
case 0x75: return GB(t->u.rail.cached_power, 8, 24);
|
||||
case 0x76: return GB(t->u.rail.cached_power, 16, 16);
|
||||
case 0x77: return GB(t->u.rail.cached_power, 24, 8);
|
||||
case 0x73: return t->tcache.cached_veh_length;
|
||||
case 0x74: return t->tcache.cached_power;
|
||||
case 0x75: return GB(t->tcache.cached_power, 8, 24);
|
||||
case 0x76: return GB(t->tcache.cached_power, 16, 16);
|
||||
case 0x77: return GB(t->tcache.cached_power, 24, 8);
|
||||
case 0x7C: return t->First()->index;
|
||||
case 0x7D: return GB(t->First()->index, 8, 8);
|
||||
case 0x7F: return 0; // Used for vehicle reversing hack in TTDP
|
||||
@ -886,7 +886,7 @@ static const SpriteGroup *GetVehicleSpriteGroup(EngineID engine, const Vehicle *
|
||||
/* We always use cached value, except for callbacks because the override spriteset
|
||||
* to use may be different than the one cached. It happens for callback 0x15 (refit engine),
|
||||
* as v->cargo_type is temporary changed to the new type */
|
||||
group = use_cache ? v->u.rail.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, v->u.rail.first_engine);
|
||||
group = use_cache ? ((Train *)v)->tcache.cached_override : GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, ((Train *)v)->tcache.first_engine);
|
||||
if (group != NULL) return group;
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
group = GetWagonOverrideSpriteSet(v->engine_type, v->cargo_type, ((RoadVehicle *)v)->first_engine);
|
||||
@ -952,7 +952,7 @@ SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_vi
|
||||
bool UsesWagonOverride(const Vehicle *v)
|
||||
{
|
||||
assert(v->type == VEH_TRAIN);
|
||||
return v->u.rail.cached_override != NULL;
|
||||
return ((Train *)v)->tcache.cached_override != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1127,17 +1127,18 @@ void StateGameLoop()
|
||||
|
||||
case VEH_TRAIN: {
|
||||
uint length = 0;
|
||||
for (Vehicle *u = v; u != NULL; u = u->Next()) length++;
|
||||
Train *t = (Train *)v;
|
||||
for (Vehicle *u = t; u != NULL; u = u->Next()) length++;
|
||||
|
||||
VehicleRail *wagons = MallocT<VehicleRail>(length);
|
||||
TrainCache *wagons = MallocT<TrainCache>(length);
|
||||
length = 0;
|
||||
for (Vehicle *u = v; u != NULL; u = u->Next()) wagons[length++] = u->u.rail;
|
||||
for (Train *u = t; u != NULL; u = u->Next()) wagons[length++] = u->tcache;
|
||||
|
||||
TrainConsistChanged((Train *)v, true);
|
||||
TrainConsistChanged(t, true);
|
||||
|
||||
length = 0;
|
||||
for (Vehicle *u = v; u != NULL; u = u->Next()) {
|
||||
if (memcmp(&wagons[length], &u->u.rail, sizeof(VehicleRail)) != 0) {
|
||||
for (Train *u = t; u != NULL; u = u->Next()) {
|
||||
if (memcmp(&wagons[length], &u->tcache, sizeof(TrainCache)) != 0) {
|
||||
DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length);
|
||||
}
|
||||
length++;
|
||||
|
@ -223,7 +223,7 @@ Vehicle *UpdateTrainPowerProc(Vehicle *v, void *data);
|
||||
void DrawTrainDepotSprite(int x, int y, int image, RailType railtype);
|
||||
void DrawDefaultWaypointSprite(int x, int y, RailType railtype);
|
||||
Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data);
|
||||
int TicksToLeaveDepot(const Vehicle *v);
|
||||
int TicksToLeaveDepot(const Train *v);
|
||||
|
||||
Foundation GetRailFoundation(Slope tileh, TrackBits bits);
|
||||
|
||||
|
@ -2433,10 +2433,10 @@ static const signed char _deltacoord_leaveoffset[8] = {
|
||||
* @param v vehicle outside (leaving) the depot
|
||||
* @return number of ticks when the next wagon will leave
|
||||
*/
|
||||
int TicksToLeaveDepot(const Vehicle *v)
|
||||
int TicksToLeaveDepot(const Train *v)
|
||||
{
|
||||
DiagDirection dir = GetRailDepotDirection(v->tile);
|
||||
int length = v->u.rail.cached_veh_length;
|
||||
int length = v->tcache.cached_veh_length;
|
||||
|
||||
switch (dir) {
|
||||
case DIAGDIR_NE: return ((int)(v->x_pos & 0x0F) - ((_fractcoords_enter[dir] & 0x0F) - (length + 1)));
|
||||
@ -2468,7 +2468,7 @@ static VehicleEnterTileStatus VehicleEnter_Track(Vehicle *u, TileIndex tile, int
|
||||
|
||||
/* calculate the point where the following wagon should be activated
|
||||
* this depends on the length of the current vehicle */
|
||||
length = v->u.rail.cached_veh_length;
|
||||
length = v->tcache.cached_veh_length;
|
||||
|
||||
fract_coord_leave =
|
||||
((_fractcoords_enter[dir] & 0x0F) + // x
|
||||
|
@ -252,7 +252,7 @@ void AfterLoadVehicles(bool part_of_load)
|
||||
|
||||
if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
|
||||
v->first = NULL;
|
||||
if (v->type == VEH_TRAIN) v->u.rail.first_engine = INVALID_ENGINE;
|
||||
if (v->type == VEH_TRAIN) ((Train *)v)->tcache.first_engine = INVALID_ENGINE;
|
||||
if (v->type == VEH_ROAD) ((RoadVehicle *)v)->first_engine = INVALID_ENGINE;
|
||||
|
||||
v->cargo.InvalidateCache();
|
||||
@ -318,7 +318,7 @@ void AfterLoadVehicles(bool part_of_load)
|
||||
assert(v->first != NULL);
|
||||
|
||||
if (v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) {
|
||||
if (IsFrontEngine(v)) ((Train *)v)->u.rail.last_speed = v->cur_speed; // update displayed train speed
|
||||
if (IsFrontEngine(v)) ((Train *)v)->tcache.last_speed = v->cur_speed; // update displayed train speed
|
||||
TrainConsistChanged((Train *)v, false);
|
||||
} else if (v->type == VEH_ROAD && IsRoadVehFront(v)) {
|
||||
RoadVehUpdateCache((RoadVehicle *)v);
|
||||
|
40
src/train.h
40
src/train.h
@ -259,6 +259,40 @@ void TrainConsistChanged(Train *v, bool same_length);
|
||||
void TrainPowerChanged(Train *v);
|
||||
Money GetTrainRunningCost(const Train *v);
|
||||
|
||||
/** Variables that are cached to improve performance and such */
|
||||
struct TrainCache {
|
||||
/* Cached wagon override spritegroup */
|
||||
const struct SpriteGroup *cached_override;
|
||||
|
||||
uint16 last_speed; // NOSAVE: only used in UI
|
||||
|
||||
/* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
|
||||
uint32 cached_power; ///< total power of the consist.
|
||||
uint16 cached_max_speed; ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
|
||||
uint16 cached_total_length; ///< Length of the whole train, valid only for first engine.
|
||||
uint8 cached_veh_length; ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
|
||||
bool cached_tilt; ///< train can tilt; feature provides a bonus in curves
|
||||
|
||||
/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
|
||||
uint32 cached_weight; ///< total weight of the consist.
|
||||
uint32 cached_veh_weight; ///< weight of the vehicle.
|
||||
uint32 cached_max_te; ///< max tractive effort of consist
|
||||
|
||||
/**
|
||||
* Position/type of visual effect.
|
||||
* bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
|
||||
* bit 4 - 5 = type of effect. (0 = default for engine class, 1 = steam, 2 = diesel, 3 = electric)
|
||||
* bit 6 = disable visual effect.
|
||||
* bit 7 = disable powered wagons.
|
||||
*/
|
||||
byte cached_vis_effect;
|
||||
byte user_def_data;
|
||||
|
||||
/* NOSAVE: for wagon override - id of the first engine in train
|
||||
* 0xffff == not in train */
|
||||
EngineID first_engine;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class 'wraps' Vehicle; you do not actually instantiate this class.
|
||||
* You create a Vehicle using AllocateVehicle, so it is added to the pool
|
||||
@ -268,6 +302,8 @@ Money GetTrainRunningCost(const Train *v);
|
||||
* As side-effect the vehicle type is set correctly.
|
||||
*/
|
||||
struct Train : public Vehicle {
|
||||
TrainCache tcache;
|
||||
|
||||
/* Link between the two ends of a multiheaded engine */
|
||||
Train *other_multiheaded_part;
|
||||
|
||||
@ -292,8 +328,8 @@ struct Train : public Vehicle {
|
||||
void PlayLeaveStationSound() const;
|
||||
bool IsPrimaryVehicle() const { return IsFrontEngine(this); }
|
||||
SpriteID GetImage(Direction direction) const;
|
||||
int GetDisplaySpeed() const { return this->u.rail.last_speed; }
|
||||
int GetDisplayMaxSpeed() const { return this->u.rail.cached_max_speed; }
|
||||
int GetDisplaySpeed() const { return this->tcache.last_speed; }
|
||||
int GetDisplayMaxSpeed() const { return this->tcache.cached_max_speed; }
|
||||
Money GetRunningCost() const;
|
||||
bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; }
|
||||
bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; }
|
||||
|
@ -107,22 +107,22 @@ void TrainPowerChanged(Train *v)
|
||||
|
||||
total_power += power;
|
||||
/* Tractive effort in (tonnes * 1000 * 10 =) N */
|
||||
max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
|
||||
max_te += (u->tcache.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (HasBit(u->flags, VRF_POWEREDWAGON) && HasPowerOnRail(v->railtype, railtype)) {
|
||||
total_power += RailVehInfo(u->u.rail.first_engine)->pow_wag_power;
|
||||
total_power += RailVehInfo(u->tcache.first_engine)->pow_wag_power;
|
||||
}
|
||||
}
|
||||
|
||||
if (v->u.rail.cached_power != total_power || v->u.rail.cached_max_te != max_te) {
|
||||
if (v->tcache.cached_power != total_power || v->tcache.cached_max_te != max_te) {
|
||||
/* If it has no power (no catenary), stop the train */
|
||||
if (total_power == 0) v->vehstatus |= VS_STOPPED;
|
||||
|
||||
v->u.rail.cached_power = total_power;
|
||||
v->u.rail.cached_max_te = max_te;
|
||||
v->tcache.cached_power = total_power;
|
||||
v->tcache.cached_max_te = max_te;
|
||||
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
||||
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
|
||||
}
|
||||
@ -149,18 +149,18 @@ static void TrainCargoChanged(Train *v)
|
||||
|
||||
/* powered wagons have extra weight added */
|
||||
if (HasBit(u->flags, VRF_POWEREDWAGON)) {
|
||||
vweight += RailVehInfo(u->u.rail.first_engine)->pow_wag_weight;
|
||||
vweight += RailVehInfo(u->tcache.first_engine)->pow_wag_weight;
|
||||
}
|
||||
|
||||
/* consist weight is the sum of the weight of all vehicles in the consist */
|
||||
weight += vweight;
|
||||
|
||||
/* store vehicle weight in cache */
|
||||
u->u.rail.cached_veh_weight = vweight;
|
||||
u->tcache.cached_veh_weight = vweight;
|
||||
}
|
||||
|
||||
/* store consist weight in cache */
|
||||
v->u.rail.cached_weight = weight;
|
||||
v->tcache.cached_weight = weight;
|
||||
|
||||
/* Now update train power (tractive effort is dependent on weight) */
|
||||
TrainPowerChanged(v);
|
||||
@ -192,7 +192,7 @@ void CheckTrainsLengths()
|
||||
for (const Train *u = (Train *)v, *w = (Train *)v->Next(); w != NULL; u = w, w = w->Next()) {
|
||||
if (u->track != TRACK_BIT_DEPOT) {
|
||||
if ((w->track != TRACK_BIT_DEPOT &&
|
||||
max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->u.rail.cached_veh_length) ||
|
||||
max(abs(u->x_pos - w->x_pos), abs(u->y_pos - w->y_pos)) != u->tcache.cached_veh_length) ||
|
||||
(w->track == TRACK_BIT_DEPOT && TicksToLeaveDepot(u) <= 0)) {
|
||||
SetDParam(0, v->index);
|
||||
SetDParam(1, v->owner);
|
||||
@ -222,7 +222,7 @@ void TrainConsistChanged(Train *v, bool same_length)
|
||||
|
||||
const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
|
||||
EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
|
||||
v->u.rail.cached_total_length = 0;
|
||||
v->tcache.cached_total_length = 0;
|
||||
v->compatible_railtypes = RAILTYPES_NONE;
|
||||
|
||||
bool train_can_tilt = true;
|
||||
@ -234,19 +234,19 @@ void TrainConsistChanged(Train *v, bool same_length)
|
||||
assert(u->First() == v);
|
||||
|
||||
/* update the 'first engine' */
|
||||
u->u.rail.first_engine = v == u ? INVALID_ENGINE : first_engine;
|
||||
u->tcache.first_engine = v == u ? INVALID_ENGINE : first_engine;
|
||||
u->railtype = rvi_u->railtype;
|
||||
|
||||
if (IsTrainEngine(u)) first_engine = u->engine_type;
|
||||
|
||||
/* Set user defined data to its default value */
|
||||
u->u.rail.user_def_data = rvi_u->user_def_data;
|
||||
u->tcache.user_def_data = rvi_u->user_def_data;
|
||||
u->cache_valid = 0;
|
||||
}
|
||||
|
||||
for (Train *u = v; u != NULL; u = u->Next()) {
|
||||
/* Update user defined data (must be done before other properties) */
|
||||
u->u.rail.user_def_data = GetVehicleProperty(u, 0x25, u->u.rail.user_def_data);
|
||||
u->tcache.user_def_data = GetVehicleProperty(u, 0x25, u->tcache.user_def_data);
|
||||
u->cache_valid = 0;
|
||||
}
|
||||
|
||||
@ -257,23 +257,23 @@ void TrainConsistChanged(Train *v, bool same_length)
|
||||
if (!HasBit(EngInfo(u->engine_type)->misc_flags, EF_RAIL_TILTS)) train_can_tilt = false;
|
||||
|
||||
/* Cache wagon override sprite group. NULL is returned if there is none */
|
||||
u->u.rail.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->u.rail.first_engine);
|
||||
u->tcache.cached_override = GetWagonOverrideSpriteSet(u->engine_type, u->cargo_type, u->tcache.first_engine);
|
||||
|
||||
/* Reset colour map */
|
||||
u->colourmap = PAL_NONE;
|
||||
|
||||
if (rvi_u->visual_effect != 0) {
|
||||
u->u.rail.cached_vis_effect = rvi_u->visual_effect;
|
||||
u->tcache.cached_vis_effect = rvi_u->visual_effect;
|
||||
} else {
|
||||
if (IsTrainWagon(u) || IsArticulatedPart(u)) {
|
||||
/* Wagons and articulated parts have no effect by default */
|
||||
u->u.rail.cached_vis_effect = 0x40;
|
||||
u->tcache.cached_vis_effect = 0x40;
|
||||
} else if (rvi_u->engclass == 0) {
|
||||
/* Steam is offset by -4 units */
|
||||
u->u.rail.cached_vis_effect = 4;
|
||||
u->tcache.cached_vis_effect = 4;
|
||||
} else {
|
||||
/* Diesel fumes and sparks come from the centre */
|
||||
u->u.rail.cached_vis_effect = 8;
|
||||
u->tcache.cached_vis_effect = 8;
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,11 +281,11 @@ void TrainConsistChanged(Train *v, bool same_length)
|
||||
if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) {
|
||||
uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u);
|
||||
|
||||
if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8);
|
||||
if (callback != CALLBACK_FAILED) u->tcache.cached_vis_effect = GB(callback, 0, 8);
|
||||
}
|
||||
|
||||
if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON &&
|
||||
UsesWagonOverride(u) && !HasBit(u->u.rail.cached_vis_effect, 7)) {
|
||||
UsesWagonOverride(u) && !HasBit(u->tcache.cached_vis_effect, 7)) {
|
||||
/* wagon is powered */
|
||||
SetBit(u->flags, VRF_POWEREDWAGON); // cache 'powered' status
|
||||
} else {
|
||||
@ -327,18 +327,18 @@ void TrainConsistChanged(Train *v, bool same_length)
|
||||
veh_len = 8 - Clamp(veh_len, 0, 7);
|
||||
|
||||
/* verify length hasn't changed */
|
||||
if (same_length && veh_len != u->u.rail.cached_veh_length) RailVehicleLengthChanged(u);
|
||||
if (same_length && veh_len != u->tcache.cached_veh_length) RailVehicleLengthChanged(u);
|
||||
|
||||
/* update vehicle length? */
|
||||
if (!same_length) u->u.rail.cached_veh_length = veh_len;
|
||||
if (!same_length) u->tcache.cached_veh_length = veh_len;
|
||||
|
||||
v->u.rail.cached_total_length += u->u.rail.cached_veh_length;
|
||||
v->tcache.cached_total_length += u->tcache.cached_veh_length;
|
||||
u->cache_valid = 0;
|
||||
}
|
||||
|
||||
/* store consist weight/max speed in cache */
|
||||
v->u.rail.cached_max_speed = max_speed;
|
||||
v->u.rail.cached_tilt = train_can_tilt;
|
||||
v->tcache.cached_max_speed = max_speed;
|
||||
v->tcache.cached_tilt = train_can_tilt;
|
||||
|
||||
/* recalculate cached weights and power too (we do this *after* the rest, so it is known which wagons are powered and need extra weight added) */
|
||||
TrainCargoChanged(v);
|
||||
@ -373,7 +373,7 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, i
|
||||
/* Default to the middle of the station for stations stops that are not in
|
||||
* the order list like intermediate stations when non-stop is disabled */
|
||||
OrderStopLocation osl = OSL_PLATFORM_MIDDLE;
|
||||
if (v->u.rail.cached_total_length >= *station_length) {
|
||||
if (v->tcache.cached_total_length >= *station_length) {
|
||||
/* The train is longer than the station, make it stop at the far end of the platform */
|
||||
osl = OSL_PLATFORM_FAR_END;
|
||||
} else if (v->current_order.IsType(OT_GOTO_STATION) && v->current_order.GetDestination() == station_id) {
|
||||
@ -386,11 +386,11 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, i
|
||||
default: NOT_REACHED();
|
||||
|
||||
case OSL_PLATFORM_NEAR_END:
|
||||
stop = v->u.rail.cached_total_length;
|
||||
stop = v->tcache.cached_total_length;
|
||||
break;
|
||||
|
||||
case OSL_PLATFORM_MIDDLE:
|
||||
stop = *station_length - (*station_length - v->u.rail.cached_total_length) / 2;
|
||||
stop = *station_length - (*station_length - v->tcache.cached_total_length) / 2;
|
||||
break;
|
||||
|
||||
case OSL_PLATFORM_FAR_END:
|
||||
@ -400,7 +400,7 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, i
|
||||
|
||||
/* Substract half the front vehicle length of the train so we get the real
|
||||
* stop location of the train. */
|
||||
return stop - (v->u.rail.cached_veh_length + 1) / 2;
|
||||
return stop - (v->tcache.cached_veh_length + 1) / 2;
|
||||
}
|
||||
|
||||
/** new acceleration*/
|
||||
@ -458,7 +458,7 @@ static int GetTrainAcceleration(Train *v, bool mode)
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(v->railtype);
|
||||
max_speed += (max_speed / 2) * rti->curve_speed;
|
||||
|
||||
if (v->u.rail.cached_tilt) {
|
||||
if (v->tcache.cached_tilt) {
|
||||
/* Apply max_speed bonus of 20% for a tilting train */
|
||||
max_speed += max_speed / 5;
|
||||
}
|
||||
@ -489,9 +489,9 @@ static int GetTrainAcceleration(Train *v, bool mode)
|
||||
}
|
||||
}
|
||||
|
||||
int mass = v->u.rail.cached_weight;
|
||||
int power = v->u.rail.cached_power * 746;
|
||||
max_speed = min(max_speed, v->u.rail.cached_max_speed);
|
||||
int mass = v->tcache.cached_weight;
|
||||
int power = v->tcache.cached_power * 746;
|
||||
max_speed = min(max_speed, v->tcache.cached_max_speed);
|
||||
|
||||
int num = 0; // number of vehicles, change this into the number of axles later
|
||||
int incl = 0;
|
||||
@ -503,9 +503,9 @@ static int GetTrainAcceleration(Train *v, bool mode)
|
||||
if (u->track == TRACK_BIT_DEPOT) max_speed = min(max_speed, 61);
|
||||
|
||||
if (HasBit(u->flags, VRF_GOINGUP)) {
|
||||
incl += u->u.rail.cached_veh_weight * 60; // 3% slope, quite a bit actually
|
||||
incl += u->tcache.cached_veh_weight * 60; // 3% slope, quite a bit actually
|
||||
} else if (HasBit(u->flags, VRF_GOINGDOWN)) {
|
||||
incl -= u->u.rail.cached_veh_weight * 60;
|
||||
incl -= u->tcache.cached_veh_weight * 60;
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +525,7 @@ static int GetTrainAcceleration(Train *v, bool mode)
|
||||
resistance += incl;
|
||||
resistance *= 4; //[N]
|
||||
|
||||
const int max_te = v->u.rail.cached_max_te; // [N]
|
||||
const int max_te = v->tcache.cached_max_te; // [N]
|
||||
int force;
|
||||
if (speed > 0) {
|
||||
switch (v->railtype) {
|
||||
@ -560,10 +560,10 @@ void UpdateTrainAcceleration(Train *v)
|
||||
{
|
||||
assert(IsFrontEngine(v));
|
||||
|
||||
v->max_speed = v->u.rail.cached_max_speed;
|
||||
v->max_speed = v->tcache.cached_max_speed;
|
||||
|
||||
uint power = v->u.rail.cached_power;
|
||||
uint weight = v->u.rail.cached_weight;
|
||||
uint power = v->tcache.cached_power;
|
||||
uint weight = v->tcache.cached_weight;
|
||||
assert(weight != 0);
|
||||
v->acceleration = Clamp(power / weight * 4, 1, 255);
|
||||
}
|
||||
@ -1185,13 +1185,13 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
/* Don't check callback for articulated or rear dual headed parts */
|
||||
if (!IsArticulatedPart(next_to_attach) && !IsRearDualheaded(next_to_attach)) {
|
||||
/* Back up and clear the first_engine data to avoid using wagon override group */
|
||||
EngineID first_engine = next_to_attach->u.rail.first_engine;
|
||||
next_to_attach->u.rail.first_engine = INVALID_ENGINE;
|
||||
EngineID first_engine = next_to_attach->tcache.first_engine;
|
||||
next_to_attach->tcache.first_engine = INVALID_ENGINE;
|
||||
|
||||
uint16 callback = GetVehicleCallbackParent(CBID_TRAIN_ALLOW_WAGON_ATTACH, 0, 0, dst_head->engine_type, next_to_attach, dst_head);
|
||||
|
||||
/* Restore original first_engine data */
|
||||
next_to_attach->u.rail.first_engine = first_engine;
|
||||
next_to_attach->tcache.first_engine = first_engine;
|
||||
|
||||
if (callback != CALLBACK_FAILED) {
|
||||
StringID error = STR_NULL;
|
||||
@ -1585,9 +1585,9 @@ static void UpdateVarsAfterSwap(Train *v)
|
||||
|
||||
static inline void SetLastSpeed(Train *v, int spd)
|
||||
{
|
||||
int old = v->u.rail.last_speed;
|
||||
int old = v->tcache.last_speed;
|
||||
if (spd != old) {
|
||||
v->u.rail.last_speed = spd;
|
||||
v->tcache.last_speed = spd;
|
||||
if (_settings_client.gui.vehicle_speed || (old == 0) != (spd == 0)) {
|
||||
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
|
||||
}
|
||||
@ -1790,7 +1790,7 @@ static void AdvanceWagonsBeforeSwap(Train *v)
|
||||
last = last->Previous();
|
||||
first = first->Next();
|
||||
|
||||
int differential = base->u.rail.cached_veh_length - last->u.rail.cached_veh_length;
|
||||
int differential = base->tcache.cached_veh_length - last->tcache.cached_veh_length;
|
||||
|
||||
/* do not update images now
|
||||
* negative differential will be handled in AdvanceWagonsAfterSwap() */
|
||||
@ -1850,7 +1850,7 @@ static void AdvanceWagonsAfterSwap(Train *v)
|
||||
last = last->Previous();
|
||||
first = first->Next();
|
||||
|
||||
int differential = last->u.rail.cached_veh_length - base->u.rail.cached_veh_length;
|
||||
int differential = last->tcache.cached_veh_length - base->tcache.cached_veh_length;
|
||||
|
||||
/* do not update images now */
|
||||
for (int i = 0; i < differential; i++) TrainController(first, (nomove ? last->Next() : NULL));
|
||||
@ -2267,9 +2267,9 @@ static void HandleLocomotiveSmokeCloud(const Train *v)
|
||||
|
||||
do {
|
||||
const RailVehicleInfo *rvi = RailVehInfo(v->engine_type);
|
||||
int effect_offset = GB(v->u.rail.cached_vis_effect, 0, 4) - 8;
|
||||
byte effect_type = GB(v->u.rail.cached_vis_effect, 4, 2);
|
||||
bool disable_effect = HasBit(v->u.rail.cached_vis_effect, 6);
|
||||
int effect_offset = GB(v->tcache.cached_vis_effect, 0, 4) - 8;
|
||||
byte effect_type = GB(v->tcache.cached_vis_effect, 4, 2);
|
||||
bool disable_effect = HasBit(v->tcache.cached_vis_effect, 6);
|
||||
|
||||
/* no smoke? */
|
||||
if ((rvi->railveh_type == RAILVEH_WAGON && effect_type == 0) ||
|
||||
@ -2394,7 +2394,7 @@ static bool CheckTrainStayInDepot(Train *v)
|
||||
}
|
||||
|
||||
/* if the train got no power, then keep it in the depot */
|
||||
if (v->u.rail.cached_power == 0) {
|
||||
if (v->tcache.cached_power == 0) {
|
||||
v->vehstatus |= VS_STOPPED;
|
||||
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
|
||||
return true;
|
||||
@ -4133,7 +4133,7 @@ static bool TrainApproachingLineEnd(Train *v, bool signal)
|
||||
}
|
||||
|
||||
/* do not reverse when approaching red signal */
|
||||
if (!signal && x + (v->u.rail.cached_veh_length + 1) / 2 >= TILE_SIZE) {
|
||||
if (!signal && x + (v->tcache.cached_veh_length + 1) / 2 >= TILE_SIZE) {
|
||||
/* we are too near the tile end, reverse now */
|
||||
v->cur_speed = 0;
|
||||
ReverseTrainDirection(v);
|
||||
@ -4353,7 +4353,7 @@ static bool TrainLocoHandler(Train *v, bool mode)
|
||||
int j = UpdateTrainSpeed(v);
|
||||
|
||||
/* we need to invalidate the widget if we are stopping from 'Stopping 0 km/h' to 'Stopped' */
|
||||
if (v->cur_speed == 0 && v->u.rail.last_speed == 0 && v->vehstatus & VS_STOPPED) {
|
||||
if (v->cur_speed == 0 && v->tcache.last_speed == 0 && v->vehstatus & VS_STOPPED) {
|
||||
InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ void DrawTrainImage(const Vehicle *v, int x, int y, VehicleID selection, int cou
|
||||
_cur_dpi = &tmp_dpi;
|
||||
|
||||
do {
|
||||
int width = v->u.rail.cached_veh_length;
|
||||
int width = ((Train *)v)->tcache.cached_veh_length;
|
||||
|
||||
if (dx + width > 0) {
|
||||
if (dx <= count) {
|
||||
@ -228,7 +228,7 @@ void DrawTrainDetails(const Vehicle *v, int left, int right, int y, int vscroll_
|
||||
do {
|
||||
SpriteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v);
|
||||
DrawSprite(u->GetImage(DIR_W), pal, x + WagonLengthToPixels(4 + dx), y + 6 + (is_custom_sprite(RailVehInfo(u->engine_type)->image_index) ? _traininfo_vehicle_pitch : 0));
|
||||
dx += u->u.rail.cached_veh_length;
|
||||
dx += ((Train *)u)->tcache.cached_veh_length;
|
||||
u = u->Next();
|
||||
} while (u != NULL && IsArticulatedPart(u) && u->cargo_cap == 0);
|
||||
|
||||
|
@ -1424,7 +1424,7 @@ SpriteID GetEnginePalette(EngineID engine_type, CompanyID company)
|
||||
SpriteID GetVehiclePalette(const Vehicle *v)
|
||||
{
|
||||
if (v->type == VEH_TRAIN) {
|
||||
return GetEngineColourMap(v->engine_type, v->owner, v->u.rail.first_engine, v);
|
||||
return GetEngineColourMap(v->engine_type, v->owner, ((Train *)v)->tcache.first_engine, v);
|
||||
} else if (v->type == VEH_ROAD) {
|
||||
return GetEngineColourMap(v->engine_type, v->owner, ((RoadVehicle *)v)->first_engine, v);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include "vehicle_type.h"
|
||||
#include "track_type.h"
|
||||
#include "rail_type.h"
|
||||
#include "cargo_type.h"
|
||||
#include "direction_type.h"
|
||||
#include "gfx_type.h"
|
||||
@ -44,39 +43,6 @@ enum VehicleFlags {
|
||||
VF_AUTOFILL_PRES_WAIT_TIME, ///< Whether non-destructive auto-fill should preserve waiting times
|
||||
};
|
||||
|
||||
struct VehicleRail {
|
||||
/* Cached wagon override spritegroup */
|
||||
const struct SpriteGroup *cached_override;
|
||||
|
||||
uint16 last_speed; // NOSAVE: only used in UI
|
||||
|
||||
/* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */
|
||||
uint32 cached_power; ///< total power of the consist.
|
||||
uint16 cached_max_speed; ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist)
|
||||
uint16 cached_total_length; ///< Length of the whole train, valid only for first engine.
|
||||
uint8 cached_veh_length; ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback
|
||||
bool cached_tilt; ///< train can tilt; feature provides a bonus in curves
|
||||
|
||||
/* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */
|
||||
uint32 cached_weight; ///< total weight of the consist.
|
||||
uint32 cached_veh_weight; ///< weight of the vehicle.
|
||||
uint32 cached_max_te; ///< max tractive effort of consist
|
||||
|
||||
/**
|
||||
* Position/type of visual effect.
|
||||
* bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear)
|
||||
* bit 4 - 5 = type of effect. (0 = default for engine class, 1 = steam, 2 = diesel, 3 = electric)
|
||||
* bit 6 = disable visual effect.
|
||||
* bit 7 = disable powered wagons.
|
||||
*/
|
||||
byte cached_vis_effect;
|
||||
byte user_def_data;
|
||||
|
||||
/* NOSAVE: for wagon override - id of the first engine in train
|
||||
* 0xffff == not in train */
|
||||
EngineID first_engine;
|
||||
};
|
||||
|
||||
typedef Pool<Vehicle, VehicleID, 512, 64000> VehiclePool;
|
||||
extern VehiclePool _vehicle_pool;
|
||||
|
||||
@ -204,10 +170,6 @@ public:
|
||||
|
||||
byte subtype; ///< subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes)
|
||||
|
||||
union {
|
||||
VehicleRail rail;
|
||||
} u;
|
||||
|
||||
/* cached oftenly queried NewGRF values */
|
||||
uint8 cache_valid; ///< Whether the caches are valid
|
||||
uint32 cached_var40; ///< Cache for NewGRF var 40
|
||||
|
@ -67,7 +67,7 @@ CommandCost CmdStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN:
|
||||
if (v->vehstatus & VS_STOPPED && v->u.rail.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
|
||||
if (v->vehstatus & VS_STOPPED && ((Train *)v)->tcache.cached_power == 0) return_cmd_error(STR_TRAIN_START_NO_CATENARY);
|
||||
break;
|
||||
|
||||
case VEH_SHIP:
|
||||
|
@ -603,7 +603,7 @@ static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle *
|
||||
{
|
||||
int r = 0;
|
||||
if ((*a)->type == VEH_TRAIN && (*b)->type == VEH_TRAIN) {
|
||||
r = (*a)->u.rail.cached_max_speed - (*b)->u.rail.cached_max_speed;
|
||||
r = ((const Train *)(*a))->tcache.cached_max_speed - ((const Train *)(*b))->tcache.cached_max_speed;
|
||||
} else {
|
||||
r = (*a)->max_speed - (*b)->max_speed;
|
||||
}
|
||||
@ -636,7 +636,7 @@ static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * c
|
||||
int r = 0;
|
||||
switch ((*a)->type) {
|
||||
case VEH_TRAIN:
|
||||
r = (*a)->u.rail.cached_total_length - (*b)->u.rail.cached_total_length;
|
||||
r = ((const Train *)(*a))->tcache.cached_total_length - ((const Train *)(*b))->tcache.cached_total_length;
|
||||
break;
|
||||
|
||||
case VEH_ROAD: {
|
||||
@ -1466,9 +1466,9 @@ struct VehicleDetailsWindow : Window {
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN:
|
||||
SetDParam(2, v->GetDisplayMaxSpeed());
|
||||
SetDParam(1, v->u.rail.cached_power);
|
||||
SetDParam(0, v->u.rail.cached_weight);
|
||||
SetDParam(3, v->u.rail.cached_max_te / 1000);
|
||||
SetDParam(1, ((Train *)v)->tcache.cached_power);
|
||||
SetDParam(0, ((Train *)v)->tcache.cached_weight);
|
||||
SetDParam(3, ((Train *)v)->tcache.cached_max_te / 1000);
|
||||
DrawString(2, this->width - 2, 25, (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && ((Train *)v)->railtype != RAILTYPE_MAGLEV) ?
|
||||
STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
|
||||
STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED);
|
||||
@ -1937,7 +1937,7 @@ struct VehicleViewWindow : Window {
|
||||
} else if (v->vehstatus & VS_STOPPED) {
|
||||
if (v->type == VEH_TRAIN) {
|
||||
if (v->cur_speed == 0) {
|
||||
if (v->u.rail.cached_power == 0) {
|
||||
if (((Train *)v)->tcache.cached_power == 0) {
|
||||
str = STR_TRAIN_NO_POWER;
|
||||
} else {
|
||||
str = STR_VEHICLE_STATUS_STOPPED;
|
||||
|
@ -247,8 +247,8 @@ public:
|
||||
const Vehicle *v = Yapf().GetVehicle();
|
||||
assert(v != NULL);
|
||||
assert(v->type == VEH_TRAIN);
|
||||
assert(v->u.rail.cached_total_length != 0);
|
||||
int missing_platform_length = (v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE - platform_length;
|
||||
assert(((Train *)v)->tcache.cached_total_length != 0);
|
||||
int missing_platform_length = (((Train *)v)->tcache.cached_total_length + TILE_SIZE - 1) / TILE_SIZE - platform_length;
|
||||
if (missing_platform_length < 0) {
|
||||
/* apply penalty for longer platform than needed */
|
||||
cost += Yapf().PfGetSettings().rail_longer_platform_penalty + Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
|
||||
|
Loading…
Reference in New Issue
Block a user