2005-07-24 14:12:37 +00:00
/* $Id$ */
2004-08-09 17:04:08 +00:00
# include "stdafx.h"
2005-06-02 19:30:21 +00:00
# include "openttd.h"
2005-02-05 15:58:59 +00:00
# include "debug.h"
2005-07-22 07:02:20 +00:00
# include "functions.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 "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"
2005-02-06 10:18:47 +00:00
# include "depot.h"
2005-05-02 23:59:11 +00:00
# include "vehicle_gui.h"
2006-02-03 12:55:21 +00:00
# include "newgrf_engine.h"
2004-08-09 17:04:08 +00:00
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
} ;
2005-05-11 16:17:03 +00:00
int GetRoadVehImage ( const Vehicle * v , byte direction )
2004-08-09 17:04:08 +00:00
{
int img = v - > spritenum ;
int image ;
if ( is_custom_sprite ( img ) ) {
image = GetCustomVehicleSprite ( v , direction ) ;
2006-02-06 09:18:04 +00:00
if ( image ! = 0 ) return image ;
2005-09-26 19:01:49 +00:00
img = orig_road_vehicle_info [ v - > engine_type - ROAD_ENGINES_INDEX ] . image_index ;
2004-08-09 17:04:08 +00:00
}
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
image = direction + _roadveh_images [ img ] ;
2006-02-06 09:18:04 +00:00
if ( v - > cargo_count > = v - > cargo_cap / 2 ) image + = _roadveh_full_adder [ img ] ;
2004-08-09 17:04:08 +00:00
return image ;
}
2005-10-01 12:43:34 +00:00
void DrawRoadVehEngine ( int x , int y , EngineID engine , uint32 image_ormod )
2004-08-09 17:04:08 +00:00
{
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 ;
}
2005-09-26 19:01:49 +00:00
spritenum = orig_road_vehicle_info [ engine - ROAD_ENGINES_INDEX ] . image_index ;
2004-11-13 18:01:33 +00:00
}
DrawSprite ( ( 6 + _roadveh_images [ spritenum ] ) | image_ormod , x , y ) ;
2004-08-09 17:04:08 +00:00
}
2006-01-05 12:40:50 +00:00
static int32 EstimateRoadVehCost ( EngineID 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-05-12 00:11:37 +00:00
/** Build a road vehicle.
* @ param x , y tile coordinates of depot where road vehicle is built
* @ param p1 bus / truck type being built ( engine )
* @ param p2 unused
*/
2004-08-09 17:04:08 +00:00
int32 CmdBuildRoadVeh ( int x , int y , uint32 flags , uint32 p1 , uint32 p2 )
{
int32 cost ;
Vehicle * v ;
2005-02-04 14:24:23 +00:00
UnitID unit_num ;
2005-06-25 06:15:43 +00:00
TileIndex tile = TileVirtXY ( x , y ) ;
2004-08-09 17:04:08 +00:00
Engine * e ;
2004-09-10 19:02:27 +00:00
2006-01-18 14:12:26 +00:00
if ( ! IsEngineBuildable ( p1 , VEH_Road ) ) return_cmd_error ( STR_ENGINE_NOT_BUILDABLE ) ;
2005-01-27 21:00:05 +00:00
2004-08-09 17:04:08 +00:00
SET_EXPENSES_TYPE ( EXPENSES_NEW_VEHICLES ) ;
cost = EstimateRoadVehCost ( p1 ) ;
2005-05-12 00:11:37 +00:00
if ( flags & DC_QUERY_COST ) return cost ;
2004-08-09 17:04:08 +00:00
2005-03-06 16:53:00 +00:00
/* The ai_new queries the vehicle cost before building the route,
* so we must check against cheaters no sooner than now . - - pasky */
if ( ! IsTileDepotType ( tile , TRANSPORT_ROAD ) ) return CMD_ERROR ;
2005-06-04 11:56:32 +00:00
if ( ! IsTileOwner ( tile , _current_player ) ) return CMD_ERROR ;
2005-03-06 16:53:00 +00:00
2004-08-09 17:04:08 +00:00
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 ;
2005-06-07 18:13:49 +00:00
e = GetEngine ( p1 ) ;
2004-08-09 17:04:08 +00:00
v - > reliability = e - > reliability ;
v - > reliability_spd_dec = e - > reliability_spd_dec ;
v - > max_age = e - > lifelength * 366 ;
_new_roadveh_id = v - > index ;
2005-10-29 21:54:28 +00:00
_new_vehicle_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 ;
2005-12-28 22:29:59 +00:00
v - > random_bits = VehicleRandomBits ( ) ;
2004-08-09 17:04:08 +00:00
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-11-08 23:18:09 +00:00
if ( IsLocalPlayer ( ) )
InvalidateWindow ( WC_REPLACE_VEHICLE , VEH_Road ) ; // updates the replace Road window
2004-08-09 17:04:08 +00:00
}
return cost ;
}
2005-05-12 00:11:37 +00:00
/** Start/Stop a road vehicle.
* @ param x , y unused
* @ param p1 road vehicle ID to start / stop
* @ param p2 unused
*/
2004-08-09 17:04:08 +00:00
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
2005-05-12 00:11:37 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
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-04-11 20:54:25 +00:00
void ClearSlot ( Vehicle * v , RoadStop * rs )
2005-04-08 22:44:06 +00:00
{
DEBUG ( ms , 3 ) ( " Multistop: Clearing slot %d at 0x%x " , v - > u . road . slotindex , rs - > xy ) ;
v - > u . road . slot = NULL ;
v - > u . road . slot_age = 0 ;
2005-04-11 20:54:25 +00:00
if ( rs ! = NULL ) {
// check that the slot is indeed assigned to the same vehicle
assert ( rs - > slot [ v - > u . road . slotindex ] = = v - > index ) ;
2005-04-08 22:44:06 +00:00
rs - > slot [ v - > u . road . slotindex ] = INVALID_SLOT ;
2005-04-11 20:54:25 +00:00
}
2005-04-08 22:44:06 +00:00
}
2005-05-12 00:11:37 +00:00
/** Sell a road vehicle.
* @ param x , y unused
* @ param p1 vehicle ID to be sold
* @ param p2 unused
*/
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
2005-05-12 00:11:37 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2005-01-30 20:50:06 +00:00
SET_EXPENSES_TYPE ( EXPENSES_NEW_VEHICLES ) ;
2005-02-06 22:36:08 +00:00
if ( ! IsTileDepotType ( v - > tile , TRANSPORT_ROAD ) | | v - > u . road . state ! = 254 | | ! ( v - > vehstatus & VS_STOPPED ) )
2004-08-09 17:04:08 +00:00
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 ) ;
2005-04-08 22:44:06 +00:00
ClearSlot ( v , v - > u . road . slot ) ;
2004-08-09 17:04:08 +00:00
DeleteVehicle ( v ) ;
2005-11-08 23:18:09 +00:00
if ( IsLocalPlayer ( ) )
InvalidateWindow ( WC_REPLACE_VEHICLE , VEH_Road ) ; // updates the replace Road window
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 - ( int32 ) v - > value ;
}
typedef struct RoadFindDepotData {
uint best_length ;
2005-06-24 12:38:35 +00:00
TileIndex tile ;
2004-08-09 17:04:08 +00:00
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 ,
} ;
2005-06-24 12:38:35 +00:00
static bool EnumRoadSignalFindDepot ( TileIndex tile , RoadFindDepotData * rfdd , int track , uint length , byte * state )
2004-08-09 17:04:08 +00:00
{
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 ) & &
2005-10-05 07:20:26 +00:00
GB ( _m [ tile ] . m5 , 4 , 4 ) = = 2 & &
2005-06-04 11:56:32 +00:00
IsTileOwner ( 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 ;
}
2005-02-06 10:18:47 +00:00
static Depot * FindClosestRoadDepot ( Vehicle * v )
2004-08-09 17:04:08 +00:00
{
2005-06-24 12:38:35 +00:00
TileIndex tile = v - > tile ;
2004-08-09 17:04:08 +00:00
int i ;
2004-09-10 19:02:27 +00:00
2005-10-23 13:04:44 +00:00
if ( v - > u . road . state = = 255 ) tile = GetVehicleOutOfTunnelTile ( v ) ;
2004-08-09 17:04:08 +00:00
2005-01-31 11:23:10 +00:00
if ( _patches . new_pathfinding_all ) {
NPFFoundTargetData ftd ;
/* See where we are now */
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
Trackdir trackdir = GetVehicleTrackdir ( v ) ;
2005-05-02 17:52:35 +00:00
2005-07-03 13:02:54 +00:00
ftd = NPFRouteToDepotBreadthFirst ( v - > tile , trackdir , TRANSPORT_ROAD , v - > owner , INVALID_RAILTYPE ) ;
2005-01-31 11:23:10 +00:00
if ( ftd . best_bird_dist = = 0 )
return GetDepotByTile ( ftd . node . tile ) ; /* Target found */
else
2005-02-06 10:18:47 +00:00
return NULL ; /* Target not found */
2005-01-31 11:23:10 +00:00
/* 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 */
2006-02-01 07:36:15 +00:00
for ( i = 0 ; i ! = 4 ; i + + )
2005-01-31 11:23:10 +00:00
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 )
2005-02-06 10:18:47 +00:00
return NULL ;
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-05-12 00:11:37 +00:00
/** Send a road vehicle to the depot.
* @ param x , y unused
* @ param p1 vehicle ID to send to the depot
* @ param p2 unused
*/
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 ;
2005-05-12 00:11:37 +00:00
const Depot * dep ;
2004-08-09 17:04:08 +00:00
2005-01-30 20:50:06 +00:00
if ( ! IsVehicleIndex ( p1 ) ) return CMD_ERROR ;
v = GetVehicle ( p1 ) ;
2005-05-12 00:11:37 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
2005-05-12 00:11:37 +00:00
if ( v - > vehstatus & VS_CRASHED ) return CMD_ERROR ;
2005-05-03 19:31:33 +00:00
2005-05-12 00:11:37 +00:00
/* If the current orders are already goto-depot */
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 ) {
2005-05-12 00:11:37 +00:00
/* If the orders to 'goto depot' are in the orders list (forced servicing),
* then skip to the next order ; effectively cancelling this forced service */
2005-03-20 08:43:29 +00:00
if ( HASBIT ( v - > current_order . flags , OFB_PART_OF_ORDERS ) )
2004-08-09 17:04:08 +00:00
v - > cur_order_index + + ;
2005-03-20 08:43:29 +00:00
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 ;
}
2005-05-12 00:11:37 +00:00
dep = FindClosestRoadDepot ( v ) ;
if ( dep = = NULL ) return_cmd_error ( STR_9019_UNABLE_TO_FIND_LOCAL_DEPOT ) ;
2004-08-09 17:04:08 +00:00
if ( flags & DC_EXEC ) {
2004-12-05 12:43:04 +00:00
v - > current_order . type = OT_GOTO_DEPOT ;
2005-03-20 08:43:29 +00:00
v - > current_order . flags = OF_NON_STOP | OF_HALT_IN_DEPOT ;
2005-05-12 00:11:37 +00:00
v - > current_order . station = dep - > index ;
v - > dest_tile = dep - > 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 ;
}
2005-05-12 00:11:37 +00:00
/** Turn a roadvehicle around.
* @ param x , y unused
* @ param p1 vehicle ID to turn
* @ param p2 unused
*/
2004-08-09 17:04:08 +00:00
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
2005-05-12 00:11:37 +00:00
if ( v - > type ! = VEH_Road | | ! CheckOwnership ( v - > owner ) ) return CMD_ERROR ;
2004-08-09 17:04:08 +00:00
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 ) {
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 ;
}
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 ] ;
2005-07-21 06:31:02 +00:00
v - > x_offs = GB ( x , 0 , 8 ) ;
v - > y_offs = GB ( x , 8 , 8 ) ;
v - > sprite_width = GB ( x , 16 , 8 ) ;
v - > sprite_height = GB ( x , 24 , 8 ) ;
2004-08-09 17:04:08 +00:00
}
static void ClearCrashedStation ( Vehicle * v )
{
2005-11-17 10:12:21 +00:00
RoadStop * rs = GetRoadStopByTile ( v - > tile , GetRoadStopType ( v - > tile ) ) ;
2004-08-09 17:04:08 +00:00
// mark station as not busy
2005-11-17 10:12:21 +00:00
CLRBIT ( rs - > status , 7 ) ;
2004-09-10 19:02:27 +00:00
2004-08-09 17:04:08 +00:00
// free parking bay
2005-11-17 10:12:21 +00:00
SETBIT ( rs - > status , HASBIT ( v - > u . road . state , 1 ) ? 1 : 0 ) ;
2004-08-09 17:04:08 +00:00
}
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
2005-04-08 22:50:22 +00:00
ClearSlot ( v , v - > u . road . slot ) ;
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 ) {
2005-02-12 15:53:32 +00:00
CreateEffectVehicleRel ( v , 4 , 4 , 8 , EV_EXPLOSION_LARGE ) ;
2004-08-09 17:04:08 +00:00
} else if ( v - > u . road . crashed_ctr < = 45 ) {
2006-02-01 06:32:03 +00:00
if ( ( v - > tick_counter & 7 ) = = 0 )
2004-08-09 17:04:08 +00:00
RoadVehSetRandomDirection ( v ) ;
} else if ( v - > u . road . crashed_ctr > = 2220 ) {
RoadVehDelete ( v ) ;
}
}
static void * EnumCheckRoadVehCrashTrain ( Vehicle * v , Vehicle * u )
{
2006-02-06 09:18:04 +00:00
return
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 ?
v : NULL ;
2004-08-09 17:04:08 +00:00
}
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 ;
2006-02-06 09:18:04 +00:00
if ( v - > cargo_type = = CT_PASSENGERS ) pass + = v - > cargo_count ;
2004-08-09 17:04:08 +00:00
v - > cargo_count = 0 ;
2006-02-01 06:32:03 +00:00
SetDParam ( 0 , pass ) ;
2005-08-01 13:01:14 +00:00
AddNewsItem (
( pass = = 1 ) ?
STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE ,
2004-08-09 17:04:08 +00:00
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 )
{
2005-06-24 12:38:35 +00:00
TileIndex tile ;
2004-08-09 17:04:08 +00:00
2006-02-01 06:32:03 +00:00
if ( v - > u . road . state = = 255 ) return ;
2004-08-09 17:04:08 +00:00
tile = v - > tile ;
2006-02-01 06:32:03 +00:00
if ( ! IsTileType ( tile , MP_STREET ) | | ! IsLevelCrossing ( tile ) ) return ;
2004-08-09 17:04:08 +00:00
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 ) ;
2006-02-06 09:18:04 +00:00
if ( u ! = NULL ) u - > u . special . unk0 = v - > breakdown_delay * 2 ;
2004-08-09 17:04:08 +00:00
}
}
2006-02-06 09:18:04 +00:00
if ( ( v - > tick_counter & 1 ) = = 0 ) {
if ( - - v - > breakdown_delay = = 0 ) {
2004-08-09 17:04:08 +00:00
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 & &
2005-07-28 06:09:15 +00:00
( v - > current_order . flags & ( OF_PART_OF_ORDERS | OF_SERVICE_IF_NEEDED ) ) = = ( OF_PART_OF_ORDERS | OF_SERVICE_IF_NEEDED ) & &
2005-03-19 21:16:22 +00:00
! VehicleNeedsService ( v ) ) {
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 & &
2006-02-01 06:32:03 +00:00
order - > station = = v - > current_order . station ) {
2004-08-09 17:04:08 +00:00
return ;
2006-02-01 06:32:03 +00:00
}
2004-08-09 17:04:08 +00:00
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
{
2005-04-18 05:42:59 +00:00
uint mindist = 0xFFFFFFFF ;
2005-01-29 19:41:44 +00:00
RoadStopType type ;
RoadStop * rs ;
type = ( v - > cargo_type = = CT_PASSENGERS ) ? RS_BUS : RS_TRUCK ;
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
2005-04-18 05:42:59 +00:00
for ( rs = GetPrimaryRoadStop ( st , type ) ; rs ! = NULL ; rs = rs - > next ) {
if ( DistanceManhattan ( v - > tile , rs - > xy ) < mindist ) {
2005-01-29 19:41:44 +00:00
v - > dest_tile = rs - > xy ;
}
2005-04-18 05:42:59 +00:00
}
2005-01-29 19:41:44 +00:00
}
2005-01-15 19:06:22 +00:00
} else if ( order - > type = = OT_GOTO_DEPOT ) {
2005-02-06 10:18:47 +00:00
v - > dest_tile = GetDepot ( 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 ) ;
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 ;
2005-06-25 06:15:43 +00:00
u = VehicleFromPos ( TileVirtXY ( 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 ;
}
2005-11-13 13:43:55 +00:00
static void RoadVehArrivesAt ( const Vehicle * v , Station * st )
2004-08-09 17:04:08 +00:00
{
2005-10-23 14:38:09 +00:00
if ( v - > cargo_type = = CT_PASSENGERS ) {
2004-08-09 17:04:08 +00:00
/* 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 )
{
2006-02-01 06:32:03 +00:00
uint spd = v - > cur_speed + 1 + ( v - > u . road . overtaking ! = 0 ? 1 : 0 ) ;
2004-08-09 17:04:08 +00:00
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 ;
2006-02-01 06:32:03 +00:00
if ( _patches . vehicle_speed ) {
2004-12-21 23:27:58 +00:00
InvalidateWindowWidget ( WC_VEHICLE_VIEW , v - > index , STATUS_BAR ) ;
2006-02-01 06:32:03 +00:00
}
2004-08-09 17:04:08 +00:00
}
// Decrease somewhat when turning
2006-02-01 06:32:03 +00:00
if ( ! ( v - > direction & 1 ) ) spd = spd * 3 > > 2 ;
2004-08-09 17:04:08 +00:00
2006-02-01 06:32:03 +00:00
if ( spd = = 0 ) return false ;
2004-08-09 17:04:08 +00:00
2006-02-01 06:32:03 +00:00
if ( ( byte ) + + spd = = 0 ) return true ;
2004-08-09 17:04:08 +00:00
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 ;
2005-06-24 12:38:35 +00:00
TileIndex tile ;
2004-08-09 17:04:08 +00:00
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
{
2005-06-27 06:57:24 +00:00
if ( v - > tile ! = od - > tile | | v - > type ! = VEH_Road | | v = = od - > u | | 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 & &
2006-02-01 06:32:03 +00:00
! ( u - > vehstatus & VS_STOPPED ) & &
u - > cur_speed ! = 0 ) {
return ;
}
2004-08-09 17:04:08 +00:00
if ( v - > direction ! = u - > direction | | ! ( v - > direction & 1 ) )
return ;
if ( v - > u . road . state > = 32 | | ( v - > u . road . state & 7 ) > 1 )
return ;
2005-07-21 06:31:02 +00:00
tt = GetTileTrackStatus ( v - > tile , TRANSPORT_ROAD ) & 0x3F ;
2006-02-01 06:32:03 +00:00
if ( ( tt & 3 ) = = 0 ) return ;
if ( ( tt & 0x3C ) ! = 0 ) return ;
2004-08-09 17:04:08 +00:00
2006-02-01 06:32:03 +00:00
if ( tt = = 3 ) tt = ( v - > direction & 2 ) ? 2 : 1 ;
2004-08-09 17:04:08 +00:00
od . tilebits = tt ;
od . tile = v - > tile ;
2006-02-01 06:32:03 +00:00
if ( FindRoadVehToOvertake ( & od ) ) return ;
2004-08-09 17:04:08 +00:00
2005-01-05 13:32:03 +00:00
od . tile = v - > tile + TileOffsByDir ( v - > direction > > 1 ) ;
2006-02-01 06:32:03 +00:00
if ( FindRoadVehToOvertake ( & od ) ) return ;
2004-08-09 17:04:08 +00:00
if ( od . u - > cur_speed = = 0 | | od . u - > vehstatus & VS_STOPPED ) {
v - > u . road . overtaking_ctr = 0x11 ;
v - > u . road . overtaking = 0x10 ;
} else {
2006-02-01 06:32:03 +00:00
// if (FindRoadVehToOvertake(&od)) return;
2004-08-09 17:04:08 +00:00
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 {
2006-02-01 06:32:03 +00:00
if ( b & 1 ) num + + ;
2004-08-09 17:04:08 +00:00
} while ( b > > = 1 ) ;
2005-11-14 09:21:05 +00:00
num = RandomRange ( num ) ;
2004-08-09 17:04:08 +00:00
2006-02-01 09:11:31 +00:00
for ( i = 0 ; ! ( ( bits & 1 ) & & ( ( int ) - - num ) < 0 ) ; bits > > = 1 , i + + ) ;
2004-08-09 17:04:08 +00:00
return i ;
}
typedef struct {
TileIndex dest ;
uint maxtracklen ;
uint mindist ;
} FindRoadToChooseData ;
2005-06-24 12:38:35 +00:00
static bool EnumRoadTrackFindDist ( TileIndex tile , FindRoadToChooseData * frd , int track , uint length , byte * state )
2004-08-09 17:04:08 +00:00
{
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-06-24 12:38:35 +00:00
static int RoadFindPathToDest ( Vehicle * v , TileIndex 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 ;
2005-06-24 12:38:35 +00:00
TileIndex desttile ;
2004-08-09 17:04:08 +00:00
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 ) ;
2005-10-03 21:20:01 +00:00
signal = GB ( r , 16 , 16 ) ;
bitmask = GB ( r , 0 , 16 ) ;
2004-08-09 17:04:08 +00:00
}
2005-01-16 11:24:58 +00:00
if ( IsTileType ( tile , MP_STREET ) ) {
2005-10-23 13:04:44 +00:00
if ( GB ( _m [ tile ] . m5 , 4 , 4 ) = = 2 & & IsTileOwner ( tile , v - > owner ) ) {
/* Road depot */
bitmask | = _road_veh_fp_ax_or [ GB ( _m [ tile ] . m5 , 0 , 2 ) ] ;
}
2005-01-16 11:24:58 +00:00
} else if ( IsTileType ( tile , MP_STATION ) ) {
2005-06-04 11:56:32 +00:00
if ( IsTileOwner ( tile , OWNER_NONE ) | | IsTileOwner ( tile , v - > owner ) ) {
2004-09-14 01:21:07 +00:00
/* Our station */
2005-10-23 13:04:44 +00:00
const Station * st = GetStation ( _m [ tile ] . m2 ) ;
2005-07-13 18:04:01 +00:00
byte val = _m [ tile ] . m5 ;
2004-09-14 01:21:07 +00:00
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 ;
2005-06-27 06:57:24 +00:00
if ( v - > tile ! = 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 ) ;
(svn r2448) General cleanup of rail related code, more to follow.
* Add: rail.[ch] for rail-related enums and wrapper functions.
* Codechange: Removed dozens of magic numbers with below enums.
* Codechange: Rewrote CheckTrackCombination().
* Add: TILE_SIZE, TILE_PIXELS and TILE_HEIGHT constants.
* Add: enums RailTileType, RailTileSubtype, SignalType to mask against the map arrays.
* Add: enums Track, TrackBits, Trackdir, TrackdirBits for railway track data. (Note that the old RAIL_BIT constants are replaced by TRACK_BIT ones).
* Add: enums Direction and DiagDirection
* Codechange: Moved a bunch of track(dir) related lookup arrays from npf.[ch] to rail.[ch].
* Codechange: move RailType enum from tile.h to rail.h.
* Add: Wrapper functions for masking signal status in the map arrays: SignalAlongTrackdir, SignalAgainstTrackdir and SignalOnTrack.
* Add: Wrapper functions to access rail tiles, using above enums
* Add: Wrapper functions to modify tracks, trackdirs, directions, etc.
* Add: Wrapper functions for all lookup arrays in rail.[ch] (Arrays are still used in parts of the code)
* Codechange: Renamed some variables and arguments to better represent what they contain (railbit -> track, bits -> trackdirbits, etc.).
* Codechange: Don't use FindLandscapeHeight() in CmdRemoveSingleRail(), since it returns way too much info. Use GetTileSlope() instead.
* Codechange: [NPF] Removed some unused globals and code from npf.c.
2005-06-16 18:04:02 +00:00
trackdir = DiagdirToDiagTrackdir ( enterdir ) ;
2005-01-31 11:23:10 +00:00
//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
(svn r3472) - [PBS] Remove from trunk. Anyone interested can still find it in branch/pbs. This reverts revisions r3158, r3140, r3075, r2977, r2674, r2625, r2621, r2529, r2528, r2525, r2524, r2519, r2517, r2516, r2507, r2499. (in conjunction with Tron)
- The only change is that the nsignalsw.grf file is kept and that existing nightlies with PBS signals get those signals converted to combo-signals.
2006-01-29 18:57:26 +00:00
ftd = NPFRouteToStationOrTile ( tile - TileOffsByDir ( enterdir ) , trackdir , & fstd , TRANSPORT_ROAD , v - > owner , INVALID_RAILTYPE ) ;
2005-04-15 13:48:08 +00:00
if ( ftd . best_trackdir = = 0xff ) {
/* We are already at our target. Just do something */
2005-01-31 11:23:10 +00:00
//TODO: maybe display error?
//TODO: go straight ahead if possible?
return_track ( FindFirstBit2x64 ( bitmask ) ) ;
} else {
2005-04-15 13:48:08 +00:00
/* If ftd.best_bird_dist is 0, we found our target and ftd.best_trackdir contains
the direction we need to take to get there , if ftd . best_bird_dist is not 0 ,
we did not find our target , but ftd . best_trackdir contains the direction leading
to the tile closest to our target . */
2005-01-31 11:23:10 +00:00
return_track ( ftd . best_trackdir ) ;
}
} else {
if ( IsTileType ( desttile , MP_STREET ) ) {
2005-07-13 18:04:01 +00:00
m5 = _m [ desttile ] . m5 ;
2005-01-31 11:23:10 +00:00
if ( ( m5 & 0xF0 ) = = 0x20 )
/* We are heading for a Depot */
goto do_it ;
} else if ( IsTileType ( desttile , MP_STATION ) ) {
2005-07-13 18:04:01 +00:00
m5 = _m [ desttile ] . m5 ;
2005-01-31 11:23:10 +00:00
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-07-17 18:11:17 +00:00
#if 0
2005-04-18 05:42:59 +00:00
static uint RoadFindPathToStation ( const Vehicle * v , TileIndex tile )
2005-01-29 19:41:44 +00:00
{
2005-04-18 05:42:59 +00:00
NPFFindStationOrTileData fstd ;
2005-05-02 23:59:11 +00:00
byte trackdir = GetVehicleTrackdir ( v ) ;
assert ( trackdir ! = 0xFF ) ;
2005-01-29 19:41:44 +00:00
2005-04-18 05:42:59 +00:00
fstd . dest_coords = tile ;
fstd . station_index = - 1 ; // indicates that the destination is a tile, not a station
2005-01-29 19:41:44 +00:00
(svn r3472) - [PBS] Remove from trunk. Anyone interested can still find it in branch/pbs. This reverts revisions r3158, r3140, r3075, r2977, r2674, r2625, r2621, r2529, r2528, r2525, r2524, r2519, r2517, r2516, r2507, r2499. (in conjunction with Tron)
- The only change is that the nsignalsw.grf file is kept and that existing nightlies with PBS signals get those signals converted to combo-signals.
2006-01-29 18:57:26 +00:00
return NPFRouteToStationOrTile ( v - > tile , trackdir , & fstd , TRANSPORT_ROAD , v - > owner , INVALID_RAILTYPE ) . best_path_dist ;
2005-01-29 19:41:44 +00:00
}
2005-07-17 18:11:17 +00:00
# endif
2005-01-29 19:41:44 +00:00
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-02-22 19:38:44 +00:00
static void RoadVehController ( Vehicle * v )
2004-08-09 17:04:08 +00:00
{
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 - - ;
}
2006-02-01 06:32:03 +00:00
if ( v - > vehstatus & VS_STOPPED ) return ;
2004-08-09 17:04:08 +00:00
ProcessRoadVehOrder ( v ) ;
HandleRoadVehLoading ( v ) ;
2006-02-01 06:32:03 +00:00
if ( v - > current_order . type = = OT_LOADING ) return ;
2004-08-09 17:04:08 +00:00
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
2005-10-05 07:20:26 +00:00
dir = GB ( _m [ v - > tile ] . m5 , 0 , 2 ) ;
2004-08-09 17:04:08 +00:00
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
2006-02-01 06:32:03 +00:00
if ( RoadVehFindCloseTo ( v , x , y , v - > direction ) ) return ;
2004-08-09 17:04:08 +00:00
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 ;
}
2006-02-01 06:32:03 +00:00
if ( ! RoadVehAccelerate ( v ) ) return ;
2004-08-09 17:04:08 +00:00
if ( v - > u . road . overtaking ! = 0 ) {
if ( + + v - > u . road . overtaking_ctr > = 35 )
2006-01-06 17:25:39 +00:00
/* If overtaking just aborts at a random moment, we can have a out-of-bound problem,
* if the vehicle started a corner . To protect that , only allow an abort of
* overtake if we are on straight road , which are the 8 states below */
if ( v - > u . road . state = = 0 | | v - > u . road . state = = 1 | |
v - > u . road . state = = 8 | | v - > u . road . state = = 9 | |
v - > u . road . state = = 16 | | v - > u . road . state = = 17 | |
v - > u . road . state = = 24 | | v - > u . road . state = = 25 )
v - > u . road . overtaking = 0 ;
2004-08-09 17:04:08 +00:00
}
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 ) & &
2005-10-05 07:20:26 +00:00
GB ( _m [ gp . new_tile ] . m5 , 4 , 4 ) = = 0 & &
2004-08-09 17:04:08 +00:00
( 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-06-24 12:38:35 +00:00
TileIndex tile = v - > tile + TileOffsByDir ( rd . x & 3 ) ;
2004-08-09 17:04:08 +00:00
int dir = RoadFindPathToDest ( v , tile , rd . x & 3 ) ;
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 ;
}
2006-01-06 17:25:39 +00:00
rdp = _road_drive_data [ ( dir + ( _opt . road_side < < 4 ) ) ^ v - > u . road . overtaking ] ;
2004-08-09 17:04:08 +00:00
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 ) ) {
2006-01-06 17:25:39 +00:00
if ( ( dir & 7 ) > = 6 ) { v - > cur_speed = 0 ; return ; }
2005-07-13 18:04:01 +00:00
if ( IS_BYTE_INSIDE ( _m [ v - > tile ] . m5 , 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 ;
2006-01-06 17:25:39 +00:00
v - > u . road . state = ( byte ) dir ;
2004-08-09 17:04:08 +00:00
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-07-13 18:04:01 +00:00
st = GetStation ( _m [ v - > tile ] . m2 ) ;
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 ;
2005-07-13 18:04:01 +00:00
v - > last_station_visited = _m [ v - > tile ] . m2 ;
2004-08-09 17:04:08 +00:00
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 =
2005-06-15 16:58:15 +00:00
( old_order . flags & ( OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER ) ) | 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-02-05 12:10:09 +00:00
DEBUG ( ms , 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 ) ;
2005-01-30 22:04:14 +00:00
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 ) ;
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?
2005-03-20 08:43:29 +00:00
if ( HASBIT ( t . flags , OFB_PART_OF_ORDERS ) ) {
2004-12-05 12:43:04 +00:00
v - > cur_order_index + + ;
2005-03-20 08:43:29 +00:00
} else if ( HASBIT ( t . flags , OFB_HALT_IN_DEPOT ) ) {
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 ) ;
2005-02-22 19:38:44 +00:00
RoadVehController ( v ) ;
2004-08-09 17:04:08 +00:00
}
static void CheckIfRoadVehNeedsService ( Vehicle * v )
{
2005-02-06 10:18:47 +00:00
Depot * depot ;
2004-08-09 17:04:08 +00:00
2005-03-19 21:16:22 +00:00
if ( _patches . servint_roadveh = = 0 )
2004-08-10 17:06:10 +00:00
return ;
2005-03-19 21:16:22 +00:00
if ( ! VehicleNeedsService ( v ) )
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 & &
2005-03-20 08:43:29 +00:00
( v - > current_order . flags & ( OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS ) ) ! = 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 ;
2005-02-06 10:18:47 +00:00
depot = FindClosestRoadDepot ( v ) ;
2004-08-09 17:04:08 +00:00
2005-02-06 10:18:47 +00:00
if ( depot = = NULL | | DistanceManhattan ( v - > tile , depot - > xy ) > 12 ) {
2005-03-19 21:16:22 +00:00
if ( v - > current_order . type = = OT_GOTO_DEPOT ) {
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 ;
2005-02-06 10:18:47 +00:00
v - > current_order . station = depot - > index ;
v - > dest_tile = 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
}
2005-01-29 19:41:44 +00:00
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 */
2005-05-06 12:00:25 +00:00
if ( v - > current_order . type = = OT_GOTO_STATION & & ! ( v - > vehstatus & VS_CRASHED ) ) {
2005-01-29 19:41:44 +00:00
RoadStopType type = ( v - > cargo_type = = CT_PASSENGERS ) ? RS_BUS : RS_TRUCK ;
2005-01-06 22:31:58 +00:00
st = GetStation ( v - > current_order . station ) ;
2005-01-29 19:41:44 +00:00
//Current slot has expired
2006-02-01 06:32:03 +00:00
if ( v - > u . road . slot_age + + < = 0 & & v - > u . road . slot ! = NULL ) {
2005-01-29 19:41:44 +00:00
ClearSlot ( v , v - > u . road . slot ) ;
2006-02-01 06:32:03 +00:00
}
2005-01-29 19:41:44 +00:00
//We do not have a slot, so make one
2005-07-17 12:29:33 +00:00
if ( v - > u . road . slot = = NULL ) {
RoadStop * rs = GetPrimaryRoadStop ( st , type ) ;
RoadStop * first_stop = rs ;
RoadStop * best_stop = NULL ;
2005-07-17 13:45:43 +00:00
uint32 mindist = 12 , dist ; // 12 is threshold distance.
2005-01-29 19:41:44 +00:00
2005-07-17 12:29:33 +00:00
//first we need to find out how far our stations are away.
2005-02-05 12:10:09 +00:00
DEBUG ( ms , 2 ) ( " Multistop: Attempting to obtain a slot for vehicle %d at station %d (0x%x) " , v - > unitnumber , st - > index , st - > xy ) ;
2006-02-01 06:32:03 +00:00
for ( ; rs ! = NULL ; rs = rs - > next ) {
2005-07-17 12:29:33 +00:00
// Only consider those with at least a free slot.
if ( ! ( rs - > slot [ 0 ] = = INVALID_SLOT | | rs - > slot [ 1 ] = = INVALID_SLOT ) )
continue ;
// Previously the NPF pathfinder was used here even if NPF is OFF.. WTF?
assert ( NUM_SLOTS = = 2 ) ;
dist = DistanceManhattan ( v - > tile , rs - > xy ) ;
2005-07-17 13:45:43 +00:00
// Check if the station is located BEHIND the vehicle..
// In that case, add penalty.
2006-02-01 06:32:03 +00:00
switch ( v - > direction ) {
case 1 : // going north east,x position decreasing
if ( v - > x_pos < = ( int32 ) TileX ( rs - > xy ) * 16 + 15 ) dist + = 6 ;
break ;
case 3 : // Going south east, y position increasing
if ( v - > y_pos > = ( int32 ) TileY ( rs - > xy ) * 16 ) dist + = 6 ;
break ;
case 5 : // Going south west, x position increasing
if ( v - > x_pos > = ( int32 ) TileX ( rs - > xy ) * 16 ) dist + = 6 ;
break ;
case 7 : // Going north west, y position decrasing.
if ( v - > y_pos < = ( int32 ) TileY ( rs - > xy ) * 16 + 15 ) dist + = 6 ;
break ;
2005-07-17 13:45:43 +00:00
}
2005-07-17 12:29:33 +00:00
// Remember the one with the shortest distance
if ( dist < mindist ) {
mindist = dist ;
best_stop = rs ;
2005-01-29 19:41:44 +00:00
}
2005-07-17 12:29:33 +00:00
DEBUG ( ms , 3 ) ( " Multistop: Distance to stop at 0x%x is %d " , rs - > xy , dist ) ;
2005-01-29 19:41:44 +00:00
}
2005-07-17 12:29:33 +00:00
// best_stop now contains the best stop we found.
2006-02-06 09:18:04 +00:00
if ( best_stop ! = NULL ) {
2005-07-17 12:29:33 +00:00
int slot ;
// Find a free slot in this stop. We know that at least one is free.
assert ( best_stop - > slot [ 0 ] = = INVALID_SLOT | | best_stop - > slot [ 1 ] = = INVALID_SLOT ) ;
slot = ( best_stop - > slot [ 0 ] = = INVALID_SLOT ) ? 0 : 1 ;
best_stop - > slot [ slot ] = v - > index ;
v - > u . road . slot = best_stop ;
v - > dest_tile = best_stop - > xy ;
2005-07-17 13:45:43 +00:00
v - > u . road . slot_age = - 5 ;
2005-07-17 12:29:33 +00:00
v - > u . road . slotindex = slot ;
2005-07-17 13:45:43 +00:00
DEBUG ( ms , 1 ) ( " Multistop: Slot %d at 0x%x assigned to vehicle %d (0x%x) " , slot , best_stop - > xy , v - > unitnumber , v - > tile ) ;
2006-02-06 09:18:04 +00:00
} else if ( first_stop ! = NULL ) {
2005-07-17 12:29:33 +00:00
//now we couldn't assign a slot for one reason or another.
//so we just go towards the first station
2005-02-05 12:10:09 +00:00
DEBUG ( ms , 1 ) ( " Multistop: No free slot found for vehicle %d, going to default station " , v - > unitnumber ) ;
2005-07-17 12:29:33 +00:00
v - > dest_tile = first_stop - > xy ;
2005-02-05 12:10:09 +00:00
}
2005-01-29 19:41:44 +00:00
}
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
}
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 ) ;
}
}
}