Changeset - r4725:3a289e38fda7
[Not reviewed]
master
0 10 0
bjarni - 18 years ago 2006-10-04 12:01:59
bjarni@openttd.org
(svn r6637) -Codechange: merged all (vehicle type)EnterDepot into VehicleEnterDepot()
This revealed duplicated code like aircraft lists got invalidated twice
Moved invalidation of the vehicle detail window to VehicleServiceInDepot() as it should always be updated when serviced
10 files changed with 93 insertions and 197 deletions:
0 comments (0 inline, 0 general)
aircraft.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef AIRCRAFT_H
 
#define AIRCRAFT_H
 

	
 
#include "station_map.h"
 
#include "vehicle.h"
 

	
 

	
 
static inline bool IsAircraftInHangar(const Vehicle* v)
 
{
 
	assert(v->type == VEH_Aircraft);
 
	return v->vehstatus & VS_HIDDEN && IsHangarTile(v->tile);
 
}
 

	
 
static inline bool IsAircraftInHangarStopped(const Vehicle* v)
 
{
 
	return IsAircraftInHangar(v) && v->vehstatus & VS_STOPPED;
 
}
 

	
 
uint16 AircraftDefaultCargoCapacity(CargoID cid, EngineID engine_type);
 

	
 
void CcCloneAircraft(bool success, TileIndex tile, uint32 p1, uint32 p2);
 
inline void HandleAircraftEnterHangar(Vehicle *v);
 

	
 
#endif /* AIRCRAFT_H */
aircraft_cmd.c
Show inline comments
 
@@ -788,118 +788,117 @@ static void HelicopterTickHandler(Vehicl
 
	VehiclePositionChanged(u);
 
	EndVehicleMove(u);
 
}
 

	
 
static void SetAircraftPosition(Vehicle *v, int x, int y, int z)
 
{
 
	Vehicle *u;
 
	int safe_x;
 
	int safe_y;
 

	
 
	v->x_pos = x;
 
	v->y_pos = y;
 
	v->z_pos = z;
 

	
 
	v->cur_image = GetAircraftImage(v, v->direction);
 
	if (v->subtype == 0) v->next->next->cur_image = GetRotorImage(v);
 

	
 
	BeginVehicleMove(v);
 
	VehiclePositionChanged(v);
 
	EndVehicleMove(v);
 

	
 
	u = v->next;
 

	
 
	safe_x = clamp(x, 0, MapMaxX() * TILE_SIZE);
 
	safe_y = clamp(y - 1, 0, MapMaxY() * TILE_SIZE);
 
	u->x_pos = x;
 
	u->y_pos = y - ((v->z_pos-GetSlopeZ(safe_x, safe_y)) >> 3);;
 

	
 
	safe_y = clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE);
 
	u->z_pos = GetSlopeZ(safe_x, safe_y);
 
	u->cur_image = v->cur_image;
 

	
 
	BeginVehicleMove(u);
 
	VehiclePositionChanged(u);
 
	EndVehicleMove(u);
 

	
 
	u = u->next;
 
	if (u != NULL) {
 
		u->x_pos = x;
 
		u->y_pos = y;
 
		u->z_pos = z + 5;
 

	
 
		BeginVehicleMove(u);
 
		VehiclePositionChanged(u);
 
		EndVehicleMove(u);
 
	}
 
}
 

	
 
static void ServiceAircraft(Vehicle *v)
 
/** Handle Aircraft specific tasks when a an Aircraft enters a hangar
 
 * Made inline because it's only called from one location (VehicleEnterDepot)
 
 * Can't be moved to vehicle.c because it calls static Aircraft specific functions
 
 * @param *v Vehicle that enters the hangar
 
 */
 
inline void HandleAircraftEnterHangar(Vehicle *v)
 
{
 
	Vehicle *u;
 

	
 
	v->cur_speed = 0;
 
	v->subspeed = 0;
 
	v->progress = 0;
 
	v->vehstatus |= VS_HIDDEN;
 

	
 
	u = v->next;
 
	u->vehstatus |= VS_HIDDEN;
 
	u = u->next;
 
	if (u != NULL) {
 
		u->vehstatus |= VS_HIDDEN;
 
		u->cur_speed = 0;
 
	}
 

	
 
	SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
 
	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 

	
 
	VehicleServiceInDepot(v);
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
}
 

	
 
static void PlayAircraftSound(const Vehicle* v)
 
{
 
	if (!PlayVehicleSound(v, VSE_START)) {
 
		SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v);
 
	}
 
}
 

	
 
static bool UpdateAircraftSpeed(Vehicle *v)
 
{
 
	uint spd = v->acceleration * 2;
 
	byte t;
 

	
 
	v->subspeed = (t=v->subspeed) + (byte)spd;
 
	spd = min(v->cur_speed + (spd >> 8) + (v->subspeed < t), v->max_speed);
 

	
 
	// adjust speed for broken vehicles
 
	if (v->vehstatus & VS_AIRCRAFT_BROKEN) spd = min(spd, 27);
 

	
 
	//updates statusbar only if speed have changed to save CPU time
 
	if (spd != v->cur_speed) {
 
		v->cur_speed = spd;
 
		if (_patches.vehicle_speed)
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
	}
 

	
 
	if (!(v->direction & 1)) spd = spd * 3 / 4;
 

	
 
	if (spd == 0) return false;
 

	
 
	if ((byte)++spd == 0) return true;
 

	
 
	v->progress = (t = v->progress) - (byte)spd;
 

	
 
	return t < v->progress;
 
}
 

	
 
// get Aircraft running altitude
 
static byte GetAircraftFlyingAltitude(const Vehicle *v)
 
{
 
	switch (v->max_speed) {
 
		case 37: return 162;
 
		case 74: return 171;
 
		default: return 180;
 
	}
 
}
 

	
 
@@ -1340,205 +1339,163 @@ static void MaybeCrashAirplane(Vehicle *
 
	}
 

	
 
	CrashAirplane(v);
 
}
 

	
 
// we've landed and just arrived at a terminal
 
static void AircraftEntersTerminal(Vehicle *v)
 
{
 
	Station *st;
 
	Order old_order;
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) return;
 

	
 
	st = GetStation(v->u.air.targetairport);
 
	v->last_station_visited = v->u.air.targetairport;
 

	
 
	/* Check if station was ever visited before */
 
	if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
 
		uint32 flags;
 

	
 
		st->had_vehicle_of_type |= HVOT_AIRCRAFT;
 
		SetDParam(0, st->index);
 
		// show newsitem of celebrating citizens
 
		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_A033_CITIZENS_CELEBRATE_FIRST,
 
			flags,
 
			v->index,
 
			0);
 
	}
 

	
 
	old_order = v->current_order;
 
	v->current_order.type = OT_LOADING;
 
	v->current_order.flags = 0;
 

	
 
	if (old_order.type == OT_GOTO_STATION &&
 
			v->current_order.dest == v->last_station_visited) {
 
		v->current_order.flags =
 
			(old_order.flags & (OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER)) | OF_NON_STOP;
 
	}
 

	
 
	SET_EXPENSES_TYPE(EXPENSES_AIRCRAFT_INC);
 
	LoadUnloadVehicle(v);
 
	MarkAircraftDirty(v);
 
	InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 
}
 

	
 

	
 
static void AircraftEnterHangar(Vehicle *v)
 
{
 
	Order old_order;
 

	
 
	ServiceAircraft(v);
 
	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		int32 cost;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		old_order = v->current_order;
 
		v->current_order.type = OT_NOTHING;
 
		v->current_order.flags = 0;
 

	
 
		_current_player = v->owner;
 
		cost = DoCommand(v->tile, v->index, old_order.refit_cargo | old_order.refit_subtype << 8, DC_EXEC, CMD_REFIT_AIRCRAFT);
 
		if (!CmdFailed(cost) && v->owner == _local_player && cost != 0) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
		if (HASBIT(old_order.flags, OFB_PART_OF_ORDERS)) {
 
			v->cur_order_index++;
 
		} else if (HASBIT(old_order.flags, OFB_HALT_IN_DEPOT)) { // force depot visit
 
			v->vehstatus |= VS_STOPPED;
 
			InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 

	
 
			if (v->owner == _local_player) {
 
				SetDParam(0, v->unitnumber);
 
				AddNewsItem(
 
					STR_A014_AIRCRAFT_IS_WAITING_IN,
 
					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
 
					v->index,
 
					0
 
				);
 
			}
 
		}
 
	}
 
}
 

	
 
static void AircraftLand(Vehicle *v)
 
{
 
	v->sprite_width = v->sprite_height = 2;
 
}
 

	
 
static void AircraftLandAirplane(Vehicle *v)
 
{
 
	AircraftLand(v);
 
	if (!PlayVehicleSound(v, VSE_TOUCHDOWN)) {
 
		SndPlayVehicleFx(SND_17_SKID_PLANE, v);
 
	}
 
	MaybeCrashAirplane(v);
 
}
 

	
 
// set the right pos when heading to other airports after takeoff
 
static void AircraftNextAirportPos_and_Order(Vehicle *v)
 
{
 
	const Station* st;
 
	const AirportFTAClass *Airport;
 

	
 
	if (v->current_order.type == OT_GOTO_STATION ||
 
			v->current_order.type == OT_GOTO_DEPOT)
 
		v->u.air.targetairport = v->current_order.dest;
 

	
 
	st = GetStation(v->u.air.targetairport);
 
	Airport = GetAirport(st->airport_type);
 
	v->u.air.pos = v->u.air.previous_pos = Airport->entry_point;
 
}
 

	
 
static void AircraftLeaveHangar(Vehicle *v)
 
{
 
	v->cur_speed = 0;
 
	v->subspeed = 0;
 
	v->progress = 0;
 
	v->direction = 3;
 
	v->vehstatus &= ~VS_HIDDEN;
 
	{
 
		Vehicle *u = v->next;
 
		u->vehstatus &= ~VS_HIDDEN;
 

	
 
		// Rotor blades
 
		u = u->next;
 
		if (u != NULL) {
 
			u->vehstatus &= ~VS_HIDDEN;
 
			u->cur_speed = 80;
 
		}
 
	}
 

	
 
	VehicleServiceInDepot(v);
 
	SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
 
	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 
}
 

	
 

	
 
////////////////////////////////////////////////////////////////////////////////
 
///////////////////   AIRCRAFT MOVEMENT SCHEME  ////////////////////////////////
 
////////////////////////////////////////////////////////////////////////////////
 
static void AircraftEventHandler_EnterTerminal(Vehicle *v, const AirportFTAClass *Airport)
 
{
 
	AircraftEntersTerminal(v);
 
	v->u.air.state = Airport->layout[v->u.air.pos].heading;
 
}
 

	
 
static void AircraftEventHandler_EnterHangar(Vehicle *v, const AirportFTAClass *Airport)
 
{
 
	AircraftEnterHangar(v);
 
	VehicleEnterDepot(v);
 
	v->u.air.state = Airport->layout[v->u.air.pos].heading;
 
}
 

	
 
// In an Airport Hangar
 
static void AircraftEventHandler_InHangar(Vehicle *v, const AirportFTAClass *Airport)
 
{
 
	// if we just arrived, execute EnterHangar first
 
	if (v->u.air.previous_pos != v->u.air.pos) {
 
		AircraftEventHandler_EnterHangar(v, Airport);
 
		return;
 
	}
 

	
 
	// if we were sent to the depot, stay there
 
	if (v->current_order.type == OT_GOTO_DEPOT && (v->vehstatus & VS_STOPPED)) {
 
		v->current_order.type = OT_NOTHING;
 
		v->current_order.flags = 0;
 
		return;
 
	}
 

	
 
	if (v->current_order.type != OT_GOTO_STATION &&
 
			v->current_order.type != OT_GOTO_DEPOT)
 
		return;
 

	
 
	// if the block of the next position is busy, stay put
 
	if (AirportHasBlock(v, &Airport->layout[v->u.air.pos], Airport)) return;
 

	
 
	// We are already at the target airport, we need to find a terminal
 
	if (v->current_order.dest == v->u.air.targetairport) {
 
		// FindFreeTerminal:
 
		// 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal
 
		if (v->subtype != 0) {
 
			if (!AirportFindFreeTerminal(v, Airport)) return; // airplane
 
		} else {
 
			if (!AirportFindFreeHelipad(v, Airport)) return; // helicopter
 
		}
 
	} else { // Else prepare for launch.
 
		// airplane goto state takeoff, helicopter to helitakeoff
 
		v->u.air.state = (v->subtype != 0) ? TAKEOFF : HELITAKEOFF;
 
	}
 
	AircraftLeaveHangar(v);
 
	AirportMove(v, Airport);
 
}
 

	
 
// At one of the Airport's Terminals
 
static void AircraftEventHandler_AtTerminal(Vehicle *v, const AirportFTAClass *Airport)
 
{
 
	// if we just arrived, execute EnterTerminal first
 
	if (v->u.air.previous_pos != v->u.air.pos) {
rail_cmd.c
Show inline comments
 
@@ -1961,82 +1961,82 @@ static void ChangeTileOwner_Track(TileIn
 
		SetTileOwner(tile, new_player);
 
	} else {
 
		DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
	}
 
}
 

	
 
static const byte _fractcoords_behind[4] = { 0x8F, 0x8, 0x80, 0xF8 };
 
static const byte _fractcoords_enter[4] = { 0x8A, 0x48, 0x84, 0xA8 };
 
static const byte _deltacoord_leaveoffset[8] = {
 
	-1,  0,  1,  0, /* x */
 
	 0,  1,  0, -1  /* y */
 
};
 

	
 
static uint32 VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	byte fract_coord;
 
	byte fract_coord_leave;
 
	DiagDirection dir;
 
	int length;
 

	
 
	// this routine applies only to trains in depot tiles
 
	if (v->type != VEH_Train || !IsTileDepotType(tile, TRANSPORT_RAIL)) return 0;
 

	
 
	/* depot direction */
 
	dir = GetRailDepotDirection(tile);
 

	
 
	/* calculate the point where the following wagon should be activated */
 
	/* this depends on the length of the current vehicle */
 
	length = v->u.rail.cached_veh_length;
 

	
 
	fract_coord_leave =
 
		((_fractcoords_enter[dir] & 0x0F) + // x
 
			(length + 1) * _deltacoord_leaveoffset[dir]) +
 
		(((_fractcoords_enter[dir] >> 4) +  // y
 
			((length + 1) * _deltacoord_leaveoffset[dir+4])) << 4);
 

	
 
	fract_coord = (x & 0xF) + ((y & 0xF) << 4);
 

	
 
	if (_fractcoords_behind[dir] == fract_coord) {
 
		/* make sure a train is not entering the tile from behind */
 
		return 8;
 
	} else if (_fractcoords_enter[dir] == fract_coord) {
 
		if (DiagDirToDir(ReverseDiagDir(dir)) == v->direction) {
 
			/* enter the depot */
 
			v->u.rail.track = 0x80,
 
			v->vehstatus |= VS_HIDDEN; /* hide it */
 
			v->direction = ReverseDir(v->direction);
 
			if (v->next == NULL)
 
				TrainEnterDepot(v, tile);
 
				VehicleEnterDepot(v);
 
			v->tile = tile;
 
			InvalidateWindow(WC_VEHICLE_DEPOT, tile);
 
			return 4;
 
		}
 
	} else if (fract_coord_leave == fract_coord) {
 
		if (DiagDirToDir(dir) == v->direction) {
 
			/* leave the depot? */
 
			if ((v = v->next) != NULL) {
 
				v->vehstatus &= ~VS_HIDDEN;
 
				v->u.rail.track = (DiagDirToAxis(dir) == AXIS_X ? 1 : 2);
 
			}
 
		}
 
	}
 

	
 
	return 0;
 
}
 

	
 

	
 
const TileTypeProcs _tile_type_rail_procs = {
 
	DrawTile_Track,           /* draw_tile_proc */
 
	GetSlopeZ_Track,          /* get_slope_z_proc */
 
	ClearTile_Track,          /* clear_tile_proc */
 
	GetAcceptedCargo_Track,   /* get_accepted_cargo_proc */
 
	GetTileDesc_Track,        /* get_tile_desc_proc */
 
	GetTileTrackStatus_Track, /* get_tile_track_status_proc */
 
	ClickTile_Track,          /* click_tile_proc */
 
	AnimateTile_Track,        /* animate_tile_proc */
 
	TileLoop_Track,           /* tile_loop_clear */
 
	ChangeTileOwner_Track,    /* change_tile_owner_clear */
 
	NULL,                     /* get_produced_cargo_proc */
 
	VehicleEnter_Track,       /* vehicle_enter_tile_proc */
 
	GetSlopeTileh_Track,      /* get_slope_tileh_proc */
 
};
road_cmd.c
Show inline comments
 
/* $Id$ */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "bridge_map.h"
 
#include "rail_map.h"
 
#include "road_map.h"
 
#include "sprite.h"
 
#include "table/sprites.h"
 
#include "table/strings.h"
 
#include "functions.h"
 
#include "map.h"
 
#include "tile.h"
 
#include "town_map.h"
 
#include "vehicle.h"
 
#include "viewport.h"
 
#include "command.h"
 
#include "player.h"
 
#include "town.h"
 
#include "gfx.h"
 
#include "sound.h"
 
#include "yapf/yapf.h"
 
#include "depot.h"
 

	
 
void RoadVehEnterDepot(Vehicle *v);
 

	
 

	
 
static uint CountRoadBits(RoadBits r)
 
{
 
	uint count = 0;
 

	
 
	if (r & ROAD_NW) ++count;
 
	if (r & ROAD_SW) ++count;
 
	if (r & ROAD_SE) ++count;
 
	if (r & ROAD_NE) ++count;
 
	return count;
 
}
 

	
 

	
 
static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool* edge_road)
 
{
 
	RoadBits present;
 
	RoadBits n;
 
	byte owner;
 
	*edge_road = true;
 

	
 
	if (_game_mode == GM_EDITOR) return true;
 

	
 
	// Only do the special processing for actual players.
 
	if (_current_player >= MAX_PLAYERS) return true;
 

	
 
	owner = IsLevelCrossingTile(tile) ? GetCrossingRoadOwner(tile) : GetTileOwner(tile);
 

	
 
	// Only do the special processing if the road is owned
 
	// by a town
 
	if (owner != OWNER_TOWN) {
 
		return owner == OWNER_NONE || CheckOwnership(owner);
 
	}
 

	
 
	if (_cheats.magic_bulldozer.value) return true;
 

	
 
	// Get a bitmask of which neighbouring roads has a tile
 
	n = 0;
 
	present = GetAnyRoadBits(tile);
 
	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile,-1, 0)) & ROAD_SW) n |= ROAD_NE;
 
	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile, 0, 1)) & ROAD_NW) n |= ROAD_SE;
 
	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile, 1, 0)) & ROAD_NE) n |= ROAD_SW;
 
	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile, 0,-1)) & ROAD_SE) n |= ROAD_NW;
 

	
 
	// If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
 
	// then allow it
 
	if ((n & (n - 1)) != 0 && (n & remove) != 0) {
 
		Town *t;
 
		*edge_road = false;
 
@@ -1012,97 +1010,97 @@ static uint32 GetTileTrackStatus_Road(Ti
 
			break;
 

	
 
		default: break;
 
	}
 
	return 0;
 
}
 

	
 
static const StringID _road_tile_strings[] = {
 
	STR_1814_ROAD,
 
	STR_1814_ROAD,
 
	STR_1814_ROAD,
 
	STR_1815_ROAD_WITH_STREETLIGHTS,
 
	STR_1814_ROAD,
 
	STR_1816_TREE_LINED_ROAD,
 
	STR_1814_ROAD,
 
	STR_1814_ROAD,
 
};
 

	
 
static void GetTileDesc_Road(TileIndex tile, TileDesc *td)
 
{
 
	td->owner = GetTileOwner(tile);
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_CROSSING: td->str = STR_1818_ROAD_RAIL_LEVEL_CROSSING; break;
 
		case ROAD_TILE_DEPOT: td->str = STR_1817_ROAD_VEHICLE_DEPOT; break;
 
		default: td->str = _road_tile_strings[GetRoadside(tile)]; break;
 
	}
 
}
 

	
 
static const byte _roadveh_enter_depot_unk0[4] = {
 
	8, 9, 0, 1
 
};
 

	
 
static uint32 VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_CROSSING:
 
			if (v->type == VEH_Train && !IsCrossingBarred(tile)) {
 
				/* train crossing a road */
 
				SndPlayVehicleFx(SND_0E_LEVEL_CROSSING, v);
 
				BarCrossing(tile);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			break;
 

	
 
		case ROAD_TILE_DEPOT:
 
			if (v->type == VEH_Road &&
 
					v->u.road.frame == 11 &&
 
					_roadveh_enter_depot_unk0[GetRoadDepotDirection(tile)] == v->u.road.state) {
 
				RoadVehEnterDepot(v);
 
				VehicleEnterDepot(v);
 
				return 4;
 
			}
 
			break;
 

	
 
		default: break;
 
	}
 
	return 0;
 
}
 

	
 

	
 
static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player)
 
{
 
	if (IsLevelCrossing(tile) && GetCrossingRoadOwner(tile) == old_player) {
 
		SetCrossingRoadOwner(tile, new_player == OWNER_SPECTATOR ? OWNER_NONE : new_player);
 
	}
 

	
 
	if (!IsTileOwner(tile, old_player)) return;
 

	
 
	if (new_player != OWNER_SPECTATOR) {
 
		SetTileOwner(tile, new_player);
 
	} else {
 
		switch (GetRoadTileType(tile)) {
 
			case ROAD_TILE_NORMAL:
 
				SetTileOwner(tile, OWNER_NONE);
 
				break;
 

	
 
			case ROAD_TILE_CROSSING:
 
				MakeRoadNormal(tile, GetCrossingRoadOwner(tile), GetCrossingRoadBits(tile), GetTownIndex(tile));
 
				break;
 

	
 
			default:
 
			case ROAD_TILE_DEPOT:
 
				DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
				break;
 
		}
 
	}
 
}
 

	
 

	
 
const TileTypeProcs _tile_type_road_procs = {
 
	DrawTile_Road,           /* draw_tile_proc */
 
	GetSlopeZ_Road,          /* get_slope_z_proc */
 
	ClearTile_Road,          /* clear_tile_proc */
 
	GetAcceptedCargo_Road,   /* get_accepted_cargo_proc */
 
	GetTileDesc_Road,        /* get_tile_desc_proc */
 
	GetTileTrackStatus_Road, /* get_tile_track_status_proc */
 
	ClickTile_Road,          /* click_tile_proc */
 
	AnimateTile_Road,        /* animate_tile_proc */
roadveh_cmd.c
Show inline comments
 
@@ -1530,142 +1530,96 @@ again:
 
			v->current_order.flags = 0;
 
			ClearSlot(v);
 
		}
 
		SETBIT(rs->status, 7);
 

	
 
		if (rs == v->u.road.slot) {
 
			//we have arrived at the correct station
 
			ClearSlot(v);
 
		} 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
 
			DEBUG(ms, 0) ("Multistop: Vehicle %d (index %d) arrived at wrong stop.", v->unitnumber, v->index);
 
			if (v->tile != v->dest_tile) {
 
				DEBUG(ms, 0) ("Multistop: -- Current tile 0x%X is not destination tile 0x%X. Route problem", v->tile, v->dest_tile);
 
			}
 
			if (v->dest_tile != v->u.road.slot->xy) {
 
				DEBUG(ms, 0) ("Multistop: -- Stop tile 0x%X is not destination tile 0x%X. Multistop desync", v->u.road.slot->xy, v->dest_tile);
 
			}
 
			if (v->current_order.type != OT_GOTO_STATION) {
 
				DEBUG(ms, 0) ("Multistop: -- Current order type (%d) is not OT_GOTO_STATION.", v->current_order.type);
 
			} else {
 
				if (v->current_order.dest != st->index)
 
					DEBUG(ms, 0) ("Multistop: -- Current station %d is not target station in current_order.station (%d).",
 
							st->index, v->current_order.dest);
 
			}
 

	
 
			DEBUG(ms, 0) ("           -- Force a slot clearing.");
 
			ClearSlot(v);
 
		}
 

	
 
		StartRoadVehSound(v);
 
		InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
	}
 

	
 
	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);
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 
		int32 cost;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		t = v->current_order;
 
		v->current_order.type = OT_DUMMY;
 
		v->current_order.flags = 0;
 

	
 
		_current_player = v->owner;
 
		cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_ROAD_VEH);
 
		if (!CmdFailed(cost) && v->owner == _local_player && cost != 0) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
		// Part of the orderlist?
 
		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) {
 
			v->cur_order_index++;
 
		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) {
 
			v->vehstatus |= VS_STOPPED;
 
			if (v->owner == _local_player) {
 
				SetDParam(0, v->unitnumber);
 
				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);
 
	InvalidateWindowClasses(WC_ROADVEH_LIST);
 
}
 

	
 
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);
 
	RoadVehController(v);
 
}
 

	
 
static void CheckIfRoadVehNeedsService(Vehicle *v)
 
{
 
	const Depot* depot;
 

	
 
	if (_patches.servint_roadveh == 0) return;
 
	if (!VehicleNeedsService(v)) return;
 
	if (v->vehstatus & VS_STOPPED) return;
 
	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
 

	
 
	// Don't interfere with a depot visit scheduled by the user, or a
 
	// depot visit by the order list.
 
	if (v->current_order.type == OT_GOTO_DEPOT &&
 
			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
 
		return;
 

	
 
	// 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;
 

	
 
	if (IsRoadVehInDepot(v)) {
 
		VehicleServiceInDepot(v);
 
		return;
 
	}
 

	
 
	// XXX If we already have a depot order, WHY do we search over and over?
 
	depot = FindClosestRoadDepot(v);
 

	
 
	if (depot == NULL || DistanceManhattan(v->tile, depot->xy) > 12) {
 
		if (v->current_order.type == OT_GOTO_DEPOT) {
 
			v->current_order.type = OT_DUMMY;
 
			v->current_order.flags = 0;
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
		}
 
		return;
 
	}
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT &&
ship.h
Show inline comments
 
/* $Id$ */
 

	
 
#ifndef SHIP_H
 
#define SHIP_H
 

	
 
#include "vehicle.h"
 

	
 
void CcCloneShip(bool success, TileIndex tile, uint32 p1, uint32 p2);
 
void RecalcShipStuff(Vehicle *v);
 

	
 
static inline bool IsShipInDepot(const Vehicle* v)
 
{
 
	assert(v->type == VEH_Ship);
 
	return v->u.ship.state == 0x80;
 
}
 

	
 
static inline bool IsShipInDepotStopped(const Vehicle* v)
 
{
 
	return IsShipInDepot(v) && v->vehstatus & VS_STOPPED;
 
}
 

	
 
#endif /* SHIP_H */
ship_cmd.c
Show inline comments
 
@@ -271,215 +271,171 @@ static void HandleShipLoading(Vehicle *v
 

	
 
	if (v->current_order.type != OT_DUMMY) {
 
		if (v->current_order.type != OT_LOADING) return;
 
		if (--v->load_unload_time_rem) return;
 

	
 
		if (v->current_order.flags & OF_FULL_LOAD && CanFillVehicle(v)) {
 
			SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
 
			if (LoadUnloadVehicle(v)) {
 
				InvalidateWindow(WC_SHIPS_LIST, v->owner);
 
				MarkShipDirty(v);
 
			}
 
			return;
 
		}
 
		PlayShipSound(v);
 

	
 
		{
 
			Order b = v->current_order;
 
			v->current_order.type = OT_LEAVESTATION;
 
			v->current_order.flags = 0;
 
			if (!(b.flags & OF_NON_STOP)) return;
 
		}
 
	}
 

	
 
	v->cur_order_index++;
 
	InvalidateVehicleOrder(v);
 
}
 

	
 
static void UpdateShipDeltaXY(Vehicle *v, int dir)
 
{
 
#define MKIT(d,c,b,a) ((a&0xFF)<<24) | ((b&0xFF)<<16) | ((c&0xFF)<<8) | ((d&0xFF)<<0)
 
	static const uint32 _delta_xy_table[8] = {
 
		MKIT( -3,  -3,  6,  6),
 
		MKIT(-16,  -3, 32,  6),
 
		MKIT( -3,  -3,  6,  6),
 
		MKIT( -3, -16,  6, 32),
 
		MKIT( -3,  -3,  6,  6),
 
		MKIT(-16,  -3, 32,  6),
 
		MKIT( -3,  -3,  6,  6),
 
		MKIT( -3, -16,  6, 32),
 
	};
 
#undef MKIT
 
	uint32 x = _delta_xy_table[dir];
 
	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);
 
}
 

	
 
static void RecalcShipStuff(Vehicle *v)
 
void RecalcShipStuff(Vehicle *v)
 
{
 
	UpdateShipDeltaXY(v, v->direction);
 
	v->cur_image = GetShipImage(v, v->direction);
 
	MarkShipDirty(v);
 
	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
}
 

	
 
static const TileIndexDiffC _ship_leave_depot_offs[] = {
 
	{-1,  0},
 
	{ 0, -1}
 
};
 

	
 
static void CheckShipLeaveDepot(Vehicle *v)
 
{
 
	TileIndex tile;
 
	Axis axis;
 
	uint m;
 

	
 
	if (!IsShipInDepot(v)) return;
 

	
 
	tile = v->tile;
 
	axis = GetShipDepotAxis(tile);
 

	
 
	// Check first side
 
	if (_ship_sometracks[axis] & GetTileShipTrackStatus(TILE_ADD(tile, ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
 
		m = (axis == AXIS_X) ? 0x101 : 0x207;
 
	// Check second side
 
	} else if (_ship_sometracks[axis + 2] & GetTileShipTrackStatus(TILE_ADD(tile, -2 * ToTileIndexDiff(_ship_leave_depot_offs[axis])))) {
 
		m = (axis == AXIS_X) ? 0x105 : 0x203;
 
	} else {
 
		return;
 
	}
 
	v->direction    = GB(m, 0, 8);
 
	v->u.ship.state = GB(m, 8, 8);
 
	v->vehstatus &= ~VS_HIDDEN;
 

	
 
	v->cur_speed = 0;
 
	RecalcShipStuff(v);
 

	
 
	PlayShipSound(v);
 
	VehicleServiceInDepot(v);
 
	InvalidateWindowClasses(WC_SHIPS_LIST);
 
}
 

	
 
static bool ShipAccelerate(Vehicle *v)
 
{
 
	uint spd;
 
	byte t;
 

	
 
	spd = min(v->cur_speed + 1, v->max_speed);
 

	
 
	//updates statusbar only if speed have changed to save CPU time
 
	if (spd != v->cur_speed) {
 
		v->cur_speed = spd;
 
		if (_patches.vehicle_speed)
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
	}
 

	
 
	// Decrease somewhat when turning
 
	if (!(v->direction & 1)) spd = spd * 3 / 4;
 

	
 
	if (spd == 0) return false;
 
	if ((byte)++spd == 0) return true;
 

	
 
	v->progress = (t = v->progress) - (byte)spd;
 

	
 
	return (t < v->progress);
 
}
 

	
 
static int32 EstimateShipCost(EngineID engine_type)
 
{
 
	return ShipVehInfo(engine_type)->base_cost * (_price.ship_base>>3)>>5;
 
}
 

	
 
static void ShipEnterDepot(Vehicle *v)
 
{
 
	v->u.ship.state = 0x80;
 
	v->vehstatus |= VS_HIDDEN;
 
	v->cur_speed = 0;
 
	RecalcShipStuff(v);
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 
		int32 cost;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		t = v->current_order;
 
		v->current_order.type = OT_DUMMY;
 
		v->current_order.flags = 0;
 

	
 
		_current_player = v->owner;
 
		cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_SHIP);
 
		if (!CmdFailed(cost) && v->owner == _local_player && cost != 0) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) {
 
			v->cur_order_index++;
 
		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) {
 
			v->vehstatus |= VS_STOPPED;
 
			if (v->owner == _local_player) {
 
				SetDParam(0, v->unitnumber);
 
				AddNewsItem(
 
					STR_981C_SHIP_IS_WAITING_IN_DEPOT,
 
					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
 
					v->index,
 
					0);
 
			}
 
		}
 
	}
 
	InvalidateWindowClasses(WC_SHIPS_LIST);
 
}
 

	
 
static void ShipArrivesAt(const Vehicle* v, Station* st)
 
{
 
	/* Check if station was ever visited before */
 
	if (!(st->had_vehicle_of_type & HVOT_SHIP)) {
 
		uint32 flags;
 

	
 
		st->had_vehicle_of_type |= HVOT_SHIP;
 

	
 
		SetDParam(0, st->index);
 
		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_9833_CITIZENS_CELEBRATE_FIRST,
 
			flags,
 
			v->index,
 
			0);
 
	}
 
}
 

	
 
typedef struct {
 
	TileIndex skiptile;
 
	TileIndex dest_coords;
 
	uint best_bird_dist;
 
	uint best_length;
 
} PathFindShip;
 

	
 
static bool ShipTrackFollower(TileIndex tile, PathFindShip *pfs, int track, uint length, byte *state)
 
{
 
	// Found dest?
 
	if (tile == pfs->dest_coords) {
 
		pfs->best_bird_dist = 0;
 

	
 
		pfs->best_length = minu(pfs->best_length, length);
 
		return true;
 
	}
 

	
 
	// Skip this tile in the calculation
 
	if (tile != pfs->skiptile) {
 
		pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
 
	}
 

	
 
	return false;
 
}
 

	
 
static const byte _ship_search_directions[6][4] = {
 
	{ 0, 9, 2, 9 },
 
	{ 9, 1, 9, 3 },
 
	{ 9, 0, 3, 9 },
 
	{ 1, 9, 9, 2 },
 
@@ -686,97 +642,97 @@ static void ShipController(Vehicle *v)
 
		}
 
		v->breakdown_ctr--;
 
	}
 

	
 
	if (v->vehstatus & VS_STOPPED) return;
 

	
 
	ProcessShipOrder(v);
 
	HandleShipLoading(v);
 

	
 
	if (v->current_order.type == OT_LOADING) return;
 

	
 
	CheckShipLeaveDepot(v);
 

	
 
	if (!ShipAccelerate(v)) return;
 

	
 
	BeginVehicleMove(v);
 

	
 
	if (GetNewVehiclePos(v, &gp)) {
 
		// staying in tile
 
		if (IsShipInDepot(v)) {
 
			gp.x = v->x_pos;
 
			gp.y = v->y_pos;
 
		} else {
 
			/* isnot inside depot */
 
			r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
 
			if (r & 0x8) goto reverse_direction;
 

	
 
			/* A leave station order only needs one tick to get processed, so we can
 
			 * always skip ahead. */
 
			if (v->current_order.type == OT_LEAVESTATION) {
 
				v->current_order.type = OT_NOTHING;
 
				v->current_order.flags = 0;
 
				InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
			} else if (v->dest_tile != 0) {
 
				/* We have a target, let's see if we reached it... */
 
				if (v->current_order.type == OT_GOTO_STATION &&
 
						IsBuoyTile(v->dest_tile) &&
 
						DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) {
 
					/* We got within 3 tiles of our target buoy, so let's skip to our
 
					 * next order */
 
					v->cur_order_index++;
 
					v->current_order.type = OT_DUMMY;
 
					InvalidateVehicleOrder(v);
 
				} else {
 
					/* Non-buoy orders really need to reach the tile */
 
					if (v->dest_tile == gp.new_tile) {
 
						if (v->current_order.type == OT_GOTO_DEPOT) {
 
							if ((gp.x&0xF)==8 && (gp.y&0xF)==8) {
 
								ShipEnterDepot(v);
 
								VehicleEnterDepot(v);
 
								return;
 
							}
 
						} else if (v->current_order.type == OT_GOTO_STATION) {
 
							Station *st;
 

	
 
							v->last_station_visited = v->current_order.dest;
 

	
 
							/* Process station in the orderlist. */
 
							st = GetStation(v->current_order.dest);
 
							if (st->facilities & FACIL_DOCK) { /* ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations */
 
								v->current_order.type = OT_LOADING;
 
								v->current_order.flags &= OF_FULL_LOAD | OF_UNLOAD | OF_TRANSFER;
 
								v->current_order.flags |= OF_NON_STOP;
 
								ShipArrivesAt(v, st);
 

	
 
								SET_EXPENSES_TYPE(EXPENSES_SHIP_INC);
 
								if (LoadUnloadVehicle(v)) {
 
									InvalidateWindow(WC_SHIPS_LIST, v->owner);
 
									MarkShipDirty(v);
 
								}
 
								InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
							} else { /* leave stations without docks right aways */
 
								v->current_order.type = OT_LEAVESTATION;
 
								v->current_order.flags = 0;
 
								v->cur_order_index++;
 
								InvalidateVehicleOrder(v);
 
							}
 
						}
 
					}
 
				}
 
			}
 
		}
 
	} else {
 
		DiagDirection diagdir;
 
		// new tile
 
		if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY())
 
			goto reverse_direction;
 

	
 
		dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile);
 
		assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW);
 
		diagdir = DirToDiagDir(dir);
 
		tracks = GetAvailShipTracks(gp.new_tile, diagdir);
 
		if (tracks == 0)
 
			goto reverse_direction;
 

	
 
		// Choose a direction, and continue if we find one
 
		track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks);
 
		if (track < 0)
train_cmd.c
Show inline comments
 
@@ -3431,145 +3431,96 @@ static void TrainLocoHandler(Vehicle *v,
 

	
 
	HandleTrainLoading(v, mode);
 

	
 
	if (v->current_order.type == OT_LOADING) return;
 

	
 
	if (CheckTrainStayInDepot(v)) return;
 

	
 
	if (!mode) HandleLocomotiveSmokeCloud(v);
 

	
 
	j = UpdateTrainSpeed(v);
 
	if (j == 0) {
 
		// if the vehicle has speed 0, update the last_speed field.
 
		if (v->cur_speed != 0) return;
 
	} else {
 
		TrainCheckIfLineEnds(v);
 

	
 
		do {
 
			TrainController(v);
 
			CheckTrainCollision(v);
 
			if (v->cur_speed <= 0x100)
 
				break;
 
		} while (--j != 0);
 
	}
 

	
 
	SetLastSpeed(v, v->cur_speed);
 
}
 

	
 

	
 
void Train_Tick(Vehicle *v)
 
{
 
	if (_age_cargo_skip_counter == 0 && v->cargo_days != 0xff)
 
		v->cargo_days++;
 

	
 
	v->tick_counter++;
 

	
 
	if (IsFrontEngine(v)) {
 
		TrainLocoHandler(v, false);
 

	
 
		// make sure vehicle wasn't deleted.
 
		if (v->type == VEH_Train && IsFrontEngine(v))
 
			TrainLocoHandler(v, true);
 
	} else if (IsFreeWagon(v) && HASBITS(v->vehstatus, VS_CRASHED)) {
 
		// Delete flooded standalone wagon
 
		if (++v->u.rail.crash_anim_pos >= 4400)
 
			DeleteVehicle(v);
 
	}
 
}
 

	
 

	
 
void TrainEnterDepot(Vehicle *v, TileIndex tile)
 
{
 
	UpdateSignalsOnSegment(tile, GetRailDepotDirection(tile));
 

	
 
	if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 

	
 
	v->load_unload_time_rem = 0;
 
	v->cur_speed = 0;
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 
		int32 cost;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		t = v->current_order;
 
		v->current_order.type = OT_DUMMY;
 
		v->current_order.flags = 0;
 

	
 
		_current_player = v->owner;
 
		cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_RAIL_VEHICLE);
 
		if (!CmdFailed(cost) && v->owner == _local_player && cost != 0) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 

	
 
		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) { // Part of the orderlist?
 
			v->u.rail.days_since_order_progr = 0;
 
			v->cur_order_index++;
 
		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) { // User initiated?
 
			v->vehstatus |= VS_STOPPED;
 
			if (v->owner == _local_player) {
 
				SetDParam(0, v->unitnumber);
 
				AddNewsItem(
 
					STR_8814_TRAIN_IS_WAITING_IN_DEPOT,
 
					NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),
 
					v->index,
 
					0
 
				);
 
			}
 
		}
 
	}
 
	InvalidateWindowClasses(WC_TRAINS_LIST);
 
}
 

	
 
#define MAX_ACCEPTABLE_DEPOT_DIST 16
 

	
 
static void CheckIfTrainNeedsService(Vehicle *v)
 
{
 
	const Depot* depot;
 
	TrainFindDepotData tfdd;
 

	
 
	if (_patches.servint_trains == 0)                   return;
 
	if (!VehicleNeedsService(v))                        return;
 
	if (v->vehstatus & VS_STOPPED)                      return;
 
	if (_patches.gotodepot && VehicleHasDepotOrders(v)) return;
 

	
 
	// Don't interfere with a depot visit scheduled by the user, or a
 
	// depot visit by the order list.
 
	if (v->current_order.type == OT_GOTO_DEPOT &&
 
			(v->current_order.flags & (OF_HALT_IN_DEPOT | OF_PART_OF_ORDERS)) != 0)
 
		return;
 

	
 
	if (CheckTrainIsInsideDepot(v)) {
 
		VehicleServiceInDepot(v);
 
		return;
 
	}
 

	
 
	tfdd = FindClosestTrainDepot(v, MAX_ACCEPTABLE_DEPOT_DIST);
 
	/* Only go to the depot if it is not too far out of our way. */
 
	if (tfdd.best_length == (uint)-1 || tfdd.best_length > MAX_ACCEPTABLE_DEPOT_DIST) {
 
		if (v->current_order.type == OT_GOTO_DEPOT) {
 
			/* If we were already heading for a depot but it has
 
			 * suddenly moved farther away, we continue our normal
 
			 * schedule? */
 
			v->current_order.type = OT_DUMMY;
 
			v->current_order.flags = 0;
 
			InvalidateWindowWidget(WC_VEHICLE_VIEW, v->index, STATUS_BAR);
 
		}
 
		return;
 
	}
 

	
 
	depot = GetDepotByTile(tfdd.tile);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT &&
 
			v->current_order.dest != depot->index &&
 
			!CHANCE16(3, 16)) {
 
		return;
 
	}
 

	
 
	v->current_order.type = OT_GOTO_DEPOT;
 
	v->current_order.flags = OF_NON_STOP;
 
	v->current_order.dest = depot->index;
vehicle.c
Show inline comments
 
@@ -61,96 +61,97 @@ static const uint32 _veh_sell_proc_table
 
	CMD_SELL_ROAD_VEH,
 
	CMD_SELL_SHIP,
 
	CMD_SELL_AIRCRAFT,
 
};
 

	
 
static const uint32 _veh_refit_proc_table[] = {
 
	CMD_REFIT_RAIL_VEHICLE,
 
	CMD_REFIT_ROAD_VEH,
 
	CMD_REFIT_SHIP,
 
	CMD_REFIT_AIRCRAFT,
 
};
 

	
 
const uint32 _send_to_depot_proc_table[] = {
 
	CMD_SEND_TRAIN_TO_DEPOT,
 
	CMD_SEND_ROADVEH_TO_DEPOT,
 
	CMD_SEND_SHIP_TO_DEPOT,
 
	CMD_SEND_AIRCRAFT_TO_HANGAR,
 
};
 

	
 

	
 
enum {
 
	/* Max vehicles: 64000 (512 * 125) */
 
	VEHICLES_POOL_BLOCK_SIZE_BITS = 9,       /* In bits, so (1 << 9) == 512 */
 
	VEHICLES_POOL_MAX_BLOCKS      = 125,
 

	
 
	BLOCKS_FOR_SPECIAL_VEHICLES   = 2, ///< Blocks needed for special vehicles
 
};
 

	
 
/**
 
 * Called if a new block is added to the vehicle-pool
 
 */
 
static void VehiclePoolNewBlock(uint start_item)
 
{
 
	Vehicle *v;
 

	
 
	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
 
	 * TODO - This is just a temporary stage, this will be removed. */
 
	for (v = GetVehicle(start_item); v != NULL; v = (v->index + 1 < GetVehiclePoolSize()) ? GetVehicle(v->index + 1) : NULL) v->index = start_item++;
 
}
 

	
 
/* Initialize the vehicle-pool */
 
MemoryPool _vehicle_pool = { "Vehicle", VEHICLES_POOL_MAX_BLOCKS, VEHICLES_POOL_BLOCK_SIZE_BITS, sizeof(Vehicle), &VehiclePoolNewBlock, NULL, 0, 0, NULL };
 

	
 
void VehicleServiceInDepot(Vehicle *v)
 
{
 
	v->date_of_last_service = _date;
 
	v->breakdowns_since_last_service = 0;
 
	v->reliability = GetEngine(v->engine_type)->reliability;
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index); // ensure that last service date and reliability are updated
 
}
 

	
 
bool VehicleNeedsService(const Vehicle *v)
 
{
 
	if (v->vehstatus & VS_CRASHED)
 
		return false; /* Crashed vehicles don't need service anymore */
 

	
 
	if (_patches.no_servicing_if_no_breakdowns && _opt.diff.vehicle_breakdowns == 0) {
 
		return EngineHasReplacementForPlayer(GetPlayer(v->owner), v->engine_type);  /* Vehicles set for autoreplacing needs to go to a depot even if breakdowns are turned off */
 
	}
 

	
 
	return _patches.servint_ispercent ?
 
		(v->reliability < GetEngine(v->engine_type)->reliability * (100 - v->service_interval) / 100) :
 
		(v->date_of_last_service + v->service_interval < _date);
 
}
 

	
 
StringID VehicleInTheWayErrMsg(const Vehicle* v)
 
{
 
	switch (v->type) {
 
		case VEH_Train:    return STR_8803_TRAIN_IN_THE_WAY;
 
		case VEH_Road:     return STR_9000_ROAD_VEHICLE_IN_THE_WAY;
 
		case VEH_Aircraft: return STR_A015_AIRCRAFT_IN_THE_WAY;
 
		default:           return STR_980E_SHIP_IN_THE_WAY;
 
	}
 
}
 

	
 
static void *EnsureNoVehicleProc(Vehicle *v, void *data)
 
{
 
	if (v->tile != *(const TileIndex*)data || v->type == VEH_Disaster)
 
		return NULL;
 

	
 
	_error_message = VehicleInTheWayErrMsg(v);
 
	return v;
 
}
 

	
 
bool EnsureNoVehicle(TileIndex tile)
 
{
 
	return VehicleFromPos(tile, &tile, EnsureNoVehicleProc) == NULL;
 
}
 

	
 
static void *EnsureNoVehicleProcZ(Vehicle *v, void *data)
 
{
 
	const TileInfo *ti = data;
 

	
 
	if (v->tile != ti->tile || v->type == VEH_Disaster) return NULL;
 
	if (v->z_pos > ti->z) return NULL;
 

	
 
	_error_message = VehicleInTheWayErrMsg(v);
 
@@ -2371,96 +2372,174 @@ uint GenerateVehicleSortList(const Vehic
 

	
 
	if ((n + 100) < *length_of_array) {
 
		/* We allocated way too much for sort_list.
 
		 * Now we will reduce how much we allocated.
 
		 * We will still make it have room for 50 extra vehicles to prevent having
 
		 * to move the whole array if just one vehicle is added later */
 
		*length_of_array = n + 50;
 
		*sort_list = realloc((void*)*sort_list, (*length_of_array) * sizeof((*sort_list)[0]));
 
	}
 

	
 
	return n;
 
}
 

	
 
/** send all vehicles of type to depots
 
 * @param type type of vehicle
 
 * @param flags the flags used for DoCommand()
 
 * @param service should the vehicles only get service in the depots
 
 * @param owner PlayerID of owner of the vehicles to send
 
 * @param VLW_flag tells what kind of list requested the goto depot
 
 * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot
 
 */
 
int32 SendAllVehiclesToDepot(byte type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id)
 
{
 
	const Vehicle **sort_list = NULL;
 
	uint n, i;
 
	uint16 array_length = 0;
 

	
 
	n = GenerateVehicleSortList(&sort_list, &array_length, type, owner, id, id, id, vlw_flag);
 

	
 
	/* Send all the vehicles to a depot */
 
	for (i = 0; i < n; i++) {
 
		const Vehicle *v = sort_list[i];
 
		int32 ret = DoCommand(v->tile, v->index, service | DEPOT_DONT_CANCEL, flags, CMD_SEND_TO_DEPOT(type));
 

	
 
		/* Return 0 if DC_EXEC is not set this is a valid goto depot command)
 
			* In this case we know that at least one vehicle can be sent to a depot
 
			* and we will issue the command. We can now safely quit the loop, knowing
 
			* it will succeed at least once. With DC_EXEC we really need to send them to the depot */
 
		if (!CmdFailed(ret) && !(flags & DC_EXEC)) {
 
			free((void*)sort_list);
 
			return 0;
 
		}
 
	}
 

	
 
	free((void*)sort_list);
 
	return (flags & DC_EXEC) ? 0 : CMD_ERROR;
 
}
 

	
 
void VehicleEnterDepot(Vehicle *v)
 
{
 
	switch (v->type) {
 
		case VEH_Train:
 
			InvalidateWindowClasses(WC_TRAINS_LIST);
 
			if (!IsFrontEngine(v)) v = GetFirstVehicleInChain(v);
 
			UpdateSignalsOnSegment(v->tile, GetRailDepotDirection(v->tile));
 
			v->load_unload_time_rem = 0;
 
			break;
 

	
 
		case VEH_Road:
 
			InvalidateWindowClasses(WC_ROADVEH_LIST);
 
			v->u.road.state = 254;
 
			break;
 

	
 
		case VEH_Ship:
 
			InvalidateWindowClasses(WC_SHIPS_LIST);
 
			v->u.ship.state = 0x80;
 
			RecalcShipStuff(v);
 
			break;
 

	
 
		case VEH_Aircraft:
 
			InvalidateWindowClasses(WC_AIRCRAFT_LIST);
 
			HandleAircraftEnterHangar(v);
 
			break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 

	
 
	v->vehstatus |= VS_HIDDEN;
 
	v->cur_speed = 0;
 

	
 
	VehicleServiceInDepot(v);
 

	
 
	TriggerVehicle(v, VEHICLE_TRIGGER_DEPOT);
 

	
 
	if (v->current_order.type == OT_GOTO_DEPOT) {
 
		Order t;
 

	
 
		InvalidateWindow(WC_VEHICLE_VIEW, v->index);
 

	
 
		t = v->current_order;
 
		v->current_order.type = OT_DUMMY;
 
		v->current_order.flags = 0;
 

	
 
		if (t.refit_cargo != CT_NO_REFIT) {
 
			int32 cost;
 

	
 
			_current_player = v->owner;
 
			cost = DoCommand(v->tile, v->index, t.refit_cargo | t.refit_subtype << 8, DC_EXEC, CMD_REFIT_VEH(v->type));
 
			if (!CmdFailed(cost) && v->owner == _local_player && cost != 0) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost);
 
		}
 

	
 
		if (HASBIT(t.flags, OFB_PART_OF_ORDERS)) {
 
			/* Part of orders */
 
			if (v->type == VEH_Train) v->u.rail.days_since_order_progr = 0;
 
			v->cur_order_index++;
 
		} else if (HASBIT(t.flags, OFB_HALT_IN_DEPOT)) {
 
			/* Force depot visit */
 
			v->vehstatus |= VS_STOPPED;
 
			if (v->owner == _local_player) {
 
				StringID string;
 

	
 
				switch (v->type) {
 
					case VEH_Train:    string = STR_8814_TRAIN_IS_WAITING_IN_DEPOT; break;
 
					case VEH_Road:     string = STR_9016_ROAD_VEHICLE_IS_WAITING;   break;
 
					case VEH_Ship:     string = STR_981C_SHIP_IS_WAITING_IN_DEPOT;  break;
 
					case VEH_Aircraft: string = STR_A014_AIRCRAFT_IS_WAITING_IN;    break;
 
					default: NOT_REACHED(); string = STR_EMPTY; // Set the string to something to avoid a compiler warning
 
				}
 

	
 
				SetDParam(0, v->unitnumber);
 
				AddNewsItem(string, NEWS_FLAGS(NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, 0),	v->index, 0);
 
			}
 
		}
 
	}
 
}
 

	
 
/** Give a custom name to your vehicle
 
 * @param tile unused
 
 * @param p1 vehicle ID to name
 
 * @param p2 unused
 
 */
 
int32 CmdNameVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Vehicle *v;
 
	StringID str;
 

	
 
	if (!IsValidVehicleID(p1) || _cmd_text[0] == '\0') return CMD_ERROR;
 

	
 
	v = GetVehicle(p1);
 

	
 
	if (!CheckOwnership(v->owner)) return CMD_ERROR;
 

	
 
	str = AllocateNameUnique(_cmd_text, 2);
 
	if (str == 0) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		StringID old_str = v->string_id;
 
		v->string_id = str;
 
		DeleteName(old_str);
 
		ResortVehicleLists();
 
		MarkWholeScreenDirty();
 
	} else {
 
		DeleteName(str);
 
	}
 

	
 
	return 0;
 
}
 

	
 

	
 
/** Change the service interval of a vehicle
 
 * @param tile unused
 
 * @param p1 vehicle ID that is being service-interval-changed
 
 * @param p2 new service interval
 
 */
 
int32 CmdChangeServiceInt(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	Vehicle* v;
 
	uint16 serv_int = GetServiceIntervalClamped(p2); /* Double check the service interval from the user-input */
 

	
 
	if (serv_int != p2 || !IsValidVehicleID(p1)) return CMD_ERROR;
 

	
 
	v = GetVehicle(p1);
 

	
vehicle.h
Show inline comments
 
@@ -227,144 +227,143 @@ struct Vehicle {
 

	
 
	int32 profit_this_year;
 
	int32 profit_last_year;
 
	uint32 value;
 

	
 
	union {
 
		VehicleRail rail;
 
		VehicleAir air;
 
		VehicleRoad road;
 
		VehicleSpecial special;
 
		VehicleDisaster disaster;
 
		VehicleShip ship;
 
	} u;
 
};
 

	
 
#define is_custom_sprite(x) (x >= 0xFD)
 
#define IS_CUSTOM_FIRSTHEAD_SPRITE(x) (x == 0xFD)
 
#define IS_CUSTOM_SECONDHEAD_SPRITE(x) (x == 0xFE)
 

	
 
typedef void *VehicleFromPosProc(Vehicle *v, void *data);
 

	
 
void VehicleServiceInDepot(Vehicle *v);
 
Vehicle *AllocateVehicle(void);
 
bool AllocateVehicles(Vehicle **vl, int num);
 
Vehicle *ForceAllocateVehicle(void);
 
Vehicle *ForceAllocateSpecialVehicle(void);
 
void VehiclePositionChanged(Vehicle *v);
 
void AfterLoadVehicles(void);
 
Vehicle *GetLastVehicleInChain(Vehicle *v);
 
Vehicle *GetPrevVehicleInChain(const Vehicle *v);
 
Vehicle *GetFirstVehicleInChain(const Vehicle *v);
 
uint CountVehiclesInChain(const Vehicle* v);
 
bool IsEngineCountable(const Vehicle *v);
 
void DeleteVehicleChain(Vehicle *v);
 
void *VehicleFromPos(TileIndex tile, void *data, VehicleFromPosProc *proc);
 
void CallVehicleTicks(void);
 
Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
 

	
 
void InitializeTrains(void);
 
byte VehicleRandomBits(void);
 

	
 
bool CanFillVehicle(Vehicle *v);
 
bool CanRefitTo(EngineID engine_type, CargoID cid_to);
 
CargoID FindFirstRefittableCargo(EngineID engine_type);
 
int32 GetRefitCost(EngineID engine_type);
 

	
 
void ViewportAddVehicles(DrawPixelInfo *dpi);
 

	
 
void TrainEnterDepot(Vehicle *v, TileIndex tile);
 

	
 
/* train_cmd.h */
 
int GetTrainImage(const Vehicle* v, Direction direction);
 
int GetAircraftImage(const Vehicle* v, Direction direction);
 
int GetRoadVehImage(const Vehicle* v, Direction direction);
 
int GetShipImage(const Vehicle* v, Direction direction);
 

	
 
Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type);
 
Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type);
 
Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type);
 

	
 
uint32 VehicleEnterTile(Vehicle *v, TileIndex tile, int x, int y);
 

	
 
StringID VehicleInTheWayErrMsg(const Vehicle* v);
 
Vehicle *FindVehicleBetween(TileIndex from, TileIndex to, byte z);
 
TileIndex GetVehicleOutOfTunnelTile(const Vehicle *v);
 

	
 
bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction);
 
void SetSignalsOnBothDir(TileIndex tile, byte track);
 

	
 
Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y);
 

	
 
void DecreaseVehicleValue(Vehicle *v);
 
void CheckVehicleBreakdown(Vehicle *v);
 
void AgeVehicle(Vehicle *v);
 
void VehicleEnteredDepotThisTick(Vehicle *v);
 

	
 
void BeginVehicleMove(Vehicle *v);
 
void EndVehicleMove(Vehicle *v);
 

	
 
void ShowAircraftViewWindow(const Vehicle* v);
 

	
 
UnitID GetFreeUnitNumber(byte type);
 

	
 
int LoadUnloadVehicle(Vehicle *v);
 

	
 
void TrainConsistChanged(Vehicle *v);
 
void TrainPowerChanged(Vehicle *v);
 
int32 GetTrainRunningCost(const Vehicle *v);
 

	
 
int CheckTrainStoppedInDepot(const Vehicle *v);
 

	
 
bool VehicleNeedsService(const Vehicle *v);
 

	
 
uint GenerateVehicleSortList(const Vehicle*** sort_list, uint16 *length_of_array, byte type, PlayerID owner, StationID station, OrderID order, uint16 depot_airport_index, uint16 window_type);
 
void BuildDepotVehicleList(byte type, TileIndex tile, Vehicle ***engine_list, uint16 *engine_list_length, uint16 *engine_count, Vehicle ***wagon_list, uint16 *wagon_list_length, uint16 *wagon_count);
 
int32 SendAllVehiclesToDepot(byte type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id);
 
void VehicleEnterDepot(Vehicle *v);
 

	
 
/* Flags to add to p2 for goto depot commands */
 
/* Note: bits 8-10 are used for VLW flags */
 
enum {
 
	DEPOT_SERVICE       = (1 << 0),	// The vehicle will leave the depot right after arrival (serivce only)
 
	DEPOT_MASS_SEND     = (1 << 1), // Tells that it's a mass send to depot command (type in VLW flag)
 
	DEPOT_DONT_CANCEL   = (1 << 2), // Don't cancel current goto depot command if any
 
	DEPOT_LOCATE_HANGAR = (1 << 3), // Find another airport if the target one lacks a hangar
 
};
 

	
 
typedef struct GetNewVehiclePosResult {
 
	int x,y;
 
	TileIndex old_tile;
 
	TileIndex new_tile;
 
} GetNewVehiclePosResult;
 

	
 
/**
 
 * Returns the Trackdir on which the vehicle is currently located.
 
 * Works for trains and ships.
 
 * Currently works only sortof for road vehicles, since they have a fuzzy
 
 * concept of being "on" a trackdir. Dunno really what it returns for a road
 
 * vehicle that is halfway a tile, never really understood that part. For road
 
 * vehicles that are at the beginning or end of the tile, should just return
 
 * the diagonal trackdir on which they are driving. I _think_.
 
 * For other vehicles types, or vehicles with no clear trackdir (such as those
 
 * in depots), returns 0xFF.
 
 */
 
Trackdir GetVehicleTrackdir(const Vehicle* v);
 

	
 
/* returns true if staying in the same tile */
 
bool GetNewVehiclePos(const Vehicle *v, GetNewVehiclePosResult *gp);
 
Direction GetDirectionTowards(const Vehicle* v, int x, int y);
 

	
 
#define BEGIN_ENUM_WAGONS(v) do {
 
#define END_ENUM_WAGONS(v) } while ( (v=v->next) != NULL);
 

	
 
extern MemoryPool _vehicle_pool;
 

	
 
/**
 
 * Get the pointer to the vehicle with index 'index'
 
 */
 
static inline Vehicle *GetVehicle(VehicleID index)
 
{
 
	return (Vehicle*)GetItemFromPool(&_vehicle_pool, index);
 
}
 

	
 
/**
 
 * Get the current size of the VehiclePool
0 comments (0 inline, 0 general)