File diff r24596:eddf98238034 → r24597:afde5721a3b6
src/order_cmd.cpp
Show inline comments
 
@@ -620,193 +620,193 @@ void OrderList::DebugCheckSanity() const
 
	Ticks check_timetable_duration = 0;
 
	Ticks check_total_duration = 0;
 

	
 
	DEBUG(misc, 6, "Checking OrderList %hu for sanity...", this->index);
 

	
 
	for (const Order *o = this->first; o != nullptr; o = o->next) {
 
		++check_num_orders;
 
		if (!o->IsType(OT_IMPLICIT)) ++check_num_manual_orders;
 
		check_timetable_duration += o->GetTimetabledWait() + o->GetTimetabledTravel();
 
		check_total_duration += o->GetWaitTime() + o->GetTravelTime();
 
	}
 
	assert(this->num_orders == check_num_orders);
 
	assert(this->num_manual_orders == check_num_manual_orders);
 
	assert(this->timetable_duration == check_timetable_duration);
 
	assert(this->total_duration == check_total_duration);
 

	
 
	for (const Vehicle *v = this->first_shared; v != nullptr; v = v->NextShared()) {
 
		++check_num_vehicles;
 
		assert(v->orders.list == this);
 
	}
 
	assert(this->num_vehicles == check_num_vehicles);
 
	DEBUG(misc, 6, "... detected %u orders (%u manual), %u vehicles, %i timetabled, %i total",
 
			(uint)this->num_orders, (uint)this->num_manual_orders,
 
			this->num_vehicles, this->timetable_duration, this->total_duration);
 
}
 

	
 
/**
 
 * Checks whether the order goes to a station or not, i.e. whether the
 
 * destination is a station
 
 * @param v the vehicle to check for
 
 * @param o the order to check
 
 * @return true if the destination is a station
 
 */
 
static inline bool OrderGoesToStation(const Vehicle *v, const Order *o)
 
{
 
	return o->IsType(OT_GOTO_STATION) ||
 
			(v->type == VEH_AIRCRAFT && o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotActionType() & ODATFB_NEAREST_DEPOT));
 
}
 

	
 
/**
 
 * Delete all news items regarding defective orders about a vehicle
 
 * This could kill still valid warnings (for example about void order when just
 
 * another order gets added), but assume the company will notice the problems,
 
 * when (s)he's changing the orders.
 
 */
 
static void DeleteOrderWarnings(const Vehicle *v)
 
{
 
	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_TOO_FEW_ORDERS);
 
	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_VOID_ORDER);
 
	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_DUPLICATE_ENTRY);
 
	DeleteVehicleNews(v->index, STR_NEWS_VEHICLE_HAS_INVALID_ENTRY);
 
	DeleteVehicleNews(v->index, STR_NEWS_PLANE_USES_TOO_SHORT_RUNWAY);
 
}
 

	
 
/**
 
 * Returns a tile somewhat representing the order destination (not suitable for pathfinding).
 
 * @param v The vehicle to get the location for.
 
 * @param airport Get the airport tile and not the station location for aircraft.
 
 * @return destination of order, or INVALID_TILE if none.
 
 */
 
TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
 
{
 
	switch (this->GetType()) {
 
		case OT_GOTO_WAYPOINT:
 
		case OT_GOTO_STATION:
 
		case OT_IMPLICIT:
 
			if (airport && v->type == VEH_AIRCRAFT) return Station::Get(this->GetDestination())->airport.tile;
 
			return BaseStation::Get(this->GetDestination())->xy;
 

	
 
		case OT_GOTO_DEPOT:
 
			if ((this->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) return INVALID_TILE;
 
			return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy;
 

	
 
		default:
 
			return INVALID_TILE;
 
	}
 
}
 

	
 
/**
 
 * Get the distance between two orders of a vehicle. Conditional orders are resolved
 
 * and the bigger distance of the two order branches is returned.
 
 * @param prev Origin order.
 
 * @param cur Destination order.
 
 * @param v The vehicle to get the distance for.
 
 * @param conditional_depth Internal param for resolving conditional orders.
 
 * @return Maximum distance between the two orders.
 
 */
 
uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth)
 
{
 
	if (cur->IsType(OT_CONDITIONAL)) {
 
		if (conditional_depth > v->GetNumOrders()) return 0;
 

	
 
		conditional_depth++;
 

	
 
		int dist1 = GetOrderDistance(prev, v->GetOrder(cur->GetConditionSkipToOrder()), v, conditional_depth);
 
		int dist2 = GetOrderDistance(prev, cur->next == nullptr ? v->orders.list->GetFirstOrder() : cur->next, v, conditional_depth);
 
		return max(dist1, dist2);
 
		return std::max(dist1, dist2);
 
	}
 

	
 
	TileIndex prev_tile = prev->GetLocation(v, true);
 
	TileIndex cur_tile = cur->GetLocation(v, true);
 
	if (prev_tile == INVALID_TILE || cur_tile == INVALID_TILE) return 0;
 
	return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
 
}
 

	
 
/**
 
 * Add an order to the orderlist of a vehicle.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 various bitstuffed elements
 
 * - p1 = (bit  0 - 19) - ID of the vehicle
 
 * - p1 = (bit 24 - 31) - the selected order (if any). If the last order is given,
 
 *                        the order will be inserted before that one
 
 *                        the maximum vehicle order id is 254.
 
 * @param p2 packed order to insert
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdInsertOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	VehicleID veh          = GB(p1,  0, 20);
 
	VehicleOrderID sel_ord = GB(p1, 20, 8);
 
	Order new_order(p2);
 

	
 
	Vehicle *v = Vehicle::GetIfValid(veh);
 
	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckOwnership(v->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	/* Check if the inserted order is to the correct destination (owner, type),
 
	 * and has the correct flags if any */
 
	switch (new_order.GetType()) {
 
		case OT_GOTO_STATION: {
 
			const Station *st = Station::GetIfValid(new_order.GetDestination());
 
			if (st == nullptr) return CMD_ERROR;
 

	
 
			if (st->owner != OWNER_NONE) {
 
				CommandCost ret = CheckOwnership(st->owner);
 
				if (ret.Failed()) return ret;
 
			}
 

	
 
			if (!CanVehicleUseStation(v, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
 
			for (Vehicle *u = v->FirstShared(); u != nullptr; u = u->NextShared()) {
 
				if (!CanVehicleUseStation(u, st)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER_SHARED);
 
			}
 

	
 
			/* Non stop only allowed for ground vehicles. */
 
			if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
 

	
 
			/* Filter invalid load/unload types. */
 
			switch (new_order.GetLoadType()) {
 
				case OLF_LOAD_IF_POSSIBLE: case OLFB_FULL_LOAD: case OLF_FULL_LOAD_ANY: case OLFB_NO_LOAD: break;
 
				default: return CMD_ERROR;
 
			}
 
			switch (new_order.GetUnloadType()) {
 
				case OUF_UNLOAD_IF_POSSIBLE: case OUFB_UNLOAD: case OUFB_TRANSFER: case OUFB_NO_UNLOAD: break;
 
				default: return CMD_ERROR;
 
			}
 

	
 
			/* Filter invalid stop locations */
 
			switch (new_order.GetStopLocation()) {
 
				case OSL_PLATFORM_NEAR_END:
 
				case OSL_PLATFORM_MIDDLE:
 
					if (v->type != VEH_TRAIN) return CMD_ERROR;
 
					FALLTHROUGH;
 

	
 
				case OSL_PLATFORM_FAR_END:
 
					break;
 

	
 
				default:
 
					return CMD_ERROR;
 
			}
 

	
 
			break;
 
		}
 

	
 
		case OT_GOTO_DEPOT: {
 
			if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
 
				if (v->type == VEH_AIRCRAFT) {
 
					const Station *st = Station::GetIfValid(new_order.GetDestination());
 

	
 
					if (st == nullptr) return CMD_ERROR;
 

	
 
					CommandCost ret = CheckOwnership(st->owner);
 
					if (ret.Failed()) return ret;
 

	
 
					if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) {
 
						return CMD_ERROR;
 
					}
 
				} else {
 
					const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
 

	
 
@@ -1000,193 +1000,193 @@ static CommandCost DecloneOrder(Vehicle 
 
	}
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Delete an order from the orderlist of a vehicle.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 the ID of the vehicle
 
 * @param p2 the order to delete (max 255)
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdDeleteOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	VehicleID veh_id = GB(p1, 0, 20);
 
	VehicleOrderID sel_ord = GB(p2, 0, 8);
 

	
 
	Vehicle *v = Vehicle::GetIfValid(veh_id);
 

	
 
	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckOwnership(v->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	/* If we did not select an order, we maybe want to de-clone the orders */
 
	if (sel_ord >= v->GetNumOrders()) return DecloneOrder(v, flags);
 

	
 
	if (v->GetOrder(sel_ord) == nullptr) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) DeleteOrder(v, sel_ord);
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Cancel the current loading order of the vehicle as the order was deleted.
 
 * @param v the vehicle
 
 */
 
static void CancelLoadingDueToDeletedOrder(Vehicle *v)
 
{
 
	assert(v->current_order.IsType(OT_LOADING));
 
	/* NON-stop flag is misused to see if a train is in a station that is
 
	 * on his order list or not */
 
	v->current_order.SetNonStopType(ONSF_STOP_EVERYWHERE);
 
	/* When full loading, "cancel" that order so the vehicle doesn't
 
	 * stay indefinitely at this station anymore. */
 
	if (v->current_order.GetLoadType() & OLFB_FULL_LOAD) v->current_order.SetLoadType(OLF_LOAD_IF_POSSIBLE);
 
}
 

	
 
/**
 
 * Delete an order but skip the parameter validation.
 
 * @param v       The vehicle to delete the order from.
 
 * @param sel_ord The id of the order to be deleted.
 
 */
 
void DeleteOrder(Vehicle *v, VehicleOrderID sel_ord)
 
{
 
	v->orders.list->DeleteOrderAt(sel_ord);
 

	
 
	Vehicle *u = v->FirstShared();
 
	DeleteOrderWarnings(u);
 
	for (; u != nullptr; u = u->NextShared()) {
 
		assert(v->orders.list == u->orders.list);
 

	
 
		if (sel_ord == u->cur_real_order_index && u->current_order.IsType(OT_LOADING)) {
 
			CancelLoadingDueToDeletedOrder(u);
 
		}
 

	
 
		if (sel_ord < u->cur_real_order_index) {
 
			u->cur_real_order_index--;
 
		} else if (sel_ord == u->cur_real_order_index) {
 
			u->UpdateRealOrderIndex();
 
		}
 

	
 
		if (sel_ord < u->cur_implicit_order_index) {
 
			u->cur_implicit_order_index--;
 
		} else if (sel_ord == u->cur_implicit_order_index) {
 
			/* Make sure the index is valid */
 
			if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
 

	
 
			/* Skip non-implicit orders for the implicit-order-index (e.g. if the current implicit order was deleted */
 
			while (u->cur_implicit_order_index != u->cur_real_order_index && !u->GetOrder(u->cur_implicit_order_index)->IsType(OT_IMPLICIT)) {
 
				u->cur_implicit_order_index++;
 
				if (u->cur_implicit_order_index >= u->GetNumOrders()) u->cur_implicit_order_index = 0;
 
			}
 
		}
 

	
 
		/* Update any possible open window of the vehicle */
 
		InvalidateVehicleOrder(u, sel_ord | (INVALID_VEH_ORDER_ID << 8));
 
	}
 

	
 
	/* As we delete an order, the order to skip to will be 'wrong'. */
 
	VehicleOrderID cur_order_id = 0;
 
	for (Order *order : v->Orders()) {
 
		if (order->IsType(OT_CONDITIONAL)) {
 
			VehicleOrderID order_id = order->GetConditionSkipToOrder();
 
			if (order_id >= sel_ord) {
 
				order_id = max(order_id - 1, 0);
 
				order_id = std::max(order_id - 1, 0);
 
			}
 
			if (order_id == cur_order_id) {
 
				order_id = (order_id + 1) % v->GetNumOrders();
 
			}
 
			order->SetConditionSkipToOrder(order_id);
 
		}
 
		cur_order_id++;
 
	}
 

	
 
	InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
 
}
 

	
 
/**
 
 * Goto order of order-list.
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 The ID of the vehicle which order is skipped
 
 * @param p2 the selected order to which we want to skip
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSkipToOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	VehicleID veh_id = GB(p1, 0, 20);
 
	VehicleOrderID sel_ord = GB(p2, 0, 8);
 

	
 
	Vehicle *v = Vehicle::GetIfValid(veh_id);
 

	
 
	if (v == nullptr || !v->IsPrimaryVehicle() || sel_ord == v->cur_implicit_order_index || sel_ord >= v->GetNumOrders() || v->GetNumOrders() < 2) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckOwnership(v->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	if (flags & DC_EXEC) {
 
		if (v->current_order.IsType(OT_LOADING)) v->LeaveStation();
 

	
 
		v->cur_implicit_order_index = v->cur_real_order_index = sel_ord;
 
		v->UpdateRealOrderIndex();
 

	
 
		InvalidateVehicleOrder(v, VIWD_MODIFY_ORDERS);
 
	}
 

	
 
	/* We have an aircraft/ship, they have a mini-schedule, so update them all */
 
	if (v->type == VEH_AIRCRAFT) SetWindowClassesDirty(WC_AIRCRAFT_LIST);
 
	if (v->type == VEH_SHIP) SetWindowClassesDirty(WC_SHIPS_LIST);
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Move an order inside the orderlist
 
 * @param tile unused
 
 * @param flags operation to perform
 
 * @param p1 the ID of the vehicle
 
 * @param p2 order to move and target
 
 *           bit 0-15  : the order to move
 
 *           bit 16-31 : the target order
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 * @note The target order will move one place down in the orderlist
 
 *  if you move the order upwards else it'll move it one place down
 
 */
 
CommandCost CmdMoveOrder(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	VehicleID veh = GB(p1, 0, 20);
 
	VehicleOrderID moving_order = GB(p2,  0, 16);
 
	VehicleOrderID target_order = GB(p2, 16, 16);
 

	
 
	Vehicle *v = Vehicle::GetIfValid(veh);
 
	if (v == nullptr || !v->IsPrimaryVehicle()) return CMD_ERROR;
 

	
 
	CommandCost ret = CheckOwnership(v->owner);
 
	if (ret.Failed()) return ret;
 

	
 
	/* Don't make senseless movements */
 
	if (moving_order >= v->GetNumOrders() || target_order >= v->GetNumOrders() ||
 
			moving_order == target_order || v->GetNumOrders() <= 1) return CMD_ERROR;
 

	
 
	Order *moving_one = v->GetOrder(moving_order);
 
	/* Don't move an empty order */
 
	if (moving_one == nullptr) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		v->orders.list->MoveOrder(moving_order, target_order);
 

	
 
		/* Update shared list */
 
		Vehicle *u = v->FirstShared();
 

	
 
		DeleteOrderWarnings(u);
 

	
 
		for (; u != nullptr; u = u->NextShared()) {
 
			/* Update the current order.
 
			 * There are multiple ways to move orders, which result in cur_implicit_order_index
 
			 * and cur_real_order_index to not longer make any sense. E.g. moving another
 
			 * real order between them.
 
			 *
 
@@ -1892,193 +1892,193 @@ void DeleteVehicleOrders(Vehicle *v, boo
 
	DeleteOrderWarnings(v);
 

	
 
	if (v->IsOrderListShared()) {
 
		/* Remove ourself from the shared order list. */
 
		v->RemoveFromShared();
 
		v->orders.list = nullptr;
 
	} else if (v->orders.list != nullptr) {
 
		/* Remove the orders */
 
		v->orders.list->FreeChain(keep_orderlist);
 
		if (!keep_orderlist) v->orders.list = nullptr;
 
	}
 

	
 
	if (reset_order_indices) {
 
		v->cur_implicit_order_index = v->cur_real_order_index = 0;
 
		if (v->current_order.IsType(OT_LOADING)) {
 
			CancelLoadingDueToDeletedOrder(v);
 
		}
 
	}
 
}
 

	
 
/**
 
 * Clamp the service interval to the correct min/max. The actual min/max values
 
 * depend on whether it's in percent or days.
 
 * @param interval proposed service interval
 
 * @return Clamped service interval
 
 */
 
uint16 GetServiceIntervalClamped(uint interval, bool ispercent)
 
{
 
	return ispercent ? Clamp(interval, MIN_SERVINT_PERCENT, MAX_SERVINT_PERCENT) : Clamp(interval, MIN_SERVINT_DAYS, MAX_SERVINT_DAYS);
 
}
 

	
 
/**
 
 *
 
 * Check if a vehicle has any valid orders
 
 *
 
 * @return false if there are no valid orders
 
 * @note Conditional orders are not considered valid destination orders
 
 *
 
 */
 
static bool CheckForValidOrders(const Vehicle *v)
 
{
 
	for (const Order *order : v->Orders()) {
 
		switch (order->GetType()) {
 
			case OT_GOTO_STATION:
 
			case OT_GOTO_DEPOT:
 
			case OT_GOTO_WAYPOINT:
 
				return true;
 

	
 
			default:
 
				break;
 
		}
 
	}
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Compare the variable and value based on the given comparator.
 
 */
 
static bool OrderConditionCompare(OrderConditionComparator occ, int variable, int value)
 
{
 
	switch (occ) {
 
		case OCC_EQUALS:      return variable == value;
 
		case OCC_NOT_EQUALS:  return variable != value;
 
		case OCC_LESS_THAN:   return variable <  value;
 
		case OCC_LESS_EQUALS: return variable <= value;
 
		case OCC_MORE_THAN:   return variable >  value;
 
		case OCC_MORE_EQUALS: return variable >= value;
 
		case OCC_IS_TRUE:     return variable != 0;
 
		case OCC_IS_FALSE:    return variable == 0;
 
		default: NOT_REACHED();
 
	}
 
}
 

	
 
/**
 
 * Process a conditional order and determine the next order.
 
 * @param order the order the vehicle currently has
 
 * @param v the vehicle to update
 
 * @return index of next order to jump to, or INVALID_VEH_ORDER_ID to use the next order
 
 */
 
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v)
 
{
 
	if (order->GetType() != OT_CONDITIONAL) return INVALID_VEH_ORDER_ID;
 

	
 
	bool skip_order = false;
 
	OrderConditionComparator occ = order->GetConditionComparator();
 
	uint16 value = order->GetConditionValue();
 

	
 
	switch (order->GetConditionVariable()) {
 
		case OCV_LOAD_PERCENTAGE:    skip_order = OrderConditionCompare(occ, CalcPercentVehicleFilled(v, nullptr), value); break;
 
		case OCV_RELIABILITY:        skip_order = OrderConditionCompare(occ, ToPercent16(v->reliability),       value); break;
 
		case OCV_MAX_RELIABILITY:    skip_order = OrderConditionCompare(occ, ToPercent16(v->GetEngine()->reliability),   value); break;
 
		case OCV_MAX_SPEED:          skip_order = OrderConditionCompare(occ, v->GetDisplayMaxSpeed() * 10 / 16, value); break;
 
		case OCV_AGE:                skip_order = OrderConditionCompare(occ, v->age / DAYS_IN_LEAP_YEAR,        value); break;
 
		case OCV_REQUIRES_SERVICE:   skip_order = OrderConditionCompare(occ, v->NeedsServicing(),               value); break;
 
		case OCV_UNCONDITIONALLY:    skip_order = true; break;
 
		case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break;
 
		case OCV_REMAINING_LIFETIME: skip_order = OrderConditionCompare(occ, std::max(v->max_age - v->age + DAYS_IN_LEAP_YEAR - 1, 0) / DAYS_IN_LEAP_YEAR, value); break;
 
		default: NOT_REACHED();
 
	}
 

	
 
	return skip_order ? order->GetConditionSkipToOrder() : (VehicleOrderID)INVALID_VEH_ORDER_ID;
 
}
 

	
 
/**
 
 * Update the vehicle's destination tile from an order.
 
 * @param order the order the vehicle currently has
 
 * @param v the vehicle to update
 
 * @param conditional_depth the depth (amount of steps) to go with conditional orders. This to prevent infinite loops.
 
 * @param pbs_look_ahead Whether we are forecasting orders for pbs reservations in advance. If true, the order indices must not be modified.
 
 */
 
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool pbs_look_ahead)
 
{
 
	if (conditional_depth > v->GetNumOrders()) {
 
		v->current_order.Free();
 
		v->SetDestTile(0);
 
		return false;
 
	}
 

	
 
	switch (order->GetType()) {
 
		case OT_GOTO_STATION:
 
			v->SetDestTile(v->GetOrderStationLocation(order->GetDestination()));
 
			return true;
 

	
 
		case OT_GOTO_DEPOT:
 
			if ((order->GetDepotOrderType() & ODTFB_SERVICE) && !v->NeedsServicing()) {
 
				assert(!pbs_look_ahead);
 
				UpdateVehicleTimetable(v, true);
 
				v->IncrementRealOrderIndex();
 
				break;
 
			}
 

	
 
			if (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) {
 
				/* We need to search for the nearest depot (hangar). */
 
				TileIndex location;
 
				DestinationID destination;
 
				bool reverse;
 

	
 
				if (v->FindClosestDepot(&location, &destination, &reverse)) {
 
					/* PBS reservations cannot reverse */
 
					if (pbs_look_ahead && reverse) return false;
 

	
 
					v->SetDestTile(location);
 
					v->current_order.MakeGoToDepot(destination, v->current_order.GetDepotOrderType(), v->current_order.GetNonStopType(), (OrderDepotActionFlags)(v->current_order.GetDepotActionType() & ~ODATFB_NEAREST_DEPOT), v->current_order.GetRefitCargo());
 

	
 
					/* If there is no depot in front, reverse automatically (trains only) */
 
					if (v->type == VEH_TRAIN && reverse) DoCommand(v->tile, v->index, 0, DC_EXEC, CMD_REVERSE_TRAIN_DIRECTION);
 

	
 
					if (v->type == VEH_AIRCRAFT) {
 
						Aircraft *a = Aircraft::From(v);
 
						if (a->state == FLYING && a->targetairport != destination) {
 
							/* The aircraft is now heading for a different hangar than the next in the orders */
 
							extern void AircraftNextAirportPos_and_Order(Aircraft *a);
 
							AircraftNextAirportPos_and_Order(a);
 
						}
 
					}
 
					return true;
 
				}
 

	
 
				/* If there is no depot, we cannot help PBS either. */
 
				if (pbs_look_ahead) return false;
 

	
 
				UpdateVehicleTimetable(v, true);
 
				v->IncrementRealOrderIndex();
 
			} else {
 
				if (v->type != VEH_AIRCRAFT) {
 
					v->SetDestTile(Depot::Get(order->GetDestination())->xy);
 
				} else {
 
					Aircraft *a = Aircraft::From(v);
 
					DestinationID destination = a->current_order.GetDestination();
 
					if (a->targetairport != destination) {
 
						/* The aircraft is now heading for a different hangar than the next in the orders */
 
						a->SetDestTile(a->GetOrderStationLocation(destination));
 
					}
 
				}
 
				return true;
 
			}
 
			break;
 

	
 
		case OT_GOTO_WAYPOINT:
 
			v->SetDestTile(Waypoint::Get(order->GetDestination())->xy);
 
			return true;
 

	
 
		case OT_CONDITIONAL: {
 
			assert(!pbs_look_ahead);
 
			VehicleOrderID next_order = ProcessConditionalOrder(order, v);
 
			if (next_order != INVALID_VEH_ORDER_ID) {
 
				/* Jump to next_order. cur_implicit_order_index becomes exactly that order,
 
				 * cur_real_order_index might come after next_order. */
 
				UpdateVehicleTimetable(v, false);
 
				v->cur_implicit_order_index = v->cur_real_order_index = next_order;
 
				v->UpdateRealOrderIndex();
 
				v->current_order_time += v->GetOrder(v->cur_real_order_index)->GetTimetabledTravel();