Merge branch 'master' into infrastructure_sharing
Conflicts: src/aircraft_cmd.cpp src/economy.cpp src/lang/english.txt src/order_gui.cpp src/roadveh_cmd.cpp src/saveload/saveload.cpp src/settings.cpp src/settings_gui.cpp src/train_cmd.cpp
This commit is contained in:
@@ -35,10 +35,13 @@
|
||||
#include "infrastructure_func.h"
|
||||
#include "order_backup.h"
|
||||
#include "zoom_func.h"
|
||||
#include "newgrf_debug.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
#include "table/train_cmd.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool force_res, bool *got_reservation, bool mark_stuck);
|
||||
static bool TrainCheckIfLineEnds(Train *v, bool reverse = true);
|
||||
bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // Also used in vehicle_sl.cpp.
|
||||
@@ -49,6 +52,11 @@ static void CheckNextTrainTile(Train *v);
|
||||
static const byte _vehicle_initial_x_fract[4] = {10, 8, 4, 8};
|
||||
static const byte _vehicle_initial_y_fract[4] = { 8, 4, 8, 10};
|
||||
|
||||
template <>
|
||||
bool IsValidImageIndex<VEH_TRAIN>(uint8 image_index)
|
||||
{
|
||||
return image_index < lengthof(_engine_sprite_base);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the side in which the train will leave the tile
|
||||
@@ -117,9 +125,9 @@ void CheckTrainsLengths()
|
||||
* Recalculates the cached stuff of a train. Should be called each time a vehicle is added
|
||||
* to/removed from the chain, and when the game is loaded.
|
||||
* Note: this needs to be called too for 'wagon chains' (in the depot, without an engine)
|
||||
* @param same_length should length of vehicles stay the same?
|
||||
* @param allowed_changes Stuff that is allowed to change.
|
||||
*/
|
||||
void Train::ConsistChanged(bool same_length)
|
||||
void Train::ConsistChanged(ConsistChangeFlags allowed_changes)
|
||||
{
|
||||
uint16 max_speed = UINT16_MAX;
|
||||
|
||||
@@ -201,7 +209,16 @@ void Train::ConsistChanged(bool same_length)
|
||||
}
|
||||
}
|
||||
|
||||
u->cargo_cap = e_u->DetermineCapacity(u);
|
||||
uint16 new_cap = e_u->DetermineCapacity(u);
|
||||
if (allowed_changes & CCF_CAPACITY) {
|
||||
/* Update vehicle capacity. */
|
||||
if (u->cargo_cap > new_cap) u->cargo.Truncate(new_cap);
|
||||
u->refit_cap = min(new_cap, u->refit_cap);
|
||||
u->cargo_cap = new_cap;
|
||||
} else {
|
||||
/* Verify capacity hasn't changed. */
|
||||
if (new_cap != u->cargo_cap) ShowNewGrfVehicleError(u->engine_type, STR_NEWGRF_BROKEN, STR_NEWGRF_BROKEN_CAPACITY, GBUG_VEH_CAPACITY, true);
|
||||
}
|
||||
u->vcache.cached_cargo_age_period = GetVehicleProperty(u, PROP_TRAIN_CARGO_AGE_PERIOD, e_u->info.cargo_age_period);
|
||||
|
||||
/* check the vehicle length (callback) */
|
||||
@@ -209,21 +226,24 @@ void Train::ConsistChanged(bool same_length)
|
||||
if (e_u->GetGRF() != NULL && e_u->GetGRF()->grf_version >= 8) {
|
||||
/* Use callback 36 */
|
||||
veh_len = GetVehicleProperty(u, PROP_TRAIN_SHORTEN_FACTOR, CALLBACK_FAILED);
|
||||
|
||||
if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) {
|
||||
ErrorUnknownCallbackResult(e_u->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len);
|
||||
}
|
||||
} else if (HasBit(e_u->info.callback_mask, CBM_VEHICLE_LENGTH)) {
|
||||
/* Use callback 11 */
|
||||
veh_len = GetVehicleCallback(CBID_VEHICLE_LENGTH, 0, 0, u->engine_type, u);
|
||||
}
|
||||
if (veh_len != CALLBACK_FAILED && veh_len >= VEHICLE_LENGTH) {
|
||||
ErrorUnknownCallbackResult(e_u->GetGRFID(), CBID_VEHICLE_LENGTH, veh_len);
|
||||
}
|
||||
if (veh_len == CALLBACK_FAILED) veh_len = rvi_u->shorten_factor;
|
||||
veh_len = VEHICLE_LENGTH - Clamp(veh_len, 0, VEHICLE_LENGTH - 1);
|
||||
|
||||
/* verify length hasn't changed */
|
||||
if (same_length && veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
|
||||
|
||||
/* update vehicle length? */
|
||||
if (!same_length) u->gcache.cached_veh_length = veh_len;
|
||||
if (allowed_changes & CCF_LENGTH) {
|
||||
/* Update vehicle length. */
|
||||
u->gcache.cached_veh_length = veh_len;
|
||||
} else {
|
||||
/* Verify length hasn't changed. */
|
||||
if (veh_len != u->gcache.cached_veh_length) VehicleLengthChanged(u);
|
||||
}
|
||||
|
||||
this->gcache.cached_total_length += u->gcache.cached_veh_length;
|
||||
this->InvalidateNewGRFCache();
|
||||
@@ -241,7 +261,9 @@ void Train::ConsistChanged(bool same_length)
|
||||
if (this->IsFrontEngine()) {
|
||||
this->UpdateAcceleration();
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, this->index);
|
||||
InvalidateWindowData(WC_VEHICLE_REFIT, this->index);
|
||||
InvalidateWindowData(WC_VEHICLE_REFIT, this->index, VIWD_CONSIST_CHANGED);
|
||||
InvalidateWindowData(WC_VEHICLE_ORDERS, this->index, VIWD_CONSIST_CHANGED);
|
||||
InvalidateNewGRFInspectWindow(GSF_TRAINS, this->index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,10 +392,11 @@ int Train::GetCurveSpeedLimit() const
|
||||
*/
|
||||
int Train::GetCurrentMaxSpeed() const
|
||||
{
|
||||
int max_speed = this->tcache.cached_max_curve_speed;
|
||||
assert(max_speed == this->GetCurveSpeedLimit());
|
||||
int max_speed = _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL ?
|
||||
this->gcache.cached_max_track_speed :
|
||||
this->tcache.cached_max_curve_speed;
|
||||
|
||||
if (IsRailStationTile(this->tile)) {
|
||||
if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && IsRailStationTile(this->tile)) {
|
||||
StationID sid = GetStationIndex(this->tile);
|
||||
if (this->current_order.ShouldStopAtStation(this, sid)) {
|
||||
int station_ahead;
|
||||
@@ -399,20 +422,25 @@ int Train::GetCurrentMaxSpeed() const
|
||||
}
|
||||
|
||||
for (const Train *u = this; u != NULL; u = u->Next()) {
|
||||
if (u->track == TRACK_BIT_DEPOT) {
|
||||
if (_settings_game.vehicle.train_acceleration_model == AM_REALISTIC && u->track == TRACK_BIT_DEPOT) {
|
||||
max_speed = min(max_speed, 61);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Vehicle is on the middle part of a bridge. */
|
||||
if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
|
||||
max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
|
||||
}
|
||||
}
|
||||
|
||||
max_speed = min(max_speed, this->current_order.max_speed);
|
||||
max_speed = min(max_speed, this->current_order.GetMaxSpeed());
|
||||
return min(max_speed, this->gcache.cached_max_track_speed);
|
||||
}
|
||||
|
||||
/** Update acceleration of the train from the cached power and weight. */
|
||||
void Train::UpdateAcceleration()
|
||||
{
|
||||
assert(this->IsFrontEngine());
|
||||
assert(this->IsFrontEngine() || this->IsFreeWagon());
|
||||
|
||||
uint power = this->gcache.cached_power;
|
||||
uint weight = this->gcache.cached_weight;
|
||||
@@ -437,14 +465,15 @@ int Train::GetDisplayImageWidth(Point *offset) const
|
||||
}
|
||||
|
||||
if (offset != NULL) {
|
||||
offset->x = reference_width / 2;
|
||||
offset->y = vehicle_pitch;
|
||||
offset->x = ScaleGUITrad(reference_width) / 2;
|
||||
offset->y = ScaleGUITrad(vehicle_pitch);
|
||||
}
|
||||
return this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH;
|
||||
return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH);
|
||||
}
|
||||
|
||||
static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction)
|
||||
{
|
||||
assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
|
||||
return ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum];
|
||||
}
|
||||
|
||||
@@ -468,9 +497,10 @@ SpriteID Train::GetImage(Direction direction, EngineImageType image_type) const
|
||||
spritenum = this->GetEngine()->original_image_index;
|
||||
}
|
||||
|
||||
assert(IsValidImageIndex<VEH_TRAIN>(spritenum));
|
||||
sprite = GetDefaultTrainSprite(spritenum, direction);
|
||||
|
||||
if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
|
||||
if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum];
|
||||
|
||||
return sprite;
|
||||
}
|
||||
@@ -485,7 +515,7 @@ static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImage
|
||||
SpriteID sprite = GetCustomVehicleIcon(engine, dir, image_type);
|
||||
if (sprite != 0) {
|
||||
if (e->GetGRF() != NULL) {
|
||||
y += e->GetGRF()->traininfo_vehicle_pitch;
|
||||
y += ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch);
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
@@ -509,18 +539,55 @@ void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engin
|
||||
const Sprite *real_spritef = GetSprite(spritef, ST_NORMAL);
|
||||
const Sprite *real_spriter = GetSprite(spriter, ST_NORMAL);
|
||||
|
||||
preferred_x = Clamp(preferred_x, left - UnScaleByZoom(real_spritef->x_offs, ZOOM_LVL_GUI) + 14, right - UnScaleByZoom(real_spriter->width, ZOOM_LVL_GUI) - UnScaleByZoom(real_spriter->x_offs, ZOOM_LVL_GUI) - 15);
|
||||
preferred_x = Clamp(preferred_x,
|
||||
left - UnScaleGUI(real_spritef->x_offs) + ScaleGUITrad(14),
|
||||
right - UnScaleGUI(real_spriter->width) - UnScaleGUI(real_spriter->x_offs) - ScaleGUITrad(15));
|
||||
|
||||
DrawSprite(spritef, pal, preferred_x - 14, yf);
|
||||
DrawSprite(spriter, pal, preferred_x + 15, yr);
|
||||
DrawSprite(spritef, pal, preferred_x - ScaleGUITrad(14), yf);
|
||||
DrawSprite(spriter, pal, preferred_x + ScaleGUITrad(15), yr);
|
||||
} else {
|
||||
SpriteID sprite = GetRailIcon(engine, false, y, image_type);
|
||||
const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
|
||||
preferred_x = Clamp(preferred_x, left - UnScaleByZoom(real_sprite->x_offs, ZOOM_LVL_GUI), right - UnScaleByZoom(real_sprite->width, ZOOM_LVL_GUI) - UnScaleByZoom(real_sprite->x_offs, ZOOM_LVL_GUI));
|
||||
preferred_x = Clamp(preferred_x,
|
||||
left - UnScaleGUI(real_sprite->x_offs),
|
||||
right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs));
|
||||
DrawSprite(sprite, pal, preferred_x, y);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of the sprite of a train sprite heading west, or both heads (used for lists).
|
||||
* @param engine The engine to get the sprite from.
|
||||
* @param[out] width The width of the sprite.
|
||||
* @param[out] height The height of the sprite.
|
||||
* @param[out] xoffs Number of pixels to shift the sprite to the right.
|
||||
* @param[out] yoffs Number of pixels to shift the sprite downwards.
|
||||
* @param image_type Context the sprite is used in.
|
||||
*/
|
||||
void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
|
||||
{
|
||||
int y = 0;
|
||||
|
||||
SpriteID sprite = GetRailIcon(engine, false, y, image_type);
|
||||
const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL);
|
||||
|
||||
width = UnScaleGUI(real_sprite->width);
|
||||
height = UnScaleGUI(real_sprite->height);
|
||||
xoffs = UnScaleGUI(real_sprite->x_offs);
|
||||
yoffs = UnScaleGUI(real_sprite->y_offs);
|
||||
|
||||
if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) {
|
||||
sprite = GetRailIcon(engine, true, y, image_type);
|
||||
real_sprite = GetSprite(sprite, ST_NORMAL);
|
||||
|
||||
/* Calculate values relative to an imaginary center between the two sprites. */
|
||||
width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(real_sprite->width) + UnScaleGUI(real_sprite->x_offs) - xoffs;
|
||||
height = max<uint>(height, UnScaleGUI(real_sprite->height));
|
||||
xoffs = xoffs - ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2;
|
||||
yoffs = min(yoffs, UnScaleGUI(real_sprite->y_offs));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a railroad wagon.
|
||||
* @param tile tile of the depot where rail-vehicle is built.
|
||||
@@ -566,6 +633,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
|
||||
|
||||
v->cargo_type = e->GetDefaultCargoType();
|
||||
v->cargo_cap = rvi->capacity;
|
||||
v->refit_cap = 0;
|
||||
|
||||
v->railtype = rvi->railtype;
|
||||
|
||||
@@ -579,8 +647,8 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const
|
||||
|
||||
_new_vehicle_id = v->index;
|
||||
|
||||
VehicleUpdatePosition(v);
|
||||
v->First()->ConsistChanged(false);
|
||||
v->UpdatePosition();
|
||||
v->First()->ConsistChanged(CCF_ARRANGE);
|
||||
UpdateTrainGroupID(v->First());
|
||||
|
||||
CheckConsistencyOfArticulatedVehicle(v);
|
||||
@@ -633,6 +701,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
|
||||
u->cargo_type = v->cargo_type;
|
||||
u->cargo_subtype = v->cargo_subtype;
|
||||
u->cargo_cap = v->cargo_cap;
|
||||
u->refit_cap = v->refit_cap;
|
||||
u->railtype = v->railtype;
|
||||
u->engine_type = v->engine_type;
|
||||
u->build_year = v->build_year;
|
||||
@@ -641,7 +710,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v)
|
||||
v->SetMultiheaded();
|
||||
u->SetMultiheaded();
|
||||
v->SetNext(u);
|
||||
VehicleUpdatePosition(u);
|
||||
u->UpdatePosition();
|
||||
|
||||
/* Now we need to link the front and rear engines together */
|
||||
v->other_multiheaded_part = u;
|
||||
@@ -685,7 +754,9 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
|
||||
v->spritenum = rvi->image_index;
|
||||
v->cargo_type = e->GetDefaultCargoType();
|
||||
v->cargo_cap = rvi->capacity;
|
||||
v->refit_cap = 0;
|
||||
v->last_station_visited = INVALID_STATION;
|
||||
v->last_loading_station = INVALID_STATION;
|
||||
|
||||
v->engine_type = e->index;
|
||||
v->gcache.first_engine = INVALID_ENGINE; // needs to be set before first callback
|
||||
@@ -697,20 +768,21 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
|
||||
v->railtype = rvi->railtype;
|
||||
_new_vehicle_id = v->index;
|
||||
|
||||
v->service_interval = Company::Get(_current_company)->settings.vehicle.servint_trains;
|
||||
v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains);
|
||||
v->date_of_last_service = _date;
|
||||
v->build_year = _cur_year;
|
||||
v->cur_image = SPR_IMG_QUERY;
|
||||
v->random_bits = VehicleRandomBits();
|
||||
|
||||
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
|
||||
v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
|
||||
|
||||
v->group_id = DEFAULT_GROUP;
|
||||
|
||||
v->SetFrontEngine();
|
||||
v->SetEngine();
|
||||
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
|
||||
if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
|
||||
AddRearEngineToMultiheadedTrain(v);
|
||||
@@ -718,7 +790,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
|
||||
AddArticulatedParts(v);
|
||||
}
|
||||
|
||||
v->ConsistChanged(false);
|
||||
v->ConsistChanged(CCF_ARRANGE);
|
||||
UpdateTrainGroupID(v);
|
||||
|
||||
if (!HasBit(data, 0) && !(flags & DC_AUTOREPLACE)) { // check if the cars should be added to the new vehicle
|
||||
@@ -731,34 +803,6 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the whole consist the in a depot?
|
||||
* @return \c true iff all vehicles of the train are in a depot.
|
||||
*/
|
||||
bool Train::IsInDepot() const
|
||||
{
|
||||
/* Is the front engine stationary in the depot? */
|
||||
if (!IsRailDepotTile(this->tile) || this->cur_speed != 0) return false;
|
||||
|
||||
/* Check whether the rest is also already trying to enter the depot. */
|
||||
for (const Train *v = this; v != NULL; v = v->Next()) {
|
||||
if (v->track != TRACK_BIT_DEPOT || v->tile != this->tile) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the train stopped in a depot?
|
||||
* @return True if the train is stopped in a depot, else false.
|
||||
*/
|
||||
bool Train::IsStoppedInDepot() const
|
||||
{
|
||||
/* Are we stopped? Of course wagons don't really care... */
|
||||
if (this->IsFrontEngine() && !(this->vehstatus & VS_STOPPED)) return false;
|
||||
return this->IsInDepot();
|
||||
}
|
||||
|
||||
static Train *FindGoodVehiclePos(const Train *src)
|
||||
{
|
||||
EngineID eng = src->engine_type;
|
||||
@@ -1092,14 +1136,14 @@ static void NormaliseTrainHead(Train *head)
|
||||
if (head == NULL) return;
|
||||
|
||||
/* Tell the 'world' the train changed. */
|
||||
head->ConsistChanged(false);
|
||||
head->ConsistChanged(CCF_ARRANGE);
|
||||
UpdateTrainGroupID(head);
|
||||
|
||||
/* Not a front engine, i.e. a free wagon chain. No need to do more. */
|
||||
if (!head->IsFrontEngine()) return;
|
||||
|
||||
/* Update the refit button and window */
|
||||
InvalidateWindowData(WC_VEHICLE_REFIT, head->index);
|
||||
InvalidateWindowData(WC_VEHICLE_REFIT, head->index, VIWD_CONSIST_CHANGED);
|
||||
SetWindowWidgetDirty(WC_VEHICLE_VIEW, head->index, WID_VV_REFIT);
|
||||
|
||||
/* If we don't have a unit number yet, set one. */
|
||||
@@ -1198,8 +1242,10 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
Train *original_src_head = src_head;
|
||||
Train *original_dst_head = (dst_head == src_head ? NULL : dst_head);
|
||||
|
||||
/* We want this information from before the rearrangement, but execute this after the validation. */
|
||||
bool original_src_head_front_engine = original_src_head != NULL && original_src_head->IsFrontEngine();
|
||||
/* We want this information from before the rearrangement, but execute this after the validation.
|
||||
* original_src_head can't be NULL; src is by definition != NULL, so src_head can't be NULL as
|
||||
* src->GetFirst() always yields non-NULL, so eventually original_src_head != NULL as well. */
|
||||
bool original_src_head_front_engine = original_src_head->IsFrontEngine();
|
||||
bool original_dst_head_front_engine = original_dst_head != NULL && original_dst_head->IsFrontEngine();
|
||||
|
||||
/* (Re)arrange the trains in the wanted arrangement. */
|
||||
@@ -1255,6 +1301,7 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
DeleteWindowById(WC_VEHICLE_REFIT, src->index);
|
||||
DeleteWindowById(WC_VEHICLE_DETAILS, src->index);
|
||||
DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index);
|
||||
DeleteNewGRFInspectWindow(GSF_TRAINS, src->index);
|
||||
SetWindowDirty(WC_COMPANY, _current_company);
|
||||
|
||||
/* Delete orders, group stuff and the unit number as we're not the
|
||||
@@ -1284,6 +1331,9 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
CheckCargoCapacity(dst_head);
|
||||
}
|
||||
|
||||
if (src_head != NULL) src_head->First()->MarkDirty();
|
||||
if (dst_head != NULL) dst_head->First()->MarkDirty();
|
||||
|
||||
/* We are undoubtedly changing something in the depot and train list. */
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
|
||||
InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
|
||||
@@ -1309,9 +1359,6 @@ CommandCost CmdMoveRailVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
*/
|
||||
CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint32 user)
|
||||
{
|
||||
/* Check if we deleted a vehicle window */
|
||||
Window *w = NULL;
|
||||
|
||||
/* Sell a chain of vehicles or not? */
|
||||
bool sell_chain = HasBit(data, 0);
|
||||
|
||||
@@ -1362,9 +1409,6 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3
|
||||
/* Copy other important data from the front engine */
|
||||
new_head->CopyVehicleConfigAndStatistics(first);
|
||||
GroupStatistics::CountVehicle(new_head, 1); // after copying over the profit
|
||||
|
||||
/* If we deleted a window then open a new one for the 'new' train */
|
||||
if (IsLocalCompany() && w != NULL) ShowVehicleViewWindow(new_head);
|
||||
} else if (v->IsPrimaryVehicle() && data & (MAKE_ORDER_BACKUP_FLAG >> 20)) {
|
||||
OrderBackup::Backup(v, user);
|
||||
}
|
||||
@@ -1400,7 +1444,7 @@ void Train::UpdateDeltaXY(Direction direction)
|
||||
if (!IsDiagonalDirection(direction)) {
|
||||
static const int _sign_table[] =
|
||||
{
|
||||
// x, y
|
||||
/* x, y */
|
||||
-1, -1, // DIR_N
|
||||
-1, 1, // DIR_E
|
||||
1, 1, // DIR_S
|
||||
@@ -1526,14 +1570,14 @@ static void UpdateStatusAfterSwap(Train *v)
|
||||
/* We have just left the wormhole, possibly set the
|
||||
* "goingdown" bit. UpdateInclination() can be used
|
||||
* because we are at the border of the tile. */
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
v->UpdateInclination(true, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
|
||||
@@ -1649,7 +1693,7 @@ void UpdateLevelCrossing(TileIndex tile, bool sound)
|
||||
|
||||
if (new_state != IsCrossingBarred(tile)) {
|
||||
if (new_state && sound) {
|
||||
SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
}
|
||||
SetCrossingBarred(tile, new_state);
|
||||
MarkTileDirtyByTile(tile);
|
||||
@@ -1666,7 +1710,7 @@ static inline void MaybeBarCrossingWithSound(TileIndex tile)
|
||||
{
|
||||
if (!IsCrossingBarred(tile)) {
|
||||
BarCrossing(tile);
|
||||
SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
if (_settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, tile);
|
||||
MarkTileDirtyByTile(tile);
|
||||
}
|
||||
}
|
||||
@@ -1796,7 +1840,7 @@ void ReverseTrainDirection(Train *v)
|
||||
ClrBit(v->flags, VRF_REVERSING);
|
||||
|
||||
/* recalculate cached data */
|
||||
v->ConsistChanged(true);
|
||||
v->ConsistChanged(CCF_TRACK);
|
||||
|
||||
/* update all images */
|
||||
for (Train *u = v; u != NULL; u = u->Next()) u->UpdateViewport(false, false);
|
||||
@@ -1880,7 +1924,7 @@ CommandCost CmdReverseTrainDirection(TileIndex tile, DoCommandFlag flags, uint32
|
||||
if (flags & DC_EXEC) {
|
||||
ToggleBit(v->flags, VRF_REVERSE_DIRECTION);
|
||||
|
||||
front->ConsistChanged(false);
|
||||
front->ConsistChanged(CCF_ARRANGE);
|
||||
SetWindowDirty(WC_VEHICLE_DEPOT, front->tile);
|
||||
SetWindowDirty(WC_VEHICLE_DETAILS, front->index);
|
||||
SetWindowDirty(WC_VEHICLE_VIEW, front->index);
|
||||
@@ -1933,6 +1977,8 @@ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
Train *t = Train::GetIfValid(p1);
|
||||
if (t == NULL) return CMD_ERROR;
|
||||
|
||||
if (!t->IsPrimaryVehicle()) return CMD_ERROR;
|
||||
|
||||
CommandCost ret = CheckVehicleControlAllowed(t);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
@@ -1943,7 +1989,7 @@ CommandCost CmdForceTrainProceed(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
* to proceed to the next signal. In the other cases we
|
||||
* would like to pass the signal at danger and run till the
|
||||
* next signal we encounter. */
|
||||
t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsInDepot() ? TFP_STUCK : TFP_SIGNAL;
|
||||
t->force_proceed = t->force_proceed == TFP_SIGNAL ? TFP_NONE : HasBit(t->flags, VRF_TRAIN_STUCK) || t->IsChainInDepot() ? TFP_STUCK : TFP_SIGNAL;
|
||||
SetWindowDirty(WC_VEHICLE_VIEW, t->index);
|
||||
}
|
||||
|
||||
@@ -2142,7 +2188,7 @@ static bool CheckTrainStayInDepot(Train *v)
|
||||
v->cur_speed = 0;
|
||||
|
||||
v->UpdateViewport(true, true);
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner);
|
||||
v->UpdateAcceleration();
|
||||
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
|
||||
@@ -2171,8 +2217,12 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
|
||||
SetTunnelBridgeReservation(end, false);
|
||||
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
MarkTileDirtyByTile(tile);
|
||||
MarkTileDirtyByTile(end);
|
||||
if (IsBridge(tile)) {
|
||||
MarkBridgeDirty(tile);
|
||||
} else {
|
||||
MarkTileDirtyByTile(tile);
|
||||
MarkTileDirtyByTile(end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2741,7 +2791,8 @@ void Train::MarkDirty()
|
||||
{
|
||||
Train *v = this;
|
||||
do {
|
||||
v->UpdateViewport(false, false);
|
||||
v->colourmap = PAL_NONE;
|
||||
v->UpdateViewport(true, false);
|
||||
} while ((v = v->Next()) != NULL);
|
||||
|
||||
/* need to update acceleration and cached values since the goods on the train changed. */
|
||||
@@ -2761,7 +2812,7 @@ int Train::UpdateSpeed()
|
||||
switch (_settings_game.vehicle.train_acceleration_model) {
|
||||
default: NOT_REACHED();
|
||||
case AM_ORIGINAL:
|
||||
return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, min(this->gcache.cached_max_track_speed, this->current_order.max_speed));
|
||||
return this->DoUpdateSpeed(this->acceleration * (this->GetAccelerationStatus() == AS_BRAKE ? -4 : 2), 0, this->GetCurrentMaxSpeed());
|
||||
|
||||
case AM_REALISTIC:
|
||||
return this->DoUpdateSpeed(this->GetAcceleration(), this->GetAccelerationStatus() == AS_BRAKE ? 0 : 2, this->GetCurrentMaxSpeed());
|
||||
@@ -2784,7 +2835,7 @@ static void TrainEnterStation(Train *v, StationID station)
|
||||
SetDParam(0, st->index);
|
||||
AddVehicleNewsItem(
|
||||
STR_NEWS_FIRST_TRAIN_ARRIVAL,
|
||||
v->owner == _local_company ? NS_ARRIVAL_COMPANY : NS_ARRIVAL_OTHER,
|
||||
v->owner == _local_company ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER,
|
||||
v->index,
|
||||
st->index
|
||||
);
|
||||
@@ -2797,6 +2848,7 @@ static void TrainEnterStation(Train *v, StationID station)
|
||||
|
||||
v->BeginLoading();
|
||||
|
||||
TriggerStationRandomisation(st, v->tile, SRT_TRAIN_ARRIVES);
|
||||
TriggerStationAnimation(st, v->tile, SAT_TRAIN_ARRIVES);
|
||||
}
|
||||
|
||||
@@ -3018,13 +3070,10 @@ static bool CheckTrainCollision(Train *v)
|
||||
if (tcc.num == 0) return false;
|
||||
|
||||
SetDParam(0, tcc.num);
|
||||
AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH,
|
||||
NS_ACCIDENT,
|
||||
v->index
|
||||
);
|
||||
AddVehicleNewsItem(STR_NEWS_TRAIN_CRASH, NT_ACCIDENT, v->index);
|
||||
|
||||
ModifyStationRatingAround(v->tile, v->owner, -160, 30);
|
||||
SndPlayVehicleFx(SND_13_BIG_CRASH, v);
|
||||
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_13_BIG_CRASH, v);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3126,8 +3175,9 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
* this to one, then if we reach the next signal it is
|
||||
* decreased to zero and we won't pass that new signal. */
|
||||
Trackdir dir = FindFirstTrackdir(trackdirbits);
|
||||
if (GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS ||
|
||||
!HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(dir))) {
|
||||
if (HasSignalOnTrackdir(gp.new_tile, dir) ||
|
||||
(HasSignalOnTrackdir(gp.new_tile, ReverseTrackdir(dir)) &&
|
||||
GetSignalType(gp.new_tile, TrackdirToTrack(dir)) != SIGTYPE_PBS)) {
|
||||
/* However, we do not want to be stopped by PBS signals
|
||||
* entered via the back. */
|
||||
v->force_proceed = (v->force_proceed == TFP_SIGNAL) ? TFP_STUCK : TFP_NONE;
|
||||
@@ -3174,7 +3224,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
goto reverse_train_direction;
|
||||
} else {
|
||||
TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track));
|
||||
TryReserveRailTrack(gp.new_tile, TrackBitsToTrack(chosen_track), false);
|
||||
}
|
||||
} else {
|
||||
/* The wagon is active, simply follow the prev vehicle. */
|
||||
@@ -3241,7 +3291,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
v->tile = gp.new_tile;
|
||||
|
||||
if (GetTileRailType(gp.new_tile) != GetTileRailType(gp.old_tile)) {
|
||||
v->First()->ConsistChanged(true);
|
||||
v->First()->ConsistChanged(CCF_TRACK);
|
||||
}
|
||||
|
||||
v->track = chosen_track;
|
||||
@@ -3267,7 +3317,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
/* If we are approaching a crossing that is reserved, play the sound now. */
|
||||
TileIndex crossing = TrainApproachingCrossingTile(v);
|
||||
if (crossing != INVALID_TILE && HasCrossingReservation(crossing)) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
|
||||
if (crossing != INVALID_TILE && HasCrossingReservation(crossing) && _settings_client.sound.ambient) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
|
||||
|
||||
/* Always try to extend the reservation when entering a tile. */
|
||||
CheckNextTrainTile(v);
|
||||
@@ -3279,14 +3329,6 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* In a tunnel or on a bridge
|
||||
* - for tunnels, only the part when the vehicle is not visible (part of enter/exit tile too)
|
||||
* - for bridges, only the middle part - without the bridge heads */
|
||||
if (!(v->vehstatus & VS_HIDDEN)) {
|
||||
Train *first = v->First();
|
||||
first->cur_speed = min(first->cur_speed, GetBridgeSpec(GetBridgeType(v->tile))->speed);
|
||||
}
|
||||
|
||||
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
||||
/* Perform look-ahead on tunnel exit. */
|
||||
if (v->IsFrontEngine()) {
|
||||
@@ -3301,8 +3343,8 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
} else {
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
VehicleUpdatePosition(v);
|
||||
if ((v->vehstatus & VS_HIDDEN) == 0) VehicleUpdateViewport(v, true);
|
||||
v->UpdatePosition();
|
||||
if ((v->vehstatus & VS_HIDDEN) == 0) v->Vehicle::UpdateViewport(true);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -3312,7 +3354,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
|
||||
/* update the Z position of the vehicle */
|
||||
int old_z = v->UpdateInclination(gp.new_tile != gp.old_tile, false);
|
||||
@@ -3415,12 +3457,13 @@ static void DeleteLastWagon(Train *v)
|
||||
|
||||
if (first != v) {
|
||||
/* Recalculate cached train properties */
|
||||
first->ConsistChanged(false);
|
||||
first->ConsistChanged(CCF_ARRANGE);
|
||||
/* Update the depot window if the first vehicle is in depot -
|
||||
* if v == first, then it is updated in PreDestructor() */
|
||||
if (first->track == TRACK_BIT_DEPOT) {
|
||||
SetWindowDirty(WC_VEHICLE_DEPOT, first->tile);
|
||||
}
|
||||
v->last_station_visited = first->last_station_visited; // for PreDestructor
|
||||
}
|
||||
|
||||
/* 'v' shouldn't be accessed after it has been deleted */
|
||||
@@ -3481,7 +3524,7 @@ static void ChangeTrainDirRandomly(Train *v)
|
||||
* a bridge, because UpdateInclination() will put the vehicle under
|
||||
* the bridge in that case */
|
||||
if (v->track != TRACK_BIT_WORMHOLE) {
|
||||
VehicleUpdatePosition(v);
|
||||
v->UpdatePosition();
|
||||
v->UpdateInclination(false, false);
|
||||
}
|
||||
}
|
||||
@@ -3770,11 +3813,7 @@ static bool TrainLocoHandler(Train *v, bool mode)
|
||||
/* Show message to player. */
|
||||
if (_settings_client.gui.lost_vehicle_warn && v->owner == _local_company) {
|
||||
SetDParam(0, v->index);
|
||||
AddVehicleNewsItem(
|
||||
STR_NEWS_TRAIN_IS_STUCK,
|
||||
NS_ADVICE,
|
||||
v->index
|
||||
);
|
||||
AddVehicleAdviceNewsItem(STR_NEWS_TRAIN_IS_STUCK, v->index);
|
||||
}
|
||||
v->wait_counter = 0;
|
||||
}
|
||||
@@ -3895,13 +3934,13 @@ bool Train::Tick()
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a train needs serivce, and if so, find a depot or service it.
|
||||
* Check whether a train needs service, and if so, find a depot or service it.
|
||||
* @return v %Train to check.
|
||||
*/
|
||||
static void CheckIfTrainNeedsService(Train *v)
|
||||
{
|
||||
if (Company::Get(v->owner)->settings.vehicle.servint_trains == 0 || !v->NeedsAutomaticServicing()) return;
|
||||
if (v->IsInDepot()) {
|
||||
if (v->IsChainInDepot()) {
|
||||
VehicleServiceInDepot(v);
|
||||
return;
|
||||
}
|
||||
|
Reference in New Issue
Block a user