2004-08-09 17:04:08 +00:00
# include "stdafx.h"
# include "ttd.h"
2004-11-25 10:47:30 +00:00
# include "table/strings.h"
2004-12-15 22:18:54 +00:00
# include "map.h"
2005-01-29 12:19:05 +00:00
# include "tile.h"
2004-08-09 17:04:08 +00:00
# include "vehicle.h"
# include "engine.h"
# include "command.h"
# include "station.h"
# include "news.h"
# include "gfx.h"
# include "pathfind.h"
2005-01-31 11:23:10 +00:00
# include "npf.h"
2004-08-09 17:04:08 +00:00
# include "player.h"
2004-11-05 23:12:33 +00:00
# include "sound.h"
2004-08-09 17:04:08 +00:00
void ShowRoadVehViewWindow ( Vehicle * v ) ;
static const uint16 _roadveh_images [ 63 ] = {
0xCD4 , 0xCDC , 0xCE4 , 0xCEC , 0xCF4 , 0xCFC , 0xD0C , 0xD14 ,
0xD24 , 0xD1C , 0xD2C , 0xD04 , 0xD1C , 0xD24 , 0xD6C , 0xD74 ,
0xD7C , 0xC14 , 0xC1C , 0xC24 , 0xC2C , 0xC34 , 0xC3C , 0xC4C ,
0xC54 , 0xC64 , 0xC5C , 0xC6C , 0xC44 , 0xC5C , 0xC64 , 0xCAC ,
0xCB4 , 0xCBC , 0xD94 , 0xD9C , 0xDA4 , 0xDAC , 0xDB4 , 0xDBC ,
0xDCC , 0xDD4 , 0xDE4 , 0xDDC , 0xDEC , 0xDC4 , 0xDDC , 0xDE4 ,
0xE2C , 0xE34 , 0xE3C , 0xC14 , 0xC1C , 0xC2C , 0xC3C , 0xC4C ,
0xC5C , 0xC64 , 0xC6C , 0xC74 , 0xC84 , 0xC94 , 0xCA4
} ;
static const uint16 _roadveh_full_adder [ 63 ] = {
0 , 88 , 0 , 0 , 0 , 0 , 48 , 48 ,
48 , 48 , 0 , 0 , 64 , 64 , 0 , 16 ,
16 , 0 , 88 , 0 , 0 , 0 , 0 , 48 ,
48 , 48 , 48 , 0 , 0 , 64 , 64 , 0 ,
16 , 16 , 0 , 88 , 0 , 0 , 0 , 0 ,
48 , 48 , 48 , 48 , 0 , 0 , 64 , 64 ,
0 , 16 , 16 , 0 , 8 , 8 , 8 , 8 ,
0 , 0 , 0 , 8 , 8 , 8 , 8
} ;
static const uint16 _road_veh_fp_ax_or [ 4 ] = {
0x100 , 0x200 , 1 , 2 ,
} ;
static const uint16 _road_veh_fp_ax_and [ 4 ] = {
0x1009 , 0x16 , 0x520 , 0x2A00
} ;
static const byte _road_reverse_table [ 4 ] = {
6 , 7 , 14 , 15
} ;
static const uint16 _road_pf_table_3 [ 4 ] = {
0x910 , 0x1600 , 0x2005 , 0x2A
} ;
int GetRoadVehImage ( Vehicle * v , byte direction )
{
int img = v - > spritenum ;
int image ;
if ( is_custom_sprite ( img ) ) {
image = GetCustomVehicleSprite ( v , direction ) ;
if ( image ) return image ;
img = _engine_original_sprites [ v - > engine_type ] ;
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
image = direction + _roadveh_images [ img ] ;
if ( v - > cargo_count > = ( v - > cargo_cap > > 1 ) )
image + = _roadveh_full_adder [ img ] ;
return image ;
}
void DrawRoadVehEngine ( int x , int y , int engine , uint32 image_ormod )
{
2004-12-03 21:57:05 +00:00
int spritenum = RoadVehInfo ( engine ) - > image_index ;
2004-11-13 18:01:33 +00:00
if ( is_custom_sprite ( spritenum ) ) {
int sprite = GetCustomVehicleIcon ( engine , 6 ) ;
if ( sprite ) {
DrawSprite ( sprite | image_ormod , x , y ) ;
return ;
}
spritenum = _engine_original_sprites [ engine ] ;
}
DrawSprite ( ( 6 + _roadveh_images [ spritenum ] ) | image_ormod , x , y ) ;
2004-08-09 17:04:08 +00:00
}
void DrawRoadVehEngineInfo ( int engine , int x , int y , int maxw )
{
2004-12-03 21:57:05 +00:00
const RoadVehicleInfo * rvi = RoadVehInfo ( engine ) ;
2004-08-09 17:04:08 +00:00
2004-12-03 21:57:05 +00:00
SetDParam ( 0 , ( ( _price . roadveh_base > > 3 ) * rvi - > base_cost ) > > 5 ) ;
SetDParam ( 1 , rvi - > max_speed * 10 > > 5 ) ;
SetDParam ( 2 , rvi - > running_cost * _price . roadveh_running > > 8 ) ;
SetDParam ( 4 , rvi - > capacity ) ;
SetDParam ( 3 , _cargoc . names_long_p [ rvi - > cargo_type ] ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
DrawStringMultiCenter ( x , y , STR_902A_COST_SPEED_RUNNING_COST , maxw ) ;
}
2004-12-27 18:18:44 +00:00
int32 EstimateRoadVehCost ( byte engine_type )
2004-08-09 17:04:08 +00:00
{
2004-12-03 21:57:05 +00:00
return ( ( _price . roadveh_base > > 3 ) * RoadVehInfo ( engine_type ) - > base_cost ) > > 5 ;
2004-08-09 17:04:08 +00:00
}
2005-01-02 17:23:04 +00:00
// p1 = engine_type
// p2 not used
2004-08-09 17:04:08 +00:00
int32 CmdBuildRoadVeh ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
int32 cost ;
Vehicle * v ;
byte unit_num ;
uint tile = TILE_FROM_XY ( x , y ) ;
Engine * e ;
2004-09-10 19:02:27 +00:00
2005-01-27 21:18:03 +00:00
if ( ! IsEngineBuildable ( p1 , VEH_Road ) ) return CMD_ERROR ;
2005-01-27 21:00:05 +00:00
2005-01-30 13:42:11 +00:00
if ( ! IsRoadDepotTile ( ( TileIndex ) tile ) ) return CMD_ERROR ;
if ( _map_owner [ tile ] ! = _current_player ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_NEW_VEHICLES ) ;
cost = EstimateRoadVehCost ( p1 ) ;
if ( flags & DC_QUERY_COST )
return cost ;
v = AllocateVehicle ( ) ;
2005-01-15 19:06:22 +00:00
if ( v = = NULL | | IsOrderPoolFull ( ) )
2004-08-09 17:04:08 +00:00
return_cmd_error ( STR_00E1_TOO_MANY_VEHICLES_IN_GAME ) ;
/* find the first free roadveh id */
unit_num = GetFreeUnitNumber ( VEH_Road ) ;
if ( unit_num > _patches . max_roadveh )
return_cmd_error ( STR_00E1_TOO_MANY_VEHICLES_IN_GAME ) ;
if ( flags & DC_EXEC ) {
2004-12-03 21:57:05 +00:00
const RoadVehicleInfo * rvi = RoadVehInfo ( p1 ) ;
2004-08-09 17:04:08 +00:00
v - > unitnumber = unit_num ;
v - > direction = 0 ;
v - > owner = _current_player ;
v - > tile = tile ;
2005-01-07 17:02:43 +00:00
x = TileX ( tile ) * 16 + 8 ;
y = TileY ( tile ) * 16 + 8 ;
2004-08-09 17:04:08 +00:00
v - > x_pos = x ;
v - > y_pos = y ;
v - > z_pos = GetSlopeZ ( x , y ) ;
v - > z_height = 6 ;
v - > u . road . state = 254 ;
v - > vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL ;
2004-12-03 21:57:05 +00:00
v - > spritenum = rvi - > image_index ;
v - > cargo_type = rvi - > cargo_type ;
v - > cargo_cap = rvi - > capacity ;
2004-08-09 17:04:08 +00:00
// v->cargo_count = 0;
v - > value = cost ;
// v->day_counter = 0;
// v->next_order_param = v->next_order = 0;
// v->load_unload_time_rem = 0;
// v->progress = 0;
// v->u.road.unk2 = 0;
// v->u.road.overtaking = 0;
2005-01-29 19:41:44 +00:00
v - > u . road . slot = NULL ;
v - > u . road . slotindex = 0 ;
v - > u . road . slot_age = 0 ;
2005-02-02 16:16:43 +00:00
v - > last_station_visited = INVALID_STATION ;
2004-12-03 21:57:05 +00:00
v - > max_speed = rvi - > max_speed ;
2004-08-09 17:04:08 +00:00
v - > engine_type = ( byte ) p1 ;
e = & _engines [ p1 ] ;
v - > reliability = e - > reliability ;
v - > reliability_spd_dec = e - > reliability_spd_dec ;
v - > max_age = e - > lifelength * 366 ;
_new_roadveh_id = v - > index ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
v - > string_id = STR_SV_ROADVEH_NAME ;
v - > service_interval = _patches . servint_roadveh ;
v - > date_of_last_service = _date ;
v - > build_year = _cur_year ;
v - > type = VEH_Road ;
v - > cur_image = 0xC15 ;
VehiclePositionChanged ( v ) ;
InvalidateWindow ( WC_VEHICLE_DEPOT , v - > tile ) ;
2004-12-10 18:16:08 +00:00
RebuildVehicleLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_COMPANY , v - > owner ) ;
}
2005-01-23 22:01:51 +00:00
InvalidateWindow ( WC_REPLACE_VEHICLE , VEH_Road ) ; // updates the replace Road window
2004-08-09 17:04:08 +00:00
return cost ;
}
// p1 = vehicle
int32 CmdStartStopRoadVeh ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
Vehicle * v ;
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
2005-01-06 22:31:58 +00:00
v = GetVehicle ( p1 ) ;
2004-08-09 17:04:08 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) )
return CMD_ERROR ;
if ( flags & DC_EXEC ) {
v - > vehstatus ^ = VS_STOPPED ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_VEHICLE_DEPOT , v - > tile ) ;
}
return 0 ;
}
2005-01-06 22:31:58 +00:00
// p1 = vehicle index in GetVehicle()
2005-01-02 17:23:04 +00:00
// p2 not used
2004-08-09 17:04:08 +00:00
int32 CmdSellRoadVeh ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
Vehicle * v ;
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
2004-09-10 19:02:27 +00:00
2005-01-06 22:31:58 +00:00
v = GetVehicle ( p1 ) ;
2004-08-09 17:04:08 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) )
return CMD_ERROR ;
2005-01-30 20:50:06 +00:00
SET_EXPENSES_TYPE ( EXPENSES_NEW_VEHICLES ) ;
2004-08-09 17:04:08 +00:00
if ( ! IsRoadDepotTile ( v - > tile ) | | v - > u . road . state ! = 254 | | ! ( v - > vehstatus & VS_STOPPED ) )
return_cmd_error ( STR_9013_MUST_BE_STOPPED_INSIDE ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
// Invalidate depot
InvalidateWindow ( WC_VEHICLE_DEPOT , v - > tile ) ;
2004-12-10 18:16:08 +00:00
RebuildVehicleLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_COMPANY , v - > owner ) ;
DeleteWindowById ( WC_VEHICLE_VIEW , v - > index ) ;
DeleteVehicle ( v ) ;
}
2005-01-23 22:01:51 +00:00
InvalidateWindow ( WC_REPLACE_VEHICLE , VEH_Road ) ; // updates the replace Road window
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
return - ( int32 ) v - > value ;
}
typedef struct RoadFindDepotData {
uint best_length ;
uint tile ;
byte owner ;
} RoadFindDepotData ;
static const byte _road_pf_directions [ 16 ] = {
0 , 1 , 0 , 1 , 2 , 1 , 255 , 255 ,
2 , 3 , 3 , 2 , 3 , 0 , 255 , 255 ,
} ;
static bool EnumRoadSignalFindDepot ( uint tile , RoadFindDepotData * rfdd , int track , uint length , byte * state )
{
2005-01-05 18:09:06 +00:00
tile + = TileOffsByDir ( _road_pf_directions [ track ] ) ;
2004-08-09 17:04:08 +00:00
2005-01-16 11:24:58 +00:00
if ( IsTileType ( tile , MP_STREET ) & &
2004-08-09 17:04:08 +00:00
( _map5 [ tile ] & 0xF0 ) = = 0x20 & &
_map_owner [ tile ] = = rfdd - > owner ) {
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
if ( length < rfdd - > best_length ) {
rfdd - > best_length = length ;
rfdd - > tile = tile ;
}
}
return false ;
}
static int FindClosestRoadDepot ( Vehicle * v )
{
uint tile = v - > tile ;
int i ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
if ( v - > u . road . state = = 255 ) { tile = GetVehicleOutOfTunnelTile ( v ) ; }
2005-01-31 11:23:10 +00:00
if ( _patches . new_pathfinding_all ) {
NPFFoundTargetData ftd ;
/* See where we are now */
byte trackdir = _dir_to_diag_trackdir [ ( v - > direction > > 1 ) & 3 ] ;
ftd = NPFRouteToDepotBreadthFirst ( v - > tile , trackdir , TRANSPORT_ROAD ) ;
if ( ftd . best_bird_dist = = 0 )
return GetDepotByTile ( ftd . node . tile ) ; /* Target found */
else
return - 1 ; /* Target not found */
/* We do not search in two directions here, why should we? We can't reverse right now can we? */
} else {
RoadFindDepotData rfdd ;
rfdd . owner = v - > owner ;
rfdd . best_length = ( uint ) - 1 ;
2004-08-09 17:04:08 +00:00
2005-01-31 11:23:10 +00:00
/* search in all directions */
for ( i = 0 ; i ! = 4 ; i + + )
FollowTrack ( tile , 0x2000 | TRANSPORT_ROAD , i , ( TPFEnumProc * ) EnumRoadSignalFindDepot , NULL , & rfdd ) ;
2004-08-09 17:04:08 +00:00
2005-01-31 11:23:10 +00:00
if ( rfdd . best_length = = ( uint ) - 1 )
return - 1 ;
2004-08-09 17:04:08 +00:00
2005-01-31 11:23:10 +00:00
return GetDepotByTile ( rfdd . tile ) ;
}
2004-08-09 17:04:08 +00:00
}
2005-01-28 17:31:42 +00:00
/* Send a road vehicle to the nearest depot
p1 = index of the road vehicle
2005-01-29 01:02:47 +00:00
p2 = bit 0 = do not stop in depot
bit 1 = set v - > set_for_replacement
bit 2 = clear v - > set_for_replacement */
2004-08-09 17:04:08 +00:00
int32 CmdSendRoadVehToDepot ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
2005-01-30 20:50:06 +00:00
Vehicle * v ;
2004-08-09 17:04:08 +00:00
int depot ;
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
v = GetVehicle ( p1 ) ;
2004-08-09 17:04:08 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) )
return CMD_ERROR ;
2005-01-28 17:31:42 +00:00
if ( HASBIT ( p2 , 0 ) ) v - > set_for_replacement = true ;
2005-01-29 01:02:47 +00:00
if ( HASBIT ( p2 , 2 ) ) v - > set_for_replacement = false ;
2005-01-28 17:31:42 +00:00
2005-01-29 01:02:47 +00:00
if ( HASBIT ( p2 , 1 ) | | HASBIT ( p2 , 2 ) ) return CMD_ERROR ; // vehicle has a depot in schedule. It just needed to alter set_for_replacement
2005-01-28 17:31:42 +00:00
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT ) {
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2004-12-05 12:43:04 +00:00
if ( v - > current_order . flags & OF_UNLOAD )
2004-08-09 17:04:08 +00:00
v - > cur_order_index + + ;
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_DUMMY ;
v - > current_order . flags = 0 ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
return 0 ;
}
depot = FindClosestRoadDepot ( v ) ;
if ( depot < 0 )
return_cmd_error ( STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT ) ;
if ( flags & DC_EXEC ) {
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_GOTO_DEPOT ;
2005-01-28 17:31:42 +00:00
v - > current_order . flags = p2 = = 0 ? OF_NON_STOP | OF_FULL_LOAD : 0 ;
2004-12-05 12:43:04 +00:00
v - > current_order . station = ( byte ) depot ;
2004-08-09 17:04:08 +00:00
v - > dest_tile = _depots [ depot ] . xy ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
return 0 ;
}
int32 CmdTurnRoadVeh ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
Vehicle * v ;
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
2005-01-06 22:31:58 +00:00
v = GetVehicle ( p1 ) ;
2004-08-09 17:04:08 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) )
return CMD_ERROR ;
if ( v - > vehstatus & ( VS_HIDDEN | VS_STOPPED ) | |
v - > u . road . crashed_ctr ! = 0 | |
v - > breakdown_ctr ! = 0 | |
v - > u . road . overtaking ! = 0 | |
v - > cur_speed < 5 ) {
_error_message = STR_EMPTY ;
return CMD_ERROR ;
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
v - > u . road . reverse_ctr = 180 ;
2004-09-10 19:02:27 +00:00
}
2004-08-09 17:04:08 +00:00
return 0 ;
}
int32 CmdChangeRoadVehServiceInt ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
Vehicle * v ;
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
2005-01-06 22:31:58 +00:00
v = GetVehicle ( p1 ) ;
2004-08-09 17:04:08 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) )
return CMD_ERROR ;
if ( flags & DC_EXEC ) {
v - > service_interval = ( uint16 ) p2 ;
InvalidateWindowWidget ( WC_VEHICLE_DETAILS , v - > index , 7 ) ;
}
return 0 ;
}
static void MarkRoadVehDirty ( Vehicle * v )
{
v - > cur_image = GetRoadVehImage ( v , v - > direction ) ;
MarkAllViewportsDirty ( v - > left_coord , v - > top_coord , v - > right_coord + 1 , v - > bottom_coord + 1 ) ;
}
static void UpdateRoadVehDeltaXY ( Vehicle * v )
{
# 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
uint32 x = _delta_xy_table [ v - > direction ] ;
v - > x_offs = ( byte ) x ;
v - > y_offs = ( byte ) ( x > > = 8 ) ;
v - > sprite_width = ( byte ) ( x > > = 8 ) ;
v - > sprite_height = ( byte ) ( x > > = 8 ) ;
}
static void ClearCrashedStation ( Vehicle * v )
{
uint tile = v - > tile ;
byte * b , bb ;
2005-01-29 19:41:44 +00:00
RoadStop * rs = GetRoadStopByTile ( tile , GetRoadStopType ( tile ) ) ;
b = & rs - > status ;
2004-08-09 17:04:08 +00:00
bb = * b ;
// mark station as not busy
bb & = ~ 0x80 ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// free parking bay
bb | = ( v - > u . road . state & 0x02 ) ? 2 : 1 ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
* b = bb ;
}
static void RoadVehDelete ( Vehicle * v )
{
DeleteWindowById ( WC_VEHICLE_VIEW , v - > index ) ;
InvalidateWindow ( WC_VEHICLE_DETAILS , v - > index ) ;
2004-09-10 19:02:27 +00:00
2004-12-10 18:16:08 +00:00
RebuildVehicleLists ( ) ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_COMPANY , v - > owner ) ;
2005-01-16 11:24:58 +00:00
if ( IsTileType ( v - > tile , MP_STATION ) )
2004-08-09 17:04:08 +00:00
ClearCrashedStation ( v ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
BeginVehicleMove ( v ) ;
EndVehicleMove ( v ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
DeleteVehicle ( v ) ;
}
static byte SetRoadVehPosition ( Vehicle * v , int x , int y )
{
byte new_z , old_z ;
// need this hint so it returns the right z coordinate on bridges.
_get_z_hint = v - > z_pos ;
new_z = GetSlopeZ ( v - > x_pos = x , v - > y_pos = y ) ;
_get_z_hint = 0 ;
old_z = v - > z_pos ;
v - > z_pos = new_z ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
VehiclePositionChanged ( v ) ;
EndVehicleMove ( v ) ;
return old_z ;
}
static void RoadVehSetRandomDirection ( Vehicle * v )
{
static const int8 _turn_prob [ 4 ] = { - 1 , 0 , 0 , 1 } ;
uint32 r = Random ( ) ;
v - > direction = ( v - > direction + _turn_prob [ r & 3 ] ) & 7 ;
BeginVehicleMove ( v ) ;
UpdateRoadVehDeltaXY ( v ) ;
v - > cur_image = GetRoadVehImage ( v , v - > direction ) ;
SetRoadVehPosition ( v , v - > x_pos , v - > y_pos ) ;
}
static void RoadVehIsCrashed ( Vehicle * v )
{
v - > u . road . crashed_ctr + + ;
if ( v - > u . road . crashed_ctr = = 2 ) {
CreateEffectVehicleRel ( v , 4 , 4 , 8 , EV_CRASHED_SMOKE ) ;
} else if ( v - > u . road . crashed_ctr < = 45 ) {
if ( ( v - > tick_counter & 7 ) = = 0 )
RoadVehSetRandomDirection ( v ) ;
} else if ( v - > u . road . crashed_ctr > = 2220 ) {
RoadVehDelete ( v ) ;
}
}
static void * EnumCheckRoadVehCrashTrain ( Vehicle * v , Vehicle * u )
{
if ( v - > type ! = VEH_Train | |
myabs ( v - > z_pos - u - > z_pos ) > 6 | |
myabs ( v - > x_pos - u - > x_pos ) > 4 | |
myabs ( v - > y_pos - u - > y_pos ) > 4 )
return NULL ;
return v ;
}
static void RoadVehCrash ( Vehicle * v )
{
uint16 pass ;
v - > u . road . crashed_ctr + + ;
v - > vehstatus | = VS_CRASHED ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
pass = 1 ;
if ( v - > cargo_type = = 0 )
pass + = v - > cargo_count ;
v - > cargo_count = 0 ;
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , pass ) ;
2004-08-09 17:04:08 +00:00
AddNewsItem ( STR_9031_ROAD_VEHICLE_CRASH_DRIVER + ( pass ! = 1 ) ,
NEWS_FLAGS ( NM_THIN , NF_VIEWPORT | NF_VEHICLE , NT_ACCIDENT , 0 ) ,
v - > index ,
0 ) ;
ModifyStationRatingAround ( v - > tile , v - > owner , - 160 , 22 ) ;
2004-12-04 09:26:39 +00:00
SndPlayVehicleFx ( SND_12_EXPLOSION , v ) ;
2004-08-09 17:04:08 +00:00
}
static void RoadVehCheckTrainCrash ( Vehicle * v )
{
uint tile ;
if ( v - > u . road . state = = 255 )
return ;
tile = v - > tile ;
// Make sure it's a road/rail crossing
2005-01-16 11:24:58 +00:00
if ( ! IsTileType ( tile , MP_STREET ) | |
2005-01-24 22:24:47 +00:00
( _map5 [ tile ] & 0xF0 ) ! = 0x10 )
2004-08-09 17:04:08 +00:00
return ;
if ( VehicleFromPos ( tile , v , ( VehicleFromPosProc * ) EnumCheckRoadVehCrashTrain ) ! = NULL )
RoadVehCrash ( v ) ;
}
static void HandleBrokenRoadVeh ( Vehicle * v )
{
if ( v - > breakdown_ctr ! = 1 ) {
v - > breakdown_ctr = 1 ;
v - > cur_speed = 0 ;
if ( v - > breakdowns_since_last_service ! = 255 )
v - > breakdowns_since_last_service + + ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_VEHICLE_VIEW , v - > index ) ;
InvalidateWindow ( WC_VEHICLE_DETAILS , v - > index ) ;
2004-09-10 19:02:27 +00:00
2004-12-04 09:26:39 +00:00
SndPlayVehicleFx ( ( _opt . landscape ! = LT_CANDY ) ?
SND_0F_VEHICLE_BREAKDOWN : SND_35_COMEDY_BREAKDOWN , v ) ;
2004-08-09 17:04:08 +00:00
if ( ! ( v - > vehstatus & VS_HIDDEN ) ) {
Vehicle * u = CreateEffectVehicleRel ( v , 4 , 4 , 5 , EV_BREAKDOWN_SMOKE ) ;
if ( u )
u - > u . special . unk0 = v - > breakdown_delay * 2 ;
}
}
if ( ! ( v - > tick_counter & 1 ) ) {
if ( ! - - v - > breakdown_delay ) {
v - > breakdown_ctr = 0 ;
InvalidateWindow ( WC_VEHICLE_VIEW , v - > index ) ;
}
}
}
static void ProcessRoadVehOrder ( Vehicle * v )
{
2005-01-15 19:06:22 +00:00
const Order * order ;
const Station * st ;
2004-08-09 17:04:08 +00:00
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type > = OT_GOTO_DEPOT & & v - > current_order . type < = OT_LEAVESTATION ) {
2005-01-15 19:06:22 +00:00
// Let a depot order in the orderlist interrupt.
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type ! = OT_GOTO_DEPOT | |
! ( v - > current_order . flags & OF_UNLOAD ) )
2004-08-09 17:04:08 +00:00
return ;
}
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT & &
( v - > current_order . flags & ( OF_UNLOAD | OF_FULL_LOAD ) ) = = ( OF_UNLOAD | OF_FULL_LOAD ) & &
2005-01-28 17:31:42 +00:00
! VehicleNeedsService ( v ) & & ! v - > set_for_replacement ) {
2004-08-09 17:04:08 +00:00
v - > cur_order_index + + ;
}
if ( v - > cur_order_index > = v - > num_orders )
v - > cur_order_index = 0 ;
2005-01-15 19:06:22 +00:00
order = GetVehicleOrder ( v , v - > cur_order_index ) ;
2004-08-09 17:04:08 +00:00
2005-01-15 19:06:22 +00:00
if ( order = = NULL ) {
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_NOTHING ;
v - > current_order . flags = 0 ;
2004-08-09 17:04:08 +00:00
v - > dest_tile = 0 ;
return ;
}
2005-01-15 19:06:22 +00:00
if ( order - > type = = v - > current_order . type & &
order - > flags = = v - > current_order . flags & &
order - > station = = v - > current_order . station )
2004-08-09 17:04:08 +00:00
return ;
2005-01-15 19:06:22 +00:00
v - > current_order = * order ;
2004-08-09 17:04:08 +00:00
v - > dest_tile = 0 ;
2005-01-15 19:06:22 +00:00
if ( order - > type = = OT_GOTO_STATION ) {
if ( order - > station = = v - > last_station_visited )
2005-02-02 16:16:43 +00:00
v - > last_station_visited = INVALID_STATION ;
2005-01-15 19:06:22 +00:00
st = GetStation ( order - > station ) ;
2005-01-29 19:41:44 +00:00
{
int32 * dist ;
int32 mindist = 0xFFFFFFFF ;
int num ;
RoadStopType type ;
RoadStop * rs ;
type = ( v - > cargo_type = = CT_PASSENGERS ) ? RS_BUS : RS_TRUCK ;
num = GetNumRoadStops ( st , type ) ;
rs = GetPrimaryRoadStop ( st , type ) ;
2005-01-30 17:46:57 +00:00
if ( rs = = NULL ) {
//There is no stop left at the station, so don't even TRY to go there
v - > cur_order_index + + ;
InvalidateVehicleOrder ( v ) ;
return ;
}
2005-01-29 19:41:44 +00:00
dist = malloc ( num * sizeof ( int32 ) ) ;
do {
2005-01-31 07:23:15 +00:00
* dist = DistanceSquare ( v - > tile , rs - > xy ) ;
2005-01-29 19:41:44 +00:00
if ( * dist < mindist ) {
v - > dest_tile = rs - > xy ;
}
rs = rs - > next ;
} while ( rs ! = NULL ) ;
free ( dist ) ;
dist = NULL ;
}
2005-01-15 19:06:22 +00:00
} else if ( order - > type = = OT_GOTO_DEPOT ) {
v - > dest_tile = _depots [ order - > station ] . xy ;
2004-08-09 17:04:08 +00:00
}
2005-01-15 19:06:22 +00:00
InvalidateVehicleOrder ( v ) ;
2004-08-09 17:04:08 +00:00
}
static void HandleRoadVehLoading ( Vehicle * v )
{
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_NOTHING )
2004-08-09 17:04:08 +00:00
return ;
2004-09-10 19:02:27 +00:00
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type ! = OT_DUMMY ) {
if ( v - > current_order . type ! = OT_LOADING )
2004-08-09 17:04:08 +00:00
return ;
if ( - - v - > load_unload_time_rem )
return ;
2004-12-05 12:43:04 +00:00
if ( v - > current_order . flags & OF_FULL_LOAD & & CanFillVehicle ( v ) ) {
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_ROADVEH_INC ) ;
if ( LoadUnloadVehicle ( v ) ) {
InvalidateWindow ( WC_ROADVEH_LIST , v - > owner ) ;
MarkRoadVehDirty ( v ) ;
}
return ;
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
{
2004-12-05 12:43:04 +00:00
Order b = v - > current_order ;
v - > current_order . type = OT_LEAVESTATION ;
v - > current_order . flags = 0 ;
if ( ! ( b . flags & OF_NON_STOP ) )
2004-08-09 17:04:08 +00:00
return ;
}
}
v - > cur_order_index + + ;
2005-01-15 19:06:22 +00:00
InvalidateVehicleOrder ( v ) ;
2005-01-28 17:31:42 +00:00
if ( v - > current_order . type ! = OT_GOTO_DEPOT & & v - > owner = = _local_player ) {
// only the vehicle owner needs to calculate the rest (locally)
if ( ( _autoreplace_array [ v - > engine_type ] ! = v - > engine_type ) | |
( _patches . autorenew & & v - > age - v - > max_age > ( _patches . autorenew_months * 30 ) ) ) {
byte flags = 1 ;
// the flags means, bit 0 = needs to go to depot, bit 1 = have depot in orders
if ( VehicleHasDepotOrders ( v ) ) SETBIT ( flags , 1 ) ;
if ( ! ( HASBIT ( flags , 1 ) & & v - > set_for_replacement ) ) {
_current_player = _local_player ;
DoCommandP ( v - > tile , v - > index , flags , NULL , CMD_SEND_ROADVEH_TO_DEPOT | CMD_SHOW_NO_ERROR ) ;
_current_player = OWNER_NONE ;
}
2005-01-29 01:02:47 +00:00
} else { // no need to go to a depot
if ( v - > set_for_replacement ) {
// it seems that the user clicked "Stop replacing"
_current_player = _local_player ;
DoCommandP ( v - > tile , v - > index , 1 | ( 1 < < 2 ) , NULL , CMD_SEND_ROADVEH_TO_DEPOT | CMD_SHOW_NO_ERROR ) ;
_current_player = OWNER_NONE ;
}
2005-01-28 17:31:42 +00:00
}
}
2004-08-09 17:04:08 +00:00
}
static void StartRoadVehSound ( Vehicle * v )
{
2004-12-04 09:26:39 +00:00
SoundFx s = RoadVehInfo ( v - > engine_type ) - > sfx ;
if ( s = = SND_19_BUS_START_PULL_AWAY & & ( v - > tick_counter & 3 ) = = 0 )
s = SND_1A_BUS_START_PULL_AWAY_WITH_HORN ;
2004-08-09 17:04:08 +00:00
SndPlayVehicleFx ( s , v ) ;
}
typedef struct RoadVehFindData {
int x , y ;
Vehicle * veh ;
byte dir ;
} RoadVehFindData ;
2005-01-22 22:47:58 +00:00
static void * EnumCheckRoadVehClose ( Vehicle * v , RoadVehFindData * rvf )
2004-08-09 17:04:08 +00:00
{
2004-09-10 19:02:27 +00:00
static const short _dists [ ] = {
2004-08-16 13:31:18 +00:00
- 4 , - 8 , - 4 , - 1 , 4 , 8 , 4 , 1 ,
- 4 , - 1 , 4 , 8 , 4 , 1 , - 4 , - 8 ,
2004-08-09 17:04:08 +00:00
} ;
2004-09-10 19:02:27 +00:00
2004-08-16 13:31:18 +00:00
short x_diff = v - > x_pos - rvf - > x ;
short y_diff = v - > y_pos - rvf - > y ;
2004-08-09 17:04:08 +00:00
2004-09-10 19:02:27 +00:00
if ( rvf - > veh = = v | |
v - > type ! = VEH_Road | |
2004-08-09 17:04:08 +00:00
v - > u . road . state = = 254 | |
myabs ( v - > z_pos - rvf - > veh - > z_pos ) > 6 | |
v - > direction ! = rvf - > dir | |
2004-08-16 13:31:18 +00:00
( _dists [ v - > direction ] < 0 & & ( x_diff < = _dists [ v - > direction ] | | x_diff > 0 ) ) | |
( _dists [ v - > direction ] > 0 & & ( x_diff > = _dists [ v - > direction ] | | x_diff < 0 ) ) | |
( _dists [ v - > direction + 8 ] < 0 & & ( y_diff < = _dists [ v - > direction + 8 ] | | y_diff > 0 ) ) | |
( _dists [ v - > direction + 8 ] > 0 & & ( y_diff > = _dists [ v - > direction + 8 ] | | y_diff < 0 ) ) )
2005-01-24 22:24:47 +00:00
return NULL ;
2004-08-09 17:04:08 +00:00
return v ;
}
static Vehicle * RoadVehFindCloseTo ( Vehicle * v , int x , int y , byte dir )
{
RoadVehFindData rvf ;
Vehicle * u ;
if ( v - > u . road . reverse_ctr ! = 0 )
return NULL ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
rvf . x = x ;
rvf . y = y ;
rvf . dir = dir ;
rvf . veh = v ;
u = VehicleFromPos ( TILE_FROM_XY ( x , y ) , & rvf , ( VehicleFromPosProc * ) EnumCheckRoadVehClose ) ;
2004-09-10 19:02:27 +00:00
2004-08-16 13:31:18 +00:00
// This code protects a roadvehicle from being blocked for ever
2004-12-29 13:13:29 +00:00
// If more than 1480 / 74 days a road vehicle is blocked, it will
2004-08-16 13:31:18 +00:00
// drive just through it. The ultimate backup-code of TTD.
// It can be disabled.
2004-08-09 17:04:08 +00:00
if ( u = = NULL ) {
v - > u . road . unk2 = 0 ;
return NULL ;
}
if ( + + v - > u . road . unk2 > 1480 )
return NULL ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
return u ;
}
static void RoadVehArrivesAt ( Vehicle * v , Station * st )
{
if ( v - > engine_type < 123 ) {
/* Check if station was ever visited before */
if ( ! ( st - > had_vehicle_of_type & HVOT_BUS ) ) {
uint32 flags ;
st - > had_vehicle_of_type | = HVOT_BUS ;
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , st - > index ) ;
2004-08-09 17:04:08 +00:00
flags = ( v - > owner = = _local_player ) ? NEWS_FLAGS ( NM_THIN , NF_VIEWPORT | NF_VEHICLE , NT_ARRIVAL_PLAYER , 0 ) : NEWS_FLAGS ( NM_THIN , NF_VIEWPORT | NF_VEHICLE , NT_ARRIVAL_OTHER , 0 ) ;
AddNewsItem (
STR_902F_CITIZENS_CELEBRATE_FIRST ,
flags ,
v - > index ,
0 ) ;
}
} else {
/* Check if station was ever visited before */
if ( ! ( st - > had_vehicle_of_type & HVOT_TRUCK ) ) {
uint32 flags ;
st - > had_vehicle_of_type | = HVOT_TRUCK ;
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , st - > index ) ;
2004-08-09 17:04:08 +00:00
flags = ( v - > owner = = _local_player ) ? NEWS_FLAGS ( NM_THIN , NF_VIEWPORT | NF_VEHICLE , NT_ARRIVAL_PLAYER , 0 ) : NEWS_FLAGS ( NM_THIN , NF_VIEWPORT | NF_VEHICLE , NT_ARRIVAL_OTHER , 0 ) ;
AddNewsItem (
STR_9030_CITIZENS_CELEBRATE_FIRST ,
flags ,
v - > index ,
0 ) ;
}
}
}
static bool RoadVehAccelerate ( Vehicle * v )
{
uint spd = v - > cur_speed + 1 + ( ( v - > u . road . overtaking ! = 0 ) ? 1 : 0 ) ;
byte t ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// Clamp
spd = min ( spd , v - > max_speed ) ;
//updates statusbar only if speed have changed to save CPU time
if ( spd ! = v - > cur_speed ) {
2004-09-10 19:02:27 +00:00
v - > cur_speed = spd ;
2004-08-09 17:04:08 +00:00
if ( _patches . vehicle_speed )
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
// Decrease somewhat when turning
if ( ! ( v - > direction & 1 ) )
spd = spd * 3 > > 2 ;
if ( spd = = 0 )
return false ;
if ( ( byte ) + + spd = = 0 )
return true ;
v - > progress = ( t = v - > progress ) - ( byte ) spd ;
return ( t < v - > progress ) ;
}
static byte RoadVehGetNewDirection ( Vehicle * v , int x , int y )
{
static const byte _roadveh_new_dir [ 11 ] = {
0 , 7 , 6 , 0 ,
1 , 0 , 5 , 0 ,
2 , 3 , 4
} ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
x = x - v - > x_pos + 1 ;
y = y - v - > y_pos + 1 ;
if ( ( uint ) x > 2 | | ( uint ) y > 2 )
return v - > direction ;
return _roadveh_new_dir [ y * 4 + x ] ;
}
static byte RoadVehGetSlidingDirection ( Vehicle * v , int x , int y )
{
byte b = RoadVehGetNewDirection ( v , x , y ) ;
byte d = v - > direction ;
if ( b = = d ) return d ;
d = ( d + 1 ) & 7 ;
if ( b = = d ) return d ;
d = ( d - 2 ) & 7 ;
if ( b = = d ) return d ;
if ( b = = ( ( d - 1 ) & 7 ) ) return d ;
if ( b = = ( ( d - 2 ) & 7 ) ) return d ;
2004-09-10 19:02:27 +00:00
return ( d + 2 ) & 7 ;
2004-08-09 17:04:08 +00:00
}
typedef struct OvertakeData {
Vehicle * u , * v ;
uint tile ;
byte tilebits ;
} OvertakeData ;
2005-01-22 22:47:58 +00:00
static void * EnumFindVehToOvertake ( Vehicle * v , OvertakeData * od )
2004-08-09 17:04:08 +00:00
{
if ( v - > tile ! = ( TileIndex ) od - > tile | |
2004-09-10 19:02:27 +00:00
v - > type ! = VEH_Road | |
v = = od - > u | |
2004-08-09 17:04:08 +00:00
v = = od - > v )
return NULL ;
2004-09-10 19:02:27 +00:00
return v ;
2004-08-09 17:04:08 +00:00
}
static bool FindRoadVehToOvertake ( OvertakeData * od )
{
uint32 bits ;
2004-09-05 16:15:22 +00:00
bits = GetTileTrackStatus ( od - > tile , TRANSPORT_ROAD ) & 0x3F ;
2004-08-09 17:04:08 +00:00
if ( ! ( od - > tilebits & bits ) | | ( bits & 0x3C ) | | ( bits & 0x3F3F0000 ) )
return true ;
return VehicleFromPos ( od - > tile , od , ( VehicleFromPosProc * ) EnumFindVehToOvertake ) ! = NULL ;
}
static void RoadVehCheckOvertake ( Vehicle * v , Vehicle * u )
{
OvertakeData od ;
byte tt ;
od . v = v ;
od . u = u ;
if ( u - > max_speed > = v - > max_speed & &
! ( u - > vehstatus & VS_STOPPED ) & &
u - > cur_speed ! = 0 )
return ;
if ( v - > direction ! = u - > direction | | ! ( v - > direction & 1 ) )
return ;
if ( v - > u . road . state > = 32 | | ( v - > u . road . state & 7 ) > 1 )
return ;
2004-09-05 16:15:22 +00:00
tt = ( byte ) ( GetTileTrackStatus ( v - > tile , TRANSPORT_ROAD ) & 0x3F ) ;
2004-08-09 17:04:08 +00:00
if ( ( tt & 3 ) = = 0 )
return ;
if ( ( tt & 0x3C ) ! = 0 )
return ;
if ( tt = = 3 ) {
tt = ( v - > direction & 2 ) ? 2 : 1 ;
}
od . tilebits = tt ;
od . tile = v - > tile ;
if ( FindRoadVehToOvertake ( & od ) )
return ;
2005-01-05 13:32:03 +00:00
od . tile = v - > tile + TileOffsByDir ( v - > direction > > 1 ) ;
2004-08-09 17:04:08 +00:00
if ( FindRoadVehToOvertake ( & od ) )
return ;
if ( od . u - > cur_speed = = 0 | | od . u - > vehstatus & VS_STOPPED ) {
v - > u . road . overtaking_ctr = 0x11 ;
v - > u . road . overtaking = 0x10 ;
} else {
// if (FindRoadVehToOvertake(&od))
// return;
v - > u . road . overtaking_ctr = 0 ;
v - > u . road . overtaking = 0x10 ;
}
}
static void RoadZPosAffectSpeed ( Vehicle * v , byte old_z )
{
if ( old_z = = v - > z_pos )
return ;
if ( old_z < v - > z_pos ) {
v - > cur_speed = v - > cur_speed * 232 > > 8 ;
} else {
uint16 spd = v - > cur_speed + 2 ;
if ( spd < = v - > max_speed )
v - > cur_speed = spd ;
}
}
static int PickRandomBit ( uint bits )
{
uint num = 0 ;
uint b = bits ;
uint i ;
do {
if ( b & 1 )
num + + ;
} while ( b > > = 1 ) ;
num = ( ( uint16 ) Random ( ) * num > > 16 ) ;
for ( i = 0 ; ! ( ( bits & 1 ) & & ( ( int ) - - num ) < 0 ) ; bits > > = 1 , i + + ) ;
return i ;
}
typedef struct {
TileIndex dest ;
uint maxtracklen ;
uint mindist ;
} FindRoadToChooseData ;
static bool EnumRoadTrackFindDist ( uint tile , FindRoadToChooseData * frd , int track , uint length , byte * state )
{
2005-01-31 07:23:15 +00:00
uint dist = DistanceManhattan ( tile , frd - > dest ) ;
2004-08-09 17:04:08 +00:00
if ( dist < = frd - > mindist ) {
if ( dist ! = frd - > mindist | | length < frd - > maxtracklen ) {
frd - > maxtracklen = length ;
}
frd - > mindist = dist ;
}
return false ;
}
// Returns direction to choose
// or -1 if the direction is currently blocked
2005-01-31 11:23:10 +00:00
static int RoadFindPathToDest ( Vehicle * v , uint tile , int enterdir )
2004-08-09 17:04:08 +00:00
{
# define return_track(x) {best_track = x; goto found_best_track; }
uint16 signal ;
uint bitmask ;
uint desttile ;
FindRoadToChooseData frd ;
int best_track ;
uint best_dist , best_maxlen ;
uint i ;
byte m5 ;
{
uint32 r ;
2004-09-14 01:21:07 +00:00
r = GetTileTrackStatus ( tile , TRANSPORT_ROAD ) ;
2004-08-09 17:04:08 +00:00
signal = ( uint16 ) ( r > > 16 ) ;
bitmask = ( uint16 ) r ;
}
2005-01-16 11:24:58 +00:00
if ( IsTileType ( tile , MP_STREET ) ) {
2004-09-14 01:21:07 +00:00
if ( ( _map5 [ tile ] & 0xF0 ) = = 0x20 & & v - > owner = = _map_owner [ tile ] )
/* Road crossing */
bitmask | = _road_veh_fp_ax_or [ _map5 [ tile ] & 3 ] ;
2005-01-16 11:24:58 +00:00
} else if ( IsTileType ( tile , MP_STATION ) ) {
2004-09-14 01:21:07 +00:00
if ( _map_owner [ tile ] = = OWNER_NONE | | _map_owner [ tile ] = = v - > owner ) {
/* Our station */
2005-01-06 22:31:58 +00:00
Station * st = GetStation ( _map2 [ tile ] ) ;
2004-09-14 01:21:07 +00:00
byte val = _map5 [ tile ] ;
if ( v - > cargo_type ! = CT_PASSENGERS ) {
2005-01-29 19:41:44 +00:00
if ( IS_BYTE_INSIDE ( val , 0x43 , 0x47 ) & & ( _patches . roadveh_queue | | st - > truck_stops - > status & 3 ) )
2004-09-14 01:21:07 +00:00
bitmask | = _road_veh_fp_ax_or [ ( val - 0x43 ) & 3 ] ;
} else {
2005-01-29 19:41:44 +00:00
if ( IS_BYTE_INSIDE ( val , 0x47 , 0x4B ) & & ( _patches . roadveh_queue | | st - > bus_stops - > status & 3 ) )
2004-09-14 01:21:07 +00:00
bitmask | = _road_veh_fp_ax_or [ ( val - 0x47 ) & 3 ] ;
}
}
}
/* The above lookups should be moved to GetTileTrackStatus in the
* future , but that requires more changes to the pathfinder and other
* stuff , probably even more arguments to GTTS .
*/
2004-09-05 16:15:22 +00:00
/* remove unreachable tracks */
2005-01-31 11:23:10 +00:00
bitmask & = _road_veh_fp_ax_and [ enterdir ] ;
2004-08-09 17:04:08 +00:00
if ( bitmask = = 0 ) {
2005-01-31 11:23:10 +00:00
/* No reachable tracks, so we'll reverse */
return_track ( _road_reverse_table [ enterdir ] ) ;
2004-08-09 17:04:08 +00:00
}
if ( v - > u . road . reverse_ctr ! = 0 ) {
2005-01-31 11:23:10 +00:00
/* What happens here?? */
2004-08-09 17:04:08 +00:00
v - > u . road . reverse_ctr = 0 ;
if ( v - > tile ! = ( TileIndex ) tile ) {
2005-01-31 11:23:10 +00:00
return_track ( _road_reverse_table [ enterdir ] ) ;
2004-08-09 17:04:08 +00:00
}
}
desttile = v - > dest_tile ;
if ( desttile = = 0 ) {
2005-01-31 11:23:10 +00:00
// Pick a random track
2004-08-09 17:04:08 +00:00
return_track ( PickRandomBit ( bitmask ) ) ;
}
2005-01-31 11:23:10 +00:00
// Only one track to choose between?
if ( ! ( KillFirstBit2x64 ( bitmask ) ) ) {
2004-08-09 17:04:08 +00:00
return_track ( FindFirstBit2x64 ( bitmask ) ) ;
}
2005-01-31 11:23:10 +00:00
if ( _patches . new_pathfinding_all ) {
NPFFindStationOrTileData fstd ;
NPFFoundTargetData ftd ;
byte trackdir ;
NPFFillWithOrderData ( & fstd , v ) ;
trackdir = _dir_to_diag_trackdir [ enterdir ] ;
//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
ftd = NPFRouteToStationOrTile ( tile - TileOffsByDir ( enterdir ) , trackdir , & fstd , TRANSPORT_ROAD ) ;
if ( ftd . best_bird_dist ! = 0 | | ftd . best_trackdir = = 0xff ) {
/* Not found, just do something, or we are already there */
//TODO: maybe display error?
//TODO: go straight ahead if possible?
return_track ( FindFirstBit2x64 ( bitmask ) ) ;
} else {
return_track ( ftd . best_trackdir ) ;
}
} else {
if ( IsTileType ( desttile , MP_STREET ) ) {
m5 = _map5 [ desttile ] ;
if ( ( m5 & 0xF0 ) = = 0x20 )
/* We are heading for a Depot */
goto do_it ;
} else if ( IsTileType ( desttile , MP_STATION ) ) {
m5 = _map5 [ desttile ] ;
if ( IS_BYTE_INSIDE ( m5 , 0x43 , 0x4B ) ) {
/* We are heading for a station */
m5 - = 0x43 ;
2004-08-09 17:04:08 +00:00
do_it : ;
2005-01-31 11:23:10 +00:00
/* When we are heading for a depot or station, we just
* pretend we are heading for the tile in front , we ' ll
* see from there */
desttile + = TileOffsByDir ( m5 & 3 ) ;
if ( desttile = = tile & & bitmask & _road_pf_table_3 [ m5 & 3 ] ) {
/* If we are already in front of the
* station / depot and we can get in from here ,
* we enter */
return_track ( FindFirstBit2x64 ( bitmask & _road_pf_table_3 [ m5 & 3 ] ) ) ;
}
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
}
2005-01-31 11:23:10 +00:00
// do pathfind
frd . dest = desttile ;
best_track = - 1 ;
best_dist = ( uint ) - 1 ;
best_maxlen = ( uint ) - 1 ;
i = 0 ;
do {
if ( bitmask & 1 ) {
if ( best_track = = - 1 ) best_track = i ; // in case we don't find the path, just pick a track
frd . maxtracklen = ( uint ) - 1 ;
frd . mindist = ( uint ) - 1 ;
FollowTrack ( tile , 0x3000 | TRANSPORT_ROAD , _road_pf_directions [ i ] , ( TPFEnumProc * ) EnumRoadTrackFindDist , NULL , & frd ) ;
if ( frd . mindist < best_dist | | ( frd . mindist = = best_dist & & frd . maxtracklen < best_maxlen ) ) {
best_dist = frd . mindist ;
best_maxlen = frd . maxtracklen ;
best_track = i ;
}
2004-08-09 17:04:08 +00:00
}
2005-01-31 11:23:10 +00:00
} while ( + + i , ( bitmask > > = 1 ) ! = 0 ) ;
}
2004-08-09 17:04:08 +00:00
found_best_track : ;
if ( HASBIT ( signal , best_track ) )
return - 1 ;
2004-09-10 19:02:27 +00:00
return best_track ;
2004-08-09 17:04:08 +00:00
}
2005-01-29 19:41:44 +00:00
static int RoadFindPathToStation ( const Vehicle * v , TileIndex tile )
{
FindRoadToChooseData frd ;
int i , best_track = - 1 ;
uint best_dist = ( uint ) - 1 , best_maxlen = ( uint ) - 1 ;
frd . dest = tile ;
frd . maxtracklen = ( uint ) - 1 ;
frd . mindist = ( uint ) - 1 ;
for ( i = 0 ; i < 4 ; i + + ) {
FollowTrack ( v - > tile , 0x2000 | TRANSPORT_ROAD , i , ( TPFEnumProc * ) EnumRoadTrackFindDist , NULL , & frd ) ;
if ( frd . mindist < best_dist | | ( frd . mindist = = best_dist & & frd . maxtracklen < best_maxlen ) ) {
best_dist = frd . mindist ;
best_maxlen = frd . maxtracklen ;
best_track = i ;
}
}
return best_maxlen ;
}
2004-08-09 17:04:08 +00:00
typedef struct RoadDriveEntry {
byte x , y ;
} RoadDriveEntry ;
# include "table/roadveh.h"
static const byte _road_veh_data_1 [ ] = {
20 , 20 , 16 , 16 , 0 , 0 , 0 , 0 ,
19 , 19 , 15 , 15 , 0 , 0 , 0 , 0 ,
16 , 16 , 12 , 12 , 0 , 0 , 0 , 0 ,
15 , 15 , 11 , 11
} ;
static const byte _roadveh_data_2 [ 4 ] = { 0 , 1 , 8 , 9 } ;
2005-01-29 19:41:44 +00:00
static inline void ClearSlot ( Vehicle * v , RoadStop * rs )
{
v - > u . road . slot = NULL ;
v - > u . road . slot_age = 0 ;
rs - > slot [ v - > u . road . slotindex ] = INVALID_SLOT ;
}
2004-08-09 17:04:08 +00:00
static void RoadVehEventHandler ( Vehicle * v )
{
GetNewVehiclePosResult gp ;
2004-12-05 12:43:04 +00:00
byte new_dir , old_dir ;
2004-08-09 17:04:08 +00:00
RoadDriveEntry rd ;
int x , y ;
Station * st ;
uint32 r ;
Vehicle * u ;
// decrease counters
v - > tick_counter + + ;
if ( v - > u . road . reverse_ctr ! = 0 )
v - > u . road . reverse_ctr - - ;
// handle crashed
if ( v - > u . road . crashed_ctr ! = 0 ) {
RoadVehIsCrashed ( v ) ;
return ;
}
RoadVehCheckTrainCrash ( v ) ;
// road vehicle has broken down?
if ( v - > breakdown_ctr ! = 0 ) {
if ( v - > breakdown_ctr < = 2 ) {
HandleBrokenRoadVeh ( v ) ;
return ;
}
v - > breakdown_ctr - - ;
}
// exit if vehicle is stopped
if ( v - > vehstatus & VS_STOPPED )
return ;
ProcessRoadVehOrder ( v ) ;
HandleRoadVehLoading ( v ) ;
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_LOADING )
2004-08-09 17:04:08 +00:00
return ;
if ( v - > u . road . state = = 254 ) {
int dir ;
const RoadDriveEntry * rdp ;
byte rd2 ;
v - > cur_speed = 0 ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
dir = _map5 [ v - > tile ] & 3 ;
v - > direction = dir * 2 + 1 ;
rd2 = _roadveh_data_2 [ dir ] ;
rdp = _road_drive_data [ ( _opt . road_side < < 4 ) + rd2 ] ;
2004-09-10 19:02:27 +00:00
2005-01-07 17:02:43 +00:00
x = TileX ( v - > tile ) * 16 + ( rdp [ 6 ] . x & 0xF ) ;
y = TileY ( v - > tile ) * 16 + ( rdp [ 6 ] . y & 0xF ) ;
2004-08-09 17:04:08 +00:00
if ( RoadVehFindCloseTo ( v , x , y , v - > direction ) )
return ;
2004-12-09 21:46:56 +00:00
VehicleServiceInDepot ( v ) ;
2004-08-09 17:04:08 +00:00
StartRoadVehSound ( v ) ;
BeginVehicleMove ( v ) ;
v - > vehstatus & = ~ VS_HIDDEN ;
v - > u . road . state = rd2 ;
v - > u . road . frame = 6 ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
v - > cur_image = GetRoadVehImage ( v , v - > direction ) ;
UpdateRoadVehDeltaXY ( v ) ;
SetRoadVehPosition ( v , x , y ) ;
InvalidateWindow ( WC_VEHICLE_DEPOT , v - > tile ) ;
return ;
}
if ( ! RoadVehAccelerate ( v ) )
return ;
if ( v - > u . road . overtaking ! = 0 ) {
if ( + + v - > u . road . overtaking_ctr > = 35 )
v - > u . road . overtaking = 0 ;
}
BeginVehicleMove ( v ) ;
if ( v - > u . road . state = = 255 ) {
GetNewVehiclePos ( v , & gp ) ;
if ( RoadVehFindCloseTo ( v , gp . x , gp . y , v - > direction ) ) {
v - > cur_speed = 0 ;
return ;
}
2005-01-16 11:24:58 +00:00
if ( IsTileType ( gp . new_tile , MP_TUNNELBRIDGE ) & &
2004-08-09 17:04:08 +00:00
( _map5 [ gp . new_tile ] & 0xF0 ) = = 0 & &
( VehicleEnterTile ( v , gp . new_tile , gp . x , gp . y ) & 4 ) ) {
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
//new_dir = RoadGetNewDirection(v, gp.x, gp.y)
v - > cur_image = GetRoadVehImage ( v , v - > direction ) ;
UpdateRoadVehDeltaXY ( v ) ;
SetRoadVehPosition ( v , gp . x , gp . y ) ;
return ;
}
v - > x_pos = gp . x ;
v - > y_pos = gp . y ;
VehiclePositionChanged ( v ) ;
return ;
}
rd = _road_drive_data [ ( v - > u . road . state + ( _opt . road_side < < 4 ) ) ^ v - > u . road . overtaking ] [ v - > u . road . frame + 1 ] ;
// switch to another tile
if ( rd . x & 0x80 ) {
2005-01-05 13:32:03 +00:00
uint tile = v - > tile + TileOffsByDir ( rd . x & 3 ) ;
2004-08-09 17:04:08 +00:00
int dir = RoadFindPathToDest ( v , tile , rd . x & 3 ) ;
int tmp ;
uint32 r ;
byte newdir ;
const RoadDriveEntry * rdp ;
if ( dir = = - 1 ) {
v - > cur_speed = 0 ;
return ;
}
again :
if ( ( dir & 7 ) > = 6 ) {
2005-01-31 11:23:10 +00:00
/* Turning around */
2004-08-09 17:04:08 +00:00
tile = v - > tile ;
}
tmp = ( dir + ( _opt . road_side < < 4 ) ) ^ v - > u . road . overtaking ;
rdp = _road_drive_data [ tmp ] ;
tmp & = ~ 0x10 ;
2005-01-07 17:02:43 +00:00
x = TileX ( tile ) * 16 + rdp [ 0 ] . x ;
y = TileY ( tile ) * 16 + rdp [ 0 ] . y ;
2004-08-09 17:04:08 +00:00
if ( RoadVehFindCloseTo ( v , x , y , newdir = RoadVehGetSlidingDirection ( v , x , y ) ) )
return ;
r = VehicleEnterTile ( v , tile , x , y ) ;
if ( r & 8 ) {
2005-01-16 11:24:58 +00:00
if ( ! IsTileType ( tile , MP_TUNNELBRIDGE ) ) {
2004-08-09 17:04:08 +00:00
v - > cur_speed = 0 ;
return ;
}
dir = _road_reverse_table [ rd . x & 3 ] ;
goto again ;
}
2005-01-16 11:24:58 +00:00
if ( IS_BYTE_INSIDE ( v - > u . road . state , 0x20 , 0x30 ) & & IsTileType ( v - > tile , MP_STATION ) ) {
2004-08-09 17:04:08 +00:00
if ( ( tmp & 7 ) > = 6 ) { v - > cur_speed = 0 ; return ; }
if ( IS_BYTE_INSIDE ( _map5 [ v - > tile ] , 0x43 , 0x4B ) ) {
2005-01-29 19:41:44 +00:00
RoadStop * rs = GetRoadStopByTile ( v - > tile , GetRoadStopType ( v - > tile ) ) ;
byte * b = & rs - > status ;
2004-08-09 17:04:08 +00:00
2005-01-29 19:41:44 +00:00
//we have reached a loading bay, mark it as used
//and clear the usage bit (0x80) of the stop
* b = ( * b | ( ( v - > u . road . state & 2 ) ? 2 : 1 ) ) & ~ 0x80 ;
2004-08-09 17:04:08 +00:00
}
}
if ( ! ( r & 4 ) ) {
v - > tile = tile ;
v - > u . road . state = ( byte ) tmp ;
v - > u . road . frame = 0 ;
}
if ( newdir ! = v - > direction ) {
v - > direction = newdir ;
v - > cur_speed - = v - > cur_speed > > 2 ;
}
v - > cur_image = GetRoadVehImage ( v , newdir ) ;
UpdateRoadVehDeltaXY ( v ) ;
RoadZPosAffectSpeed ( v , SetRoadVehPosition ( v , x , y ) ) ;
return ;
}
if ( rd . x & 0x40 ) {
int dir = RoadFindPathToDest ( v , v - > tile , rd . x & 3 ) ;
uint32 r ;
int tmp ;
byte newdir ;
const RoadDriveEntry * rdp ;
if ( dir = = - 1 ) {
v - > cur_speed = 0 ;
return ;
}
tmp = ( _opt . road_side < < 4 ) + dir ;
rdp = _road_drive_data [ tmp ] ;
2005-01-07 17:02:43 +00:00
x = TileX ( v - > tile ) * 16 + rdp [ 1 ] . x ;
y = TileY ( v - > tile ) * 16 + rdp [ 1 ] . y ;
2004-08-09 17:04:08 +00:00
if ( RoadVehFindCloseTo ( v , x , y , newdir = RoadVehGetSlidingDirection ( v , x , y ) ) )
return ;
r = VehicleEnterTile ( v , v - > tile , x , y ) ;
if ( r & 8 ) {
v - > cur_speed = 0 ;
return ;
}
v - > u . road . state = tmp & ~ 16 ;
v - > u . road . frame = 1 ;
if ( newdir ! = v - > direction ) {
v - > direction = newdir ;
v - > cur_speed - = v - > cur_speed > > 2 ;
}
v - > cur_image = GetRoadVehImage ( v , newdir ) ;
UpdateRoadVehDeltaXY ( v ) ;
RoadZPosAffectSpeed ( v , SetRoadVehPosition ( v , x , y ) ) ;
return ;
}
x = ( v - > x_pos & ~ 15 ) + ( rd . x & 15 ) ;
y = ( v - > y_pos & ~ 15 ) + ( rd . y & 15 ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
new_dir = RoadVehGetSlidingDirection ( v , x , y ) ;
if ( ! IS_BYTE_INSIDE ( v - > u . road . state , 0x20 , 0x30 ) & & ( u = RoadVehFindCloseTo ( v , x , y , new_dir ) ) ! = NULL ) {
if ( v - > u . road . overtaking = = 0 )
RoadVehCheckOvertake ( v , u ) ;
return ;
}
old_dir = v - > direction ;
if ( new_dir ! = old_dir ) {
v - > direction = new_dir ;
v - > cur_speed - = ( v - > cur_speed > > 2 ) ;
if ( old_dir ! = v - > u . road . state ) {
v - > cur_image = GetRoadVehImage ( v , new_dir ) ;
UpdateRoadVehDeltaXY ( v ) ;
SetRoadVehPosition ( v , v - > x_pos , v - > y_pos ) ;
return ;
}
}
if ( v - > u . road . state > = 0x20 & &
_road_veh_data_1 [ v - > u . road . state - 0x20 + ( _opt . road_side < < 4 ) ] = = v - > u . road . frame ) {
2005-01-29 19:41:44 +00:00
RoadStop * rs = GetRoadStopByTile ( v - > tile , GetRoadStopType ( v - > tile ) ) ;
byte * b = & rs - > status ;
2004-08-09 17:04:08 +00:00
2005-01-06 22:31:58 +00:00
st = GetStation ( _map2 [ v - > tile ] ) ;
2004-08-09 17:04:08 +00:00
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type ! = OT_LEAVESTATION & &
v - > current_order . type ! = OT_GOTO_DEPOT ) {
Order old_order ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
* b & = ~ 0x80 ;
v - > last_station_visited = _map2 [ v - > tile ] ;
RoadVehArrivesAt ( v , st ) ;
2004-12-05 12:43:04 +00:00
old_order = v - > current_order ;
v - > current_order . type = OT_LOADING ;
v - > current_order . flags = 0 ;
2004-08-09 17:04:08 +00:00
2004-12-05 12:43:04 +00:00
if ( old_order . type = = OT_GOTO_STATION & &
v - > current_order . station = = v - > last_station_visited ) {
v - > current_order . flags =
( old_order . flags & ( OF_FULL_LOAD | OF_UNLOAD ) ) | OF_NON_STOP ;
2004-08-09 17:04:08 +00:00
}
SET_EXPENSES_TYPE ( EXPENSES_ROADVEH_INC ) ;
if ( LoadUnloadVehicle ( v ) ) {
InvalidateWindow ( WC_ROADVEH_LIST , v - > owner ) ;
MarkRoadVehDirty ( v ) ;
}
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
return ;
}
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type ! = OT_GOTO_DEPOT ) {
2004-08-09 17:04:08 +00:00
if ( * b & 0x80 ) {
v - > cur_speed = 0 ;
return ;
}
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_NOTHING ;
v - > current_order . flags = 0 ;
2004-08-09 17:04:08 +00:00
}
* b | = 0x80 ;
2005-01-29 19:41:44 +00:00
if ( rs = = v - > u . road . slot ) {
//we have arrived at the correct station
ClearSlot ( v , rs ) ;
} else if ( v - > u . road . slot ! = NULL ) {
//we have arrived at the wrong station
//XXX The question is .. what to do? Actually we shouldn't be here
//but I guess we need to clear the slot
2005-01-30 22:04:14 +00:00
DEBUG ( misc , 1 ) ( " Multistop: Wrong station, force a slot clearing. Vehicle %d at 0x%x, should go to 0x%x of station %d (%x), destination 0x%x " , v - > unitnumber , v - > tile , v - > u . road . slot - > xy , st - > index , st - > xy , v - > dest_tile ) ;
ClearSlot ( v , v - > u . road . slot ) ;
2005-01-29 19:41:44 +00:00
}
2004-08-09 17:04:08 +00:00
StartRoadVehSound ( v ) ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
r = VehicleEnterTile ( v , v - > tile , x , y ) ;
if ( r & 8 ) {
v - > cur_speed = 0 ;
return ;
}
if ( ( r & 4 ) = = 0 ) {
v - > u . road . frame + + ;
}
v - > cur_image = GetRoadVehImage ( v , v - > direction ) ;
UpdateRoadVehDeltaXY ( v ) ;
RoadZPosAffectSpeed ( v , SetRoadVehPosition ( v , x , y ) ) ;
}
void RoadVehEnterDepot ( Vehicle * v )
{
v - > u . road . state = 254 ;
v - > vehstatus | = VS_HIDDEN ;
InvalidateWindow ( WC_VEHICLE_DETAILS , v - > index ) ;
2005-01-02 17:23:04 +00:00
MaybeReplaceVehicle ( v ) ;
2004-08-09 17:04:08 +00:00
2004-12-09 21:46:56 +00:00
VehicleServiceInDepot ( v ) ;
2004-11-17 08:52:47 +00:00
TriggerVehicle ( v , VEHICLE_TRIGGER_DEPOT ) ;
2004-09-10 19:02:27 +00:00
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT ) {
Order t ;
2004-08-09 17:04:08 +00:00
InvalidateWindow ( WC_VEHICLE_VIEW , v - > index ) ;
2004-09-10 19:02:27 +00:00
2004-12-05 12:43:04 +00:00
t = v - > current_order ;
v - > current_order . type = OT_DUMMY ;
v - > current_order . flags = 0 ;
2004-08-09 17:04:08 +00:00
2005-01-15 19:06:22 +00:00
// Part of the orderlist?
2004-12-05 12:43:04 +00:00
if ( t . flags & OF_UNLOAD ) {
v - > cur_order_index + + ;
} else if ( t . flags & OF_FULL_LOAD ) {
2004-08-09 17:04:08 +00:00
v - > vehstatus | = VS_STOPPED ;
if ( v - > owner = = _local_player ) {
2004-12-02 22:53:07 +00:00
SetDParam ( 0 , v - > unitnumber ) ;
2004-08-09 17:04:08 +00:00
AddNewsItem (
STR_9016_ROAD_VEHICLE_IS_WAITING ,
NEWS_FLAGS ( NM_SMALL , NF_VIEWPORT | NF_VEHICLE , NT_ADVICE , 0 ) ,
v - > index ,
0 ) ;
}
}
}
InvalidateWindow ( WC_VEHICLE_DEPOT , v - > tile ) ;
2005-01-24 22:24:47 +00:00
InvalidateWindowClasses ( WC_ROADVEH_LIST ) ;
2004-08-09 17:04:08 +00:00
}
static void AgeRoadVehCargo ( Vehicle * v )
{
if ( _age_cargo_skip_counter ! = 0 )
return ;
if ( v - > cargo_days ! = 255 )
v - > cargo_days + + ;
}
void RoadVeh_Tick ( Vehicle * v )
{
AgeRoadVehCargo ( v ) ;
RoadVehEventHandler ( v ) ;
}
static void CheckIfRoadVehNeedsService ( Vehicle * v )
{
int i ;
2005-01-28 17:31:42 +00:00
if ( _patches . servint_roadveh = = 0 & & ! v - > set_for_replacement )
2004-08-10 17:06:10 +00:00
return ;
2005-01-28 17:31:42 +00:00
if ( ! VehicleNeedsService ( v ) & & ! v - > set_for_replacement )
2004-08-09 17:04:08 +00:00
return ;
if ( v - > vehstatus & VS_STOPPED )
return ;
2005-01-15 19:06:22 +00:00
if ( _patches . gotodepot & & VehicleHasDepotOrders ( v ) )
2004-08-09 17:04:08 +00:00
return ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// Don't interfere with a depot visit scheduled by the user, or a
// depot visit by the order list.
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT & &
( v - > current_order . flags & ( OF_FULL_LOAD | OF_UNLOAD ) ) ! = 0 )
2004-08-09 17:04:08 +00:00
return ;
2005-01-29 19:41:44 +00:00
//If we already got a slot at a stop, use that FIRST, and go to a depot later
if ( v - > u . road . slot ! = NULL )
return ;
2004-08-09 17:04:08 +00:00
i = FindClosestRoadDepot ( v ) ;
2005-01-31 07:23:15 +00:00
if ( i < 0 | | DistanceManhattan ( v - > tile , ( & _depots [ i ] ) - > xy ) > 12 ) {
2005-01-28 17:31:42 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT & & ! (
2005-01-31 07:23:15 +00:00
DistanceManhattan ( v - > tile , v - > dest_tile ) > 25 & & v - > set_for_replacement ) ) {
2005-01-28 17:31:42 +00:00
/* a vehicle needs a greater distance to a depot to loose it than to find it since
they can circle forever othervise if they are in a loop with an unlucky distance */
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_DUMMY ;
v - > current_order . flags = 0 ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
return ;
}
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT & &
v - > current_order . flags & OF_NON_STOP & &
! CHANCE16 ( 1 , 20 ) )
2004-08-09 17:04:08 +00:00
return ;
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_GOTO_DEPOT ;
v - > current_order . flags = OF_NON_STOP ;
v - > current_order . station = ( byte ) i ;
2004-08-09 17:04:08 +00:00
v - > dest_tile = ( & _depots [ i ] ) - > xy ;
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-29 19:41:44 +00:00
int dist_compare ( const void * a , const void * b )
{
return ( * ( const uint32 * ) a ) - ( * ( const uint32 * ) b ) ;
}
2004-08-09 17:04:08 +00:00
void OnNewDay_RoadVeh ( Vehicle * v )
{
int32 cost ;
Station * st ;
if ( ( + + v - > day_counter & 7 ) = = 0 )
DecreaseVehicleValue ( v ) ;
if ( v - > u . road . unk2 = = 0 )
CheckVehicleBreakdown ( v ) ;
AgeVehicle ( v ) ;
CheckIfRoadVehNeedsService ( v ) ;
2005-01-17 21:54:45 +00:00
CheckOrders ( v - > index , OC_INIT ) ;
2004-08-11 10:15:38 +00:00
2004-08-09 17:04:08 +00:00
/* update destination */
2004-12-05 12:43:04 +00:00
if ( v - > current_order . type = = OT_GOTO_STATION ) {
2005-01-29 19:41:44 +00:00
RoadStop * rs ;
uint32 mindist = 0xFFFFFFFF ;
int num ;
RoadStopType type = ( v - > cargo_type = = CT_PASSENGERS ) ? RS_BUS : RS_TRUCK ;
typedef struct {
uint32 dist ;
RoadStop * rs ;
} StopStruct ;
StopStruct * stop , * firststop ;
2005-01-06 22:31:58 +00:00
st = GetStation ( v - > current_order . station ) ;
2005-01-29 19:41:44 +00:00
rs = GetPrimaryRoadStop ( st , type ) ;
num = GetNumRoadStops ( st , type ) ;
firststop = stop = malloc ( num * sizeof ( StopStruct ) ) ;
//Current slot has expired
if ( ( v - > u . road . slot_age + + < = 0 ) & & ( v - > u . road . slot ! = NULL ) ) {
ClearSlot ( v , v - > u . road . slot ) ;
}
//We do not have a slot, so make one
if ( v - > u . road . slot = = NULL ) {
//first we need to find out how far our stations are away.
2005-01-30 17:46:57 +00:00
if ( rs = = NULL )
goto no_stop ;
2005-01-29 19:41:44 +00:00
do {
stop - > dist = 0xFFFFFFFF ;
//FIXME This doesn't fully work yet, as it only goes
//to one tile BEFORE the stop in question and doesn't
//regard the direction of the exit
stop - > dist = RoadFindPathToStation ( v , rs - > xy ) ;
stop - > rs = rs ;
if ( stop - > dist < mindist ) {
mindist = stop - > dist ;
}
stop + + ;
rs = rs - > next ;
} while ( rs ! = NULL ) ;
if ( mindist < 120 ) { //if we're reasonably close, get us a slot
int k ;
bubblesort ( firststop , num , sizeof ( StopStruct ) , dist_compare ) ;
stop = firststop ;
for ( k = 0 ; k < num ; k + + ) {
int i ;
for ( i = 0 ; i < NUM_SLOTS ; i + + ) {
if ( ( stop - > rs - > slot [ i ] = = INVALID_SLOT ) & & ( stop - > dist < 120 ) ) {
//Hooray we found a free slot. Assign it
stop - > rs - > slot [ i ] = v - > index ;
v - > u . road . slot = stop - > rs ;
v - > dest_tile = stop - > rs - > xy ;
v - > u . road . slot_age = - 30 ;
v - > u . road . slotindex = i ;
goto have_slot ; //jump out of BOTH loops
}
}
stop + + ;
}
}
have_slot :
//now we couldn't assign a slot for one reason or another.
//so we just go to the nearest station
if ( v - > u . road . slot = = NULL )
v - > dest_tile = firststop - > rs - > xy ;
}
free ( firststop ) ;
firststop = stop = NULL ;
2004-08-09 17:04:08 +00:00
}
2005-01-30 17:46:57 +00:00
no_stop :
2004-08-09 17:04:08 +00:00
if ( v - > vehstatus & VS_STOPPED )
return ;
2004-12-03 21:57:05 +00:00
cost = RoadVehInfo ( v - > engine_type ) - > running_cost * _price . roadveh_running / 364 ;
2004-08-09 17:04:08 +00:00
v - > profit_this_year - = cost > > 8 ;
SET_EXPENSES_TYPE ( EXPENSES_ROADVEH_RUN ) ;
SubtractMoneyFromPlayerFract ( v - > owner , cost ) ;
InvalidateWindow ( WC_VEHICLE_DETAILS , v - > index ) ;
2005-01-24 22:24:47 +00:00
InvalidateWindowClasses ( WC_ROADVEH_LIST ) ;
2004-08-09 17:04:08 +00:00
}
void HandleClickOnRoadVeh ( Vehicle * v )
{
ShowRoadVehViewWindow ( v ) ;
}
2005-01-22 20:23:18 +00:00
void RoadVehiclesYearlyLoop ( void )
2004-08-09 17:04:08 +00:00
{
Vehicle * v ;
FOR_ALL_VEHICLES ( v ) {
if ( v - > type = = VEH_Road ) {
v - > profit_last_year = v - > profit_this_year ;
v - > profit_this_year = 0 ;
InvalidateWindow ( WC_VEHICLE_DETAILS , v - > index ) ;
}
}
}