|
@@ -214,17 +214,16 @@ void CheckTrainsLengths()
|
|
|
* @param same_length should length of vehicles stay the same?
|
|
|
*/
|
|
|
void TrainConsistChanged(Train *v, bool same_length)
|
|
|
{
|
|
|
uint16 max_speed = UINT16_MAX;
|
|
|
|
|
|
assert(v->type == VEH_TRAIN);
|
|
|
assert(IsFrontEngine(v) || IsFreeWagon(v));
|
|
|
assert(v->IsFrontEngine() || IsFreeWagon(v));
|
|
|
|
|
|
const RailVehicleInfo *rvi_v = RailVehInfo(v->engine_type);
|
|
|
EngineID first_engine = IsFrontEngine(v) ? v->engine_type : INVALID_ENGINE;
|
|
|
EngineID first_engine = v->IsFrontEngine() ? v->engine_type : INVALID_ENGINE;
|
|
|
v->tcache.cached_total_length = 0;
|
|
|
v->compatible_railtypes = RAILTYPES_NONE;
|
|
|
|
|
|
bool train_can_tilt = true;
|
|
|
|
|
|
for (Train *u = v; u != NULL; u = u->Next()) {
|
|
@@ -344,13 +343,13 @@ void TrainConsistChanged(Train *v, bool
|
|
|
v->tcache.cached_tilt = train_can_tilt;
|
|
|
v->tcache.cached_max_curve_speed = GetTrainCurveSpeedLimit(v);
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
if (IsFrontEngine(v)) {
|
|
|
if (v->IsFrontEngine()) {
|
|
|
UpdateTrainAcceleration(v);
|
|
|
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
enum AccelType {
|
|
@@ -480,13 +479,13 @@ int GetTrainCurveSpeedLimit(Train *v)
|
|
|
static int GetTrainAcceleration(Train *v, bool mode)
|
|
|
{
|
|
|
int max_speed = v->tcache.cached_max_curve_speed;
|
|
|
assert(max_speed == GetTrainCurveSpeedLimit(v)); // safety check, will be removed later
|
|
|
int speed = v->cur_speed * 10 / 16; // km-ish/h -> mp/h
|
|
|
|
|
|
if (IsTileType(v->tile, MP_STATION) && IsFrontEngine(v)) {
|
|
|
if (IsTileType(v->tile, MP_STATION) && v->IsFrontEngine()) {
|
|
|
StationID sid = GetStationIndex(v->tile);
|
|
|
if (v->current_order.ShouldStopAtStation(v, sid)) {
|
|
|
int station_ahead;
|
|
|
int station_length;
|
|
|
int stop_at = GetTrainStopLocation(sid, v->tile, v, &station_ahead, &station_length);
|
|
|
|
|
@@ -574,13 +573,13 @@ static int GetTrainAcceleration(Train *v
|
|
|
return min(-force - resistance, -10000) / mass;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void UpdateTrainAcceleration(Train *v)
|
|
|
{
|
|
|
assert(IsFrontEngine(v));
|
|
|
assert(v->IsFrontEngine());
|
|
|
|
|
|
v->max_speed = v->tcache.cached_max_speed;
|
|
|
|
|
|
uint power = v->tcache.cached_power;
|
|
|
uint weight = v->tcache.cached_weight;
|
|
|
assert(weight != 0);
|
|
@@ -936,13 +935,13 @@ int CheckTrainInDepot(const Train *v, bo
|
|
|
* in the consist. Exclude articulated parts so that autoreplacing to
|
|
|
* engines with more articulated parts than before works correctly.
|
|
|
*
|
|
|
* Also skip counting rear ends of multiheaded engines */
|
|
|
if (!IsArticulatedPart(v) && !IsRearDualheaded(v)) count++;
|
|
|
if (v->track != TRACK_BIT_DEPOT || v->tile != tile ||
|
|
|
(IsFrontEngine(v) && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
|
|
|
(v->IsFrontEngine() && needs_to_be_stopped && !(v->vehstatus & VS_STOPPED))) {
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return count;
|
|
|
}
|
|
@@ -1030,13 +1029,13 @@ static void AddWagonToConsist(Train *v,
|
|
|
* always call with the front engine
|
|
|
*/
|
|
|
static void NormaliseTrainConsist(Train *v)
|
|
|
{
|
|
|
if (IsFreeWagon(v)) return;
|
|
|
|
|
|
assert(IsFrontEngine(v));
|
|
|
assert(v->IsFrontEngine());
|
|
|
|
|
|
for (; v != NULL; v = GetNextVehicle(v)) {
|
|
|
if (!IsMultiheaded(v) || !IsTrainEngine(v)) continue;
|
|
|
|
|
|
/* make sure that there are no free cars before next engine */
|
|
|
Train *u;
|
|
@@ -1133,34 +1132,34 @@ CommandCost CmdMoveRailVehicle(TileIndex
|
|
|
/* If moving only one vehicle, just count that. */
|
|
|
src_len = 1;
|
|
|
}
|
|
|
|
|
|
if (src_len + dst_len > max_len) {
|
|
|
/* Abort if we're adding too many wagons to a train. */
|
|
|
if (dst_head != NULL && IsFrontEngine(dst_head)) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
|
|
|
if (dst_head != NULL && dst_head->IsFrontEngine()) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
|
|
|
/* Abort if we're making a train on a new row. */
|
|
|
if (dst_head == NULL && IsTrainEngine(src)) return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
|
|
|
}
|
|
|
} else {
|
|
|
/* Abort if we're creating a new train on an existing row. */
|
|
|
if (src_len > max_len && src == src_head && IsTrainEngine(GetNextVehicle(src_head)))
|
|
|
return_cmd_error(STR_ERROR_TRAIN_TOO_LONG);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* moving a loco to a new line?, then we need to assign a unitnumber. */
|
|
|
if (dst == NULL && !IsFrontEngine(src) && IsTrainEngine(src)) {
|
|
|
if (dst == NULL && !src->IsFrontEngine() && IsTrainEngine(src)) {
|
|
|
UnitID unit_num = ((flags & DC_AUTOREPLACE) != 0 ? 0 : GetFreeUnitNumber(VEH_TRAIN));
|
|
|
if (unit_num > _settings_game.vehicle.max_trains)
|
|
|
return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
|
|
|
|
|
|
if (flags & DC_EXEC) src->unitnumber = unit_num;
|
|
|
}
|
|
|
|
|
|
/* When we move the front vehicle, the second vehicle might need a unitnumber */
|
|
|
if (!HasBit(p2, 0) && (IsFreeWagon(src) || (IsFrontEngine(src) && dst == NULL)) && (flags & DC_AUTOREPLACE) == 0) {
|
|
|
if (!HasBit(p2, 0) && (IsFreeWagon(src) || (src->IsFrontEngine() && dst == NULL)) && (flags & DC_AUTOREPLACE) == 0) {
|
|
|
Vehicle *second = GetNextUnit(src);
|
|
|
if (second != NULL && IsTrainEngine(second) && GetFreeUnitNumber(VEH_TRAIN) > _settings_game.vehicle.max_trains) {
|
|
|
return_cmd_error(STR_ERROR_TOO_MANY_VEHICLES_IN_GAME);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1265,13 +1264,13 @@ CommandCost CmdMoveRailVehicle(TileIndex
|
|
|
}
|
|
|
|
|
|
/* do it? */
|
|
|
if (flags & DC_EXEC) {
|
|
|
/* If we move the front Engine and if the second vehicle is not an engine
|
|
|
add the whole vehicle to the DEFAULT_GROUP */
|
|
|
if (IsFrontEngine(src) && !IsDefaultGroupID(src->group_id)) {
|
|
|
if (src->IsFrontEngine() && !IsDefaultGroupID(src->group_id)) {
|
|
|
Vehicle *v = GetNextVehicle(src);
|
|
|
|
|
|
if (v != NULL && IsTrainEngine(v)) {
|
|
|
v->group_id = src->group_id;
|
|
|
src->group_id = DEFAULT_GROUP;
|
|
|
}
|
|
@@ -1298,13 +1297,13 @@ CommandCost CmdMoveRailVehicle(TileIndex
|
|
|
if (dst == NULL) {
|
|
|
/* We make a new line in the depot, so we know already that we invalidate the window data */
|
|
|
InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
|
|
|
|
|
|
/* move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4. */
|
|
|
if (IsTrainEngine(src)) {
|
|
|
if (!IsFrontEngine(src)) {
|
|
|
if (!src->IsFrontEngine()) {
|
|
|
/* setting the type to 0 also involves setting up the orders field. */
|
|
|
SetFrontEngine(src);
|
|
|
assert(src->orders.list == NULL);
|
|
|
|
|
|
/* Decrease the engines number of the src engine_type */
|
|
|
if (!IsDefaultGroupID(src->group_id) && Group::IsValidID(src->group_id)) {
|
|
@@ -1316,24 +1315,24 @@ CommandCost CmdMoveRailVehicle(TileIndex
|
|
|
}
|
|
|
} else {
|
|
|
SetFreeWagon(src);
|
|
|
}
|
|
|
dst_head = src;
|
|
|
} else {
|
|
|
if (IsFrontEngine(src)) {
|
|
|
if (src->IsFrontEngine()) {
|
|
|
/* the vehicle was previously a loco. need to free the order list and delete vehicle windows etc. */
|
|
|
DeleteWindowById(WC_VEHICLE_VIEW, src->index);
|
|
|
DeleteWindowById(WC_VEHICLE_ORDERS, src->index);
|
|
|
DeleteWindowById(WC_VEHICLE_REFIT, src->index);
|
|
|
DeleteWindowById(WC_VEHICLE_DETAILS, src->index);
|
|
|
DeleteWindowById(WC_VEHICLE_TIMETABLE, src->index);
|
|
|
DeleteVehicleOrders(src);
|
|
|
RemoveVehicleFromGroup(src);
|
|
|
}
|
|
|
|
|
|
if (IsFrontEngine(src) || IsFreeWagon(src)) {
|
|
|
if (src->IsFrontEngine() || IsFreeWagon(src)) {
|
|
|
InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
|
|
|
ClearFrontEngine(src);
|
|
|
ClearFreeWagon(src);
|
|
|
src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
|
|
|
}
|
|
|
|
|
@@ -1354,39 +1353,39 @@ CommandCost CmdMoveRailVehicle(TileIndex
|
|
|
AddWagonToConsist(src->other_multiheaded_part, src);
|
|
|
}
|
|
|
|
|
|
/* If there is an engine behind first_engine we moved away, it should become new first_engine
|
|
|
* To do this, CmdMoveRailVehicle must be called once more
|
|
|
* we can't loop forever here because next time we reach this line we will have a front engine */
|
|
|
if (src_head != NULL && !IsFrontEngine(src_head) && IsTrainEngine(src_head)) {
|
|
|
if (src_head != NULL && !src_head->IsFrontEngine() && IsTrainEngine(src_head)) {
|
|
|
/* As in CmdMoveRailVehicle src_head->group_id will be equal to DEFAULT_GROUP
|
|
|
* we need to save the group and reaffect it to src_head */
|
|
|
const GroupID tmp_g = src_head->group_id;
|
|
|
CmdMoveRailVehicle(0, flags, src_head->index | (INVALID_VEHICLE << 16), 1, text);
|
|
|
SetTrainGroupID(src_head, tmp_g);
|
|
|
src_head = NULL; // don't do anything more to this train since the new call will do it
|
|
|
}
|
|
|
|
|
|
if (src_head != NULL) {
|
|
|
NormaliseTrainConsist(src_head);
|
|
|
TrainConsistChanged(src_head, false);
|
|
|
UpdateTrainGroupID(src_head);
|
|
|
if (IsFrontEngine(src_head)) {
|
|
|
if (src_head->IsFrontEngine()) {
|
|
|
/* Update the refit button and window */
|
|
|
InvalidateWindow(WC_VEHICLE_REFIT, src_head->index);
|
|
|
InvalidateWindowWidget(WC_VEHICLE_VIEW, src_head->index, VVW_WIDGET_REFIT_VEH);
|
|
|
}
|
|
|
/* Update the depot window */
|
|
|
InvalidateWindow(WC_VEHICLE_DEPOT, src_head->tile);
|
|
|
}
|
|
|
|
|
|
if (dst_head != NULL) {
|
|
|
NormaliseTrainConsist(dst_head);
|
|
|
TrainConsistChanged(dst_head, false);
|
|
|
UpdateTrainGroupID(dst_head);
|
|
|
if (IsFrontEngine(dst_head)) {
|
|
|
if (dst_head->IsFrontEngine()) {
|
|
|
/* Update the refit button and window */
|
|
|
InvalidateWindowWidget(WC_VEHICLE_VIEW, dst_head->index, VVW_WIDGET_REFIT_VEH);
|
|
|
InvalidateWindow(WC_VEHICLE_REFIT, dst_head->index);
|
|
|
}
|
|
|
/* Update the depot window */
|
|
|
InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
|
|
@@ -1426,13 +1425,13 @@ CommandCost CmdSellRailWagon(TileIndex t
|
|
|
return_cmd_error(STR_ERROR_TRAINS_CAN_ONLY_BE_ALTERED_INSIDE_A_DEPOT);
|
|
|
}
|
|
|
|
|
|
if (IsRearDualheaded(v)) return_cmd_error(STR_ERROR_REAR_ENGINE_FOLLOW_FRONT);
|
|
|
|
|
|
if (flags & DC_EXEC) {
|
|
|
if (v == first && IsFrontEngine(first)) {
|
|
|
if (v == first && first->IsFrontEngine()) {
|
|
|
DeleteWindowById(WC_VEHICLE_VIEW, first->index);
|
|
|
DeleteWindowById(WC_VEHICLE_ORDERS, first->index);
|
|
|
DeleteWindowById(WC_VEHICLE_REFIT, first->index);
|
|
|
DeleteWindowById(WC_VEHICLE_DETAILS, first->index);
|
|
|
DeleteWindowById(WC_VEHICLE_TIMETABLE, first->index);
|
|
|
}
|
|
@@ -1509,13 +1508,13 @@ CommandCost CmdSellRailWagon(TileIndex t
|
|
|
|
|
|
/* 5. If the train still exists, update its acceleration, window, etc. */
|
|
|
if (first != NULL) {
|
|
|
NormaliseTrainConsist(first);
|
|
|
TrainConsistChanged(first, false);
|
|
|
UpdateTrainGroupID(first);
|
|
|
if (IsFrontEngine(first)) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
|
|
|
if (first->IsFrontEngine()) InvalidateWindow(WC_VEHICLE_REFIT, first->index);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
} break;
|
|
|
case 1: { // Delete wagon and all wagons after it given certain criteria
|
|
|
/* Start deleting every vehicle after the selected one
|
|
@@ -1717,20 +1716,22 @@ static Vehicle *TrainOnTileEnum(Vehicle
|
|
|
* @param v vehicle on tile
|
|
|
* @param data tile with crossing we are testing
|
|
|
* @return v if it is approaching a crossing, NULL otherwise
|
|
|
*/
|
|
|
static Vehicle *TrainApproachingCrossingEnum(Vehicle *v, void *data)
|
|
|
{
|
|
|
/* not a train || not front engine || crashed */
|
|
|
if (v->type != VEH_TRAIN || !IsFrontEngine(v) || (v->vehstatus & VS_CRASHED)) return NULL;
|
|
|
|
|
|
TileIndex tile = *(TileIndex*)data;
|
|
|
|
|
|
if (TrainApproachingCrossingTile(Train::From(v)) != tile) return NULL;
|
|
|
|
|
|
return v;
|
|
|
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
|
|
|
|
|
|
Train *t = Train::From(v);
|
|
|
if (!t->IsFrontEngine()) return NULL;
|
|
|
|
|
|
TileIndex tile = *(TileIndex *)data;
|
|
|
|
|
|
if (TrainApproachingCrossingTile(t) != tile) return NULL;
|
|
|
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Finds a vehicle approaching rail-road crossing
|
|
|
* @param tile tile to test
|
|
@@ -2509,13 +2510,13 @@ static void ClearPathReservation(const T
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** Free the reserved path in front of a vehicle. */
|
|
|
void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_td)
|
|
|
{
|
|
|
assert(IsFrontEngine(v));
|
|
|
assert(v->IsFrontEngine());
|
|
|
|
|
|
TileIndex tile = origin != INVALID_TILE ? origin : v->tile;
|
|
|
Trackdir td = orig_td != INVALID_TRACKDIR ? orig_td : v->GetVehicleTrackdir();
|
|
|
bool free_tile = tile != v->tile || !(IsRailwayStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE));
|
|
|
StationID station_id = IsRailwayStationTile(v->tile) ? GetStationIndex(v->tile) : INVALID_STATION;
|
|
|
|
|
@@ -3095,13 +3096,13 @@ static Track ChooseTrainTrack(Train *v,
|
|
|
* @param mark_as_stuck Should the train be marked as stuck on a failed reservation?
|
|
|
* @param first_tile_okay True if no path should be reserved if the current tile is a safe position.
|
|
|
* @return True if a path could be reserved.
|
|
|
*/
|
|
|
bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
|
|
|
{
|
|
|
assert(v->type == VEH_TRAIN && IsFrontEngine(v));
|
|
|
assert(v->IsFrontEngine());
|
|
|
|
|
|
/* We have to handle depots specially as the track follower won't look
|
|
|
* at the depot tile itself but starts from the next tile. If we are still
|
|
|
* inside the depot, a depot reservation can never be ours. */
|
|
|
if (v->track == TRACK_BIT_DEPOT) {
|
|
|
if (GetDepotWaypointReservation(v->tile)) {
|
|
@@ -3416,13 +3417,13 @@ static byte AfterSetTrainPos(Train *v, b
|
|
|
|
|
|
/* Check if the vehicle is compatible with the specified tile */
|
|
|
static inline bool CheckCompatibleRail(const Train *v, TileIndex tile)
|
|
|
{
|
|
|
return
|
|
|
IsTileOwner(tile, v->owner) && (
|
|
|
!IsFrontEngine(v) ||
|
|
|
!v->IsFrontEngine() ||
|
|
|
HasBit(v->compatible_railtypes, GetRailType(tile))
|
|
|
);
|
|
|
}
|
|
|
|
|
|
struct RailtypeSlowdownParams {
|
|
|
byte small_turn, large_turn;
|
|
@@ -3470,13 +3471,13 @@ static bool TrainMovedChangeSignals(Tile
|
|
|
|
|
|
static void SetVehicleCrashed(Train *v)
|
|
|
{
|
|
|
if (v->crash_anim_pos != 0) return;
|
|
|
|
|
|
/* Free a possible path reservation and try to mark all tiles occupied by the train reserved. */
|
|
|
if (IsFrontEngine(v)) {
|
|
|
if (v->IsFrontEngine()) {
|
|
|
/* Remove all reservations, also the ones currently under the train
|
|
|
* and any railway station paltform reservation. */
|
|
|
FreeTrainTrackReservation(v);
|
|
|
for (const Train *u = v; u != NULL; u = u->Next()) {
|
|
|
ClearPathReservation(u, u->tile, u->GetVehicleTrackdir());
|
|
|
if (IsTileType(u->tile, MP_TUNNELBRIDGE)) {
|
|
@@ -3628,22 +3629,25 @@ static bool CheckTrainCollision(Train *v
|
|
|
|
|
|
ModifyStationRatingAround(v->tile, v->owner, -160, 30);
|
|
|
SndPlayVehicleFx(SND_13_BIG_CRASH, v);
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
static Vehicle *CheckVehicleAtSignal(Vehicle *v, void *data)
|
|
|
static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
|
|
|
{
|
|
|
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
|
|
|
|
|
|
Train *t = Train::From(v);
|
|
|
DiagDirection exitdir = *(DiagDirection *)data;
|
|
|
|
|
|
/* front engine of a train, not inside wormhole or depot, not crashed */
|
|
|
if (v->type == VEH_TRAIN && IsFrontEngine(v) && (Train::From(v)->track & TRACK_BIT_MASK) && !(v->vehstatus & VS_CRASHED)) {
|
|
|
if (v->cur_speed <= 5 && TrainExitDir(v->direction, Train::From(v)->track) == exitdir) return v;
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
/* not front engine of a train, inside wormhole or depot, crashed */
|
|
|
if (!t->IsFrontEngine() || !(t->track & TRACK_BIT_MASK)) return NULL;
|
|
|
|
|
|
if (t->cur_speed > 5 || TrainExitDir(t->direction, t->track) != exitdir) return NULL;
|
|
|
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
static void TrainController(Train *v, Vehicle *nomove)
|
|
|
{
|
|
|
Train *first = v->First();
|
|
|
Train *prev;
|
|
@@ -3664,13 +3668,13 @@ static void TrainController(Train *v, Ve
|
|
|
gp.x = v->x_pos;
|
|
|
gp.y = v->y_pos;
|
|
|
} else {
|
|
|
/* Not inside depot */
|
|
|
|
|
|
/* Reverse when we are at the end of the track already, do not move to the new position */
|
|
|
if (IsFrontEngine(v) && !TrainCheckIfLineEnds(v)) return;
|
|
|
if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v)) return;
|
|
|
|
|
|
uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
|
|
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
|
|
goto invalid_rail;
|
|
|
}
|
|
|
if (HasBit(r, VETS_ENTERED_STATION)) {
|
|
@@ -3734,13 +3738,13 @@ static void TrainController(Train *v, Ve
|
|
|
DiagDirection exitdir = TrackdirToExitdir(i);
|
|
|
TileIndex o_tile = TileAddByDiagDir(gp.new_tile, exitdir);
|
|
|
|
|
|
exitdir = ReverseDiagDir(exitdir);
|
|
|
|
|
|
/* check if a train is waiting on the other side */
|
|
|
if (!HasVehicleOnPos(o_tile, &exitdir, &CheckVehicleAtSignal)) return;
|
|
|
if (!HasVehicleOnPos(o_tile, &exitdir, &CheckTrainAtSignal)) return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* If we would reverse but are currently in a PBS block and
|
|
|
* reversing of stuck trains is disabled, don't reverse. */
|
|
|
if (_settings_game.pf.wait_for_pbs_path == 255 && UpdateSignalsOnSegment(v->tile, enterdir, v->owner) == SIGSEG_PBS) {
|
|
@@ -3802,13 +3806,13 @@ static void TrainController(Train *v, Ve
|
|
|
goto invalid_rail;
|
|
|
}
|
|
|
|
|
|
if (!HasBit(r, VETS_ENTERED_WORMHOLE)) {
|
|
|
Track track = FindFirstTrack(chosen_track);
|
|
|
Trackdir tdir = TrackDirectionToTrackdir(track, chosen_dir);
|
|
|
if (IsFrontEngine(v) && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
|
|
|
if (v->IsFrontEngine() && HasPbsSignalOnTrackdir(gp.new_tile, tdir)) {
|
|
|
SetSignalStateByTrackdir(gp.new_tile, tdir, SIGNAL_STATE_RED);
|
|
|
MarkTileDirtyByTile(gp.new_tile);
|
|
|
}
|
|
|
|
|
|
/* Clear any track reservation when the last vehicle leaves the tile */
|
|
|
if (v->Next() == NULL) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir());
|
|
@@ -3834,13 +3838,13 @@ static void TrainController(Train *v, Ve
|
|
|
v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? rsp->small_turn : rsp->large_turn) * v->cur_speed >> 8;
|
|
|
}
|
|
|
direction_changed = true;
|
|
|
v->direction = chosen_dir;
|
|
|
}
|
|
|
|
|
|
if (IsFrontEngine(v)) {
|
|
|
if (v->IsFrontEngine()) {
|
|
|
v->load_unload_time_rem = 0;
|
|
|
|
|
|
/* If we are approching a crossing that is reserved, play the sound now. */
|
|
|
TileIndex crossing = TrainApproachingCrossingTile(v);
|
|
|
if (crossing != INVALID_TILE && GetCrossingReservation(crossing)) SndPlayTileFx(SND_0E_LEVEL_CROSSING, crossing);
|
|
|
|
|
@@ -3861,13 +3865,13 @@ static void TrainController(Train *v, Ve
|
|
|
v->cur_speed =
|
|
|
min(v->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 (IsFrontEngine(v)) {
|
|
|
if (v->IsFrontEngine()) {
|
|
|
TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
|
|
|
CheckNextTrainTile(v);
|
|
|
}
|
|
|
} else {
|
|
|
v->x_pos = gp.x;
|
|
|
v->y_pos = gp.y;
|
|
@@ -3888,13 +3892,13 @@ static void TrainController(Train *v, Ve
|
|
|
if (prev == NULL) {
|
|
|
/* This is the first vehicle in the train */
|
|
|
AffectSpeedByZChange(v, old_z);
|
|
|
}
|
|
|
|
|
|
if (update_signals_crossing) {
|
|
|
if (IsFrontEngine(v)) {
|
|
|
if (v->IsFrontEngine()) {
|
|
|
if (TrainMovedChangeSignals(gp.new_tile, enterdir)) {
|
|
|
/* We are entering a block with PBS signals right now, but
|
|
|
* not through a PBS signal. This means we don't have a
|
|
|
* reservation right now. As a conventional signal will only
|
|
|
* ever be green if no other train is in the block, getting
|
|
|
* a path should always be possible. If the player built
|
|
@@ -3915,13 +3919,13 @@ static void TrainController(Train *v, Ve
|
|
|
TrainMovedChangeSignals(gp.old_tile, ReverseDiagDir(enterdir));
|
|
|
if (IsLevelCrossingTile(gp.old_tile)) UpdateLevelCrossing(gp.old_tile);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Do not check on every tick to save some computing time. */
|
|
|
if (IsFrontEngine(v) && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
|
|
|
if (v->IsFrontEngine() && v->tick_counter % _settings_game.pf.path_backoff_interval == 0) CheckNextTrainTile(v);
|
|
|
}
|
|
|
|
|
|
if (direction_changed) first->tcache.cached_max_curve_speed = GetTrainCurveSpeedLimit(first);
|
|
|
|
|
|
return;
|
|
|
|
|
@@ -4199,13 +4203,13 @@ static bool TrainCanLeaveTile(const Trai
|
|
|
* @param v front engine of train
|
|
|
* @return TileIndex of crossing the train is approaching, else INVALID_TILE
|
|
|
* @pre v in non-crashed front engine
|
|
|
*/
|
|
|
static TileIndex TrainApproachingCrossingTile(const Train *v)
|
|
|
{
|
|
|
assert(IsFrontEngine(v));
|
|
|
assert(v->IsFrontEngine());
|
|
|
assert(!(v->vehstatus & VS_CRASHED));
|
|
|
|
|
|
if (!TrainCanLeaveTile(v)) return INVALID_TILE;
|
|
|
|
|
|
DiagDirection dir = TrainExitDir(v->direction, v->track);
|
|
|
TileIndex tile = v->tile + TileOffsByDiagDir(dir);
|
|
@@ -4444,13 +4448,13 @@ Money Train::GetRunningCost() const
|
|
|
bool Train::Tick()
|
|
|
{
|
|
|
if (_age_cargo_skip_counter == 0) this->cargo.AgeCargo();
|
|
|
|
|
|
this->tick_counter++;
|
|
|
|
|
|
if (IsFrontEngine(this)) {
|
|
|
if (this->IsFrontEngine()) {
|
|
|
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
|
|
|
|
|
|
this->current_order_time++;
|
|
|
|
|
|
if (!TrainLocoHandler(this, false)) return false;
|
|
|
|
|
@@ -4503,13 +4507,13 @@ static void CheckIfTrainNeedsService(Tra
|
|
|
}
|
|
|
|
|
|
void Train::OnNewDay()
|
|
|
{
|
|
|
if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
|
|
|
|
|
|
if (IsFrontEngine(this)) {
|
|
|
if (this->IsFrontEngine()) {
|
|
|
CheckVehicleBreakdown(this);
|
|
|
AgeVehicle(this);
|
|
|
|
|
|
CheckIfTrainNeedsService(this);
|
|
|
|
|
|
CheckOrders(this);
|