@ -41,8 +41,8 @@
# include "table/train_cmd.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 );
static void TrainController ( Train * v , Vehicle * nomove );
static bool TrainCheckIfLineEnds ( Train * v , bool reverse = true );
bool TrainController ( Train * v , Vehicle * nomove , bool reverse = true ); // Also used in vehicle_sl.cpp.
static TileIndex TrainApproachingCrossingTile ( const Train * v ) ;
static void CheckIfTrainNeedsService ( Train * v ) ;
static void CheckNextTrainTile ( Train * v ) ;
@ -95,7 +95,7 @@ void CheckTrainsLengths()
for ( const Train * u = v , * w = 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 - > gcache. cached_veh_length ) | |
max ( abs ( u - > x_pos - w - > x_pos ) , abs ( u - > y_pos - w - > y_pos ) ) ! = u - > CalcNextVehicleOffset( ) ) | |
( w - > track = = TRACK_BIT_DEPOT & & TicksToLeaveDepot ( u ) < = 0 ) ) {
SetDParam ( 0 , v - > index ) ;
SetDParam ( 1 , v - > owner ) ;
@ -305,11 +305,8 @@ int GetTrainStopLocation(StationID station_id, TileIndex tile, const Train *v, i
}
/* Subtract half the front vehicle length of the train so we get the real
* stop location of the train .
* Actually , the center of all vehicles is half a normal vehicle ' s length
* from the front of the vehicle , so even in case the vehicle is 1 / 8 th
* long , the center is still at 1 / 2 of VEHICLE_LENGTH . Basically FS # 3569. */
return stop - VEHICLE_LENGTH / 2 ;
* stop location of the train . */
return stop - ( v - > gcache . cached_veh_length + 1 ) / 2 ;
}
@ -1382,25 +1379,66 @@ CommandCost CmdSellRailWagon(DoCommandFlag flags, Vehicle *t, uint16 data, uint3
void Train : : UpdateDeltaXY ( Direction direction )
{
# define MKIT(a, b, c, d) ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF) << 0)
static const uint32 _delta_xy_table [ 8 ] = {
MKIT ( 3 , 3 , - 1 , - 1 ) ,
MKIT ( 3 , 7 , - 1 , - 3 ) ,
MKIT ( 3 , 3 , - 1 , - 1 ) ,
MKIT ( 7 , 3 , - 3 , - 1 ) ,
MKIT ( 3 , 3 , - 1 , - 1 ) ,
MKIT ( 3 , 7 , - 1 , - 3 ) ,
MKIT ( 3 , 3 , - 1 , - 1 ) ,
MKIT ( 7 , 3 , - 3 , - 1 ) ,
} ;
# undef MKIT
/* Set common defaults. */
this - > x_offs = - 1 ;
this - > y_offs = - 1 ;
this - > x_extent = 3 ;
this - > y_extent = 3 ;
this - > z_extent = 6 ;
this - > x_bb_offs = 0 ;
this - > y_bb_offs = 0 ;
if ( ! IsDiagonalDirection ( direction ) ) {
static const int _sign_table [ ] =
{
// x, y
- 1 , - 1 , // DIR_N
- 1 , 1 , // DIR_E
1 , 1 , // DIR_S
1 , - 1 , // DIR_W
} ;
int half_shorten = ( VEHICLE_LENGTH - this - > gcache . cached_veh_length ) / 2 ;
/* For all straight directions, move the bound box to the centre of the vehicle, but keep the size. */
this - > x_offs - = half_shorten * _sign_table [ direction ] ;
this - > y_offs - = half_shorten * _sign_table [ direction + 1 ] ;
this - > x_extent + = this - > x_bb_offs = half_shorten * _sign_table [ direction ] ;
this - > y_extent + = this - > y_bb_offs = half_shorten * _sign_table [ direction + 1 ] ;
} else {
switch ( direction ) {
/* Shorten southern corner of the bounding box according the vehicle length
* and center the bounding box on the vehicle . */
case DIR_NE :
this - > x_offs = 1 - ( this - > gcache . cached_veh_length + 1 ) / 2 ;
this - > x_extent = this - > gcache . cached_veh_length - 1 ;
this - > x_bb_offs = - 1 ;
break ;
uint32 x = _delta_xy_table [ direction ] ;
this - > x_offs = GB ( x , 0 , 8 ) ;
this - > y_offs = GB ( x , 8 , 8 ) ;
this - > x_extent = GB ( x , 16 , 8 ) ;
this - > y_extent = GB ( x , 24 , 8 ) ;
this - > z_extent = 6 ;
case DIR_NW :
this - > y_offs = 1 - ( this - > gcache . cached_veh_length + 1 ) / 2 ;
this - > y_extent = this - > gcache . cached_veh_length - 1 ;
this - > y_bb_offs = - 1 ;
break ;
/* Move northern corner of the bounding box down according to vehicle length
* and center the bounding box on the vehicle . */
case DIR_SW :
this - > x_offs = 1 + ( this - > gcache . cached_veh_length + 1 ) / 2 - VEHICLE_LENGTH ;
this - > x_extent = VEHICLE_LENGTH - 1 ;
this - > x_bb_offs = VEHICLE_LENGTH - this - > gcache . cached_veh_length - 1 ;
break ;
case DIR_SE :
this - > y_offs = 1 + ( this - > gcache . cached_veh_length + 1 ) / 2 - VEHICLE_LENGTH ;
this - > y_extent = VEHICLE_LENGTH - 1 ;
this - > y_bb_offs = VEHICLE_LENGTH - this - > gcache . cached_veh_length - 1 ;
break ;
default :
NOT_REACHED ( ) ;
}
}
}
/** Mark a train as stuck and stop it if it isn't stopped right now. */
@ -1478,7 +1516,7 @@ static void UpdateStatusAfterSwap(Train *v)
v - > UpdateViewport ( true , true ) ;
}
static void ReverseTrainSwapVeh ( Train * v , int l , int r )
void ReverseTrainSwapVeh ( Train * v , int l , int r )
{
Train * a , * b ;
@ -1626,7 +1664,7 @@ static void AdvanceWagonsBeforeSwap(Train *v)
last = last - > Previous ( ) ;
first = first - > Next ( ) ;
int differential = base - > gcache. cached_veh_length - last - > gcache . cached_veh_length ;
int differential = base - > CalcNextVehicleOffset( ) - last - > CalcNextVehicleOffset ( ) ;
/* do not update images now
* negative differential will be handled in AdvanceWagonsAfterSwap ( ) */
@ -1686,7 +1724,7 @@ static void AdvanceWagonsAfterSwap(Train *v)
last = last - > Previous ( ) ;
first = first - > Next ( ) ;
int differential = last - > gcache. cached_veh_length - base - > gcache . cached_veh_length ;
int differential = last - > CalcNextVehicleOffset( ) - base - > CalcNextVehicleOffset ( ) ;
/* do not update images now */
for ( int i = 0 ; i < differential ; i + + ) TrainController ( first , ( nomove ? last - > Next ( ) : NULL ) ) ;
@ -1697,7 +1735,7 @@ static void AdvanceWagonsAfterSwap(Train *v)
}
static void ReverseTrainDirection ( Train * v )
void ReverseTrainDirection ( Train * v )
{
if ( IsRailDepotTile ( v - > tile ) ) {
InvalidateWindowData ( WC_VEHICLE_DEPOT , v - > tile ) ;
@ -2840,7 +2878,8 @@ static Vehicle *FindTrainCollideEnum(Vehicle *v, void *data)
if ( hash & ~ 15 ) return NULL ;
/* Slower check using multiplication */
if ( x_diff * x_diff + y_diff * y_diff > 25 ) return NULL ;
int min_diff = ( Train : : From ( v ) - > gcache . cached_veh_length + 1 ) / 2 + ( tcc - > v - > gcache . cached_veh_length + 1 ) / 2 - 1 ;
if ( x_diff * x_diff + y_diff * y_diff > min_diff * min_diff ) return NULL ;
/* Happens when there is a train under bridge next to bridge head */
if ( abs ( v - > z_pos - tcc - > v - > z_pos ) > 5 ) return NULL ;
@ -2906,7 +2945,14 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
return t ;
}
static void TrainController ( Train * v , Vehicle * nomove )
/**
* Move a vehicle chain one movement stop forwards .
* @ param v First vehicle to move .
* @ param nomove Stop moving this and all following vehicles .
* @ param reverse Set to false to not execute the vehicle reversing . This does not change any other logic .
* @ return True if the vehicle could be moved forward , false otherwise .
*/
bool TrainController ( Train * v , Vehicle * nomove , bool reverse )
{
Train * first = v - > First ( ) ;
Train * prev ;
@ -2930,7 +2976,7 @@ static void TrainController(Train *v, Vehicle *nomove)
/* Not inside depot */
/* Reverse when we are at the end of the track already, do not move to the new position */
if ( v - > IsFrontEngine ( ) & & ! TrainCheckIfLineEnds ( v )) return ;
if ( v - > IsFrontEngine ( ) & & ! TrainCheckIfLineEnds ( v , reverse )) return false ;
uint32 r = VehicleEnterTile ( v , gp . new_tile , gp . x , gp . y ) ;
if ( HasBit ( r , VETS_CANNOT_ENTER ) ) {
@ -2997,13 +3043,13 @@ static void TrainController(Train *v, Vehicle *nomove)
Trackdir i = FindFirstTrackdir ( trackdirbits ) ;
/* Don't handle stuck trains here. */
if ( HasBit ( v - > flags , VRF_TRAIN_STUCK ) ) return ;
if ( HasBit ( v - > flags , VRF_TRAIN_STUCK ) ) return false ;
if ( ! HasSignalOnTrackdir ( gp . new_tile , ReverseTrackdir ( i ) ) ) {
v - > cur_speed = 0 ;
v - > subspeed = 0 ;
v - > progress = 255 - 100 ;
if ( ! _settings_game . pf . reverse_at_signals | | + + v - > wait_counter < _settings_game . pf . wait_oneway_signal * 20 ) return ;
if ( ! _settings_game . pf . reverse_at_signals | | + + v - > wait_counter < _settings_game . pf . wait_oneway_signal * 20 ) return false ;
} else if ( HasSignalOnTrackdir ( gp . new_tile , i ) ) {
v - > cur_speed = 0 ;
v - > subspeed = 0 ;
@ -3015,7 +3061,7 @@ static void TrainController(Train *v, Vehicle *nomove)
exitdir = ReverseDiagDir ( exitdir ) ;
/* check if a train is waiting on the other side */
if ( ! HasVehicleOnPos ( o_tile , & exitdir , & CheckTrainAtSignal ) ) return ;
if ( ! HasVehicleOnPos ( o_tile , & exitdir , & CheckTrainAtSignal ) ) return false ;
}
}
@ -3026,7 +3072,7 @@ static void TrainController(Train *v, Vehicle *nomove)
if ( ! _settings_game . pf . reverse_at_signals & & ! HasOnewaySignalBlockingTrackdir ( gp . new_tile , i ) & &
UpdateSignalsOnSegment ( v - > tile , enterdir , v - > owner ) = = SIGSEG_PBS ) {
v - > wait_counter = 0 ;
return ;
return false ;
}
goto reverse_train_direction ;
} else {
@ -3209,17 +3255,21 @@ static void TrainController(Train *v, Vehicle *nomove)
if ( direction_changed ) first - > tcache . cached_max_curve_speed = first - > GetCurveSpeedLimit ( ) ;
return ;
return true ;
invalid_rail :
/* We've reached end of line?? */
if ( prev ! = NULL ) error ( " Disconnecting train " ) ;
reverse_train_direction :
v - > wait_counter = 0 ;
v - > cur_speed = 0 ;
v - > subspeed = 0 ;
ReverseTrainDirection ( v ) ;
if ( reverse ) {
v - > wait_counter = 0 ;
v - > cur_speed = 0 ;
v - > subspeed = 0 ;
ReverseTrainDirection ( v ) ;
}
return false ;
}
/**
@ -3389,9 +3439,10 @@ static const uint16 _breakdown_speeds[16] = {
*
* @ param v front train engine
* @ param signal not line end , just a red signal
* @ param reverse Set to false to not execute the vehicle reversing . This does not change any other logic .
* @ return true iff we did NOT have to reverse
*/
static bool TrainApproachingLineEnd ( Train * v , bool signal )
static bool TrainApproachingLineEnd ( Train * v , bool signal , bool reverse )
{
/* Calc position within the current tile */
uint x = v - > x_pos & 0xF ;
@ -3413,13 +3464,12 @@ static bool TrainApproachingLineEnd(Train *v, bool signal)
/* Do not reverse when approaching red signal. Make sure the vehicle's front
* does not cross the tile boundary when we do reverse , but as the vehicle ' s
* location is based on their center , use half a vehicle ' s length as offset .
* Actually , the center of all vehicles is half a normal vehicle ' s length
* from the front of the vehicle , so even in case the vehicle is 1 / 8 th
* long , the center is still at 1 / 2 of VEHICLE_LENGTH . Basically FS # 3569. */
if ( ! signal & & x + VEHICLE_LENGTH / 2 > = TILE_SIZE ) {
* Multiply the half - length by two for straight directions to compensate that
* we only get odd x offsets there . */
if ( ! signal & & x + ( v - > gcache . cached_veh_length + 1 ) / 2 * ( IsDiagonalDirection ( v - > direction ) ? 1 : 2 ) > = TILE_SIZE ) {
/* we are too near the tile end, reverse now */
v - > cur_speed = 0 ;
ReverseTrainDirection ( v ) ;
if ( reverse ) ReverseTrainDirection ( v ) ;
return false ;
}
@ -3491,9 +3541,10 @@ static TileIndex TrainApproachingCrossingTile(const Train *v)
* Checks for line end . Also , bars crossing at next tile if needed
*
* @ param v vehicle we are checking
* @ param reverse Set to false to not execute the vehicle reversing . This does not change any other logic .
* @ return true iff we did NOT have to reverse
*/
static bool TrainCheckIfLineEnds ( Train * v )
static bool TrainCheckIfLineEnds ( Train * v , bool reverse )
{
/* First, handle broken down train */
@ -3531,11 +3582,11 @@ static bool TrainCheckIfLineEnds(Train *v)
/* no suitable trackbits at all || unusable rail (wrong type or owner) */
if ( bits = = TRACK_BIT_NONE | | ! CheckCompatibleRail ( v , tile ) ) {
return TrainApproachingLineEnd ( v , false );
return TrainApproachingLineEnd ( v , false , reverse );
}
/* approaching red signal */
if ( ( trackdirbits & red_signals ) ! = 0 ) return TrainApproachingLineEnd ( v , true );
if ( ( trackdirbits & red_signals ) ! = 0 ) return TrainApproachingLineEnd ( v , true , reverse );
/* approaching a rail/road crossing? then make it red */
if ( IsLevelCrossingTile ( tile ) ) MaybeBarCrossingWithSound ( tile ) ;