1
0
Fork 0
pull/10691/merge
Joan Josep 2024-08-12 07:12:45 -04:00 committed by GitHub
commit c4f35c3faa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 205 additions and 110 deletions

View File

@ -41,6 +41,7 @@
#include "framerate_type.h" #include "framerate_type.h"
#include "aircraft_cmd.h" #include "aircraft_cmd.h"
#include "vehicle_cmd.h" #include "vehicle_cmd.h"
#include "depot_base.h"
#include "table/strings.h" #include "table/strings.h"
@ -136,7 +137,7 @@ static StationID FindNearestHangar(const Aircraft *v)
if (v->current_order.IsType(OT_GOTO_STATION) || if (v->current_order.IsType(OT_GOTO_STATION) ||
(v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) { (v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) {
last_dest = Station::GetIfValid(v->last_station_visited); last_dest = Station::GetIfValid(v->last_station_visited);
next_dest = Station::GetIfValid(v->current_order.GetDestination()); next_dest = Station::GetIfValid(GetTargetDestination(v->current_order, true));
} else { } else {
last_dest = GetTargetAirportIfValid(v); last_dest = GetTargetAirportIfValid(v);
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value); next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
@ -407,9 +408,10 @@ ClosestDepot Aircraft::FindClosestDepot()
if (station == INVALID_STATION) return ClosestDepot(); if (station == INVALID_STATION) return ClosestDepot();
st = Station::Get(station); st = Station::Get(station);
assert(st->airport.hangar != nullptr);
} }
return ClosestDepot(st->xy, st->index); return ClosestDepot(st->xy, st->airport.hangar->index);
} }
static void CheckIfAircraftNeedsService(Aircraft *v) static void CheckIfAircraftNeedsService(Aircraft *v)
@ -424,13 +426,13 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
* we don't want to consider going to a depot too. */ * we don't want to consider going to a depot too. */
if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return; if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return;
const Station *st = Station::Get(v->current_order.GetDestination()); const Station *st = Station::Get(GetTargetDestination(v->current_order, true));
assert(st != nullptr); assert(st != nullptr);
/* only goto depot if the target airport has a depot */ /* only goto depot if the target airport has a depot */
if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) { if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) {
v->current_order.MakeGoToDepot(st->index, ODTFB_SERVICE); v->current_order.MakeGoToDepot(st->airport.hangar->index, ODTFB_SERVICE);
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) { } else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
v->current_order.MakeDummy(); v->current_order.MakeDummy();
@ -892,7 +894,7 @@ static bool AircraftController(Aircraft *v)
/* Jump into our "holding pattern" state machine if possible */ /* Jump into our "holding pattern" state machine if possible */
if (v->pos >= afc->nofelements) { if (v->pos >= afc->nofelements) {
v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N); v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N);
} else if (v->targetairport != v->current_order.GetDestination()) { } else if (v->targetairport != GetTargetDestination(v->current_order, true)) {
/* If not possible, just get out of here fast */ /* If not possible, just get out of here fast */
v->state = FLYING; v->state = FLYING;
UpdateAircraftCache(v); UpdateAircraftCache(v);
@ -1449,7 +1451,7 @@ static void AircraftLandAirplane(Aircraft *v)
void AircraftNextAirportPos_and_Order(Aircraft *v) void AircraftNextAirportPos_and_Order(Aircraft *v)
{ {
if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) { if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) {
v->targetairport = v->current_order.GetDestination(); v->targetairport = GetTargetDestination(v->current_order, true);
} }
const Station *st = GetTargetAirportIfValid(v); const Station *st = GetTargetAirportIfValid(v);
@ -1539,7 +1541,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
return; return;
/* We are leaving a hangar, but have to go to the exact same one; re-enter */ /* We are leaving a hangar, but have to go to the exact same one; re-enter */
if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() == v->targetairport) { if (v->current_order.IsType(OT_GOTO_DEPOT) && GetTargetDestination(v->current_order, true) == v->targetairport) {
VehicleEnterDepot(v); VehicleEnterDepot(v);
return; return;
} }
@ -1548,7 +1550,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return; if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
/* We are already at the target airport, we need to find a terminal */ /* We are already at the target airport, we need to find a terminal */
if (v->current_order.GetDestination() == v->targetairport) { if (GetTargetDestination(v->current_order, true) == v->targetairport) {
/* FindFreeTerminal: /* FindFreeTerminal:
* 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */ * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */
if (v->subtype == AIR_HELICOPTER) { if (v->subtype == AIR_HELICOPTER) {
@ -1599,7 +1601,7 @@ static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *
case OT_GOTO_STATION: // ready to fly to another airport case OT_GOTO_STATION: // ready to fly to another airport
break; break;
case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc. case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc.
go_to_hangar = v->current_order.GetDestination() == v->targetairport; go_to_hangar = GetTargetDestination(v->current_order, true) == v->targetairport;
break; break;
case OT_CONDITIONAL: case OT_CONDITIONAL:
/* In case of a conditional order we just have to wait a tick /* In case of a conditional order we just have to wait a tick
@ -2103,7 +2105,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop)
/* Check the distance to the next destination. This code works because the target /* Check the distance to the next destination. This code works because the target
* airport is only updated after take off and not on the ground. */ * airport is only updated after take off and not on the ground. */
Station *cur_st = Station::GetIfValid(v->targetairport); Station *cur_st = Station::GetIfValid(v->targetairport);
Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : nullptr; Station *next_st = Station::GetIfValid(GetTargetDestination(v->current_order, true));
if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && next_st->airport.tile != INVALID_TILE) { if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && next_st->airport.tile != INVALID_TILE) {
uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile); uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile);
@ -2169,18 +2171,7 @@ void UpdateAirplanesOnNewStation(const Station *st)
if (!v->IsNormalAircraft() || v->targetairport != st->index) continue; if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
assert(v->state == FLYING); assert(v->state == FLYING);
Order *o = &v->current_order;
/* The aircraft is heading to a hangar, but the new station doesn't have one,
* or the aircraft can't land on the new station. Cancel current order. */
if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index &&
(!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
o->MakeDummy();
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
}
v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation); v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation);
UpdateAircraftCache(v); UpdateAircraftCache(v);
} }
/* Heliports don't have a hangar. Invalidate all go to hangar orders from all aircraft. */
if (!st->airport.HasHangar()) RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index, true);
} }

View File

@ -43,16 +43,21 @@ inline bool IsDepotTile(Tile tile)
return IsRailDepotTile(tile) || IsRoadDepotTile(tile) || IsShipDepotTile(tile) || IsHangarTile(tile); return IsRailDepotTile(tile) || IsRoadDepotTile(tile) || IsShipDepotTile(tile) || IsHangarTile(tile);
} }
extern DepotID GetHangarIndex(TileIndex t);
/** /**
* Get the index of which depot is attached to the tile. * Get the index of which depot is attached to the tile.
* @param t the tile * @param t the tile
* @pre IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t) * @pre IsDepotTile(t)
* @return DepotID * @return DepotID
*/ */
inline DepotID GetDepotIndex(Tile t) inline DepotID GetDepotIndex(Tile t)
{ {
/* Hangars don't have a Depot class, thus store no DepotID. */ assert(IsDepotTile(t));
assert(IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t));
/* Hangars don't store depot id on m2. */
if (IsTileType(t, MP_STATION)) return GetHangarIndex(t);
return t.m2(); return t.m2();
} }

View File

@ -246,18 +246,14 @@ CommandCost CmdClearOrderBackup(DoCommandFlag flags, TileIndex tile, ClientID us
* Removes an order from all vehicles. Triggers when, say, a station is removed. * Removes an order from all vehicles. Triggers when, say, a station is removed.
* @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]). * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
* @param destination The destination. Can be a StationID, DepotID or WaypointID. * @param destination The destination. Can be a StationID, DepotID or WaypointID.
* @param hangar Only used for airports in the destination.
* When false, remove airport and hangar orders.
* When true, remove either airport or hangar order.
*/ */
/* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination, bool hangar) /* static */ void OrderBackup::RemoveOrder(OrderType type, DestinationID destination)
{ {
for (OrderBackup *ob : OrderBackup::Iterate()) { for (OrderBackup *ob : OrderBackup::Iterate()) {
for (Order *order = ob->orders; order != nullptr; order = order->next) { for (Order *order = ob->orders; order != nullptr; order = order->next) {
OrderType ot = order->GetType(); OrderType ot = order->GetType();
if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue; if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
if (ot == OT_GOTO_DEPOT && hangar && !IsHangarTile(ob->tile)) continue; // Not an aircraft? Can't have a hangar order. if (ot == OT_IMPLICIT) ot = OT_GOTO_STATION;
if (ot == OT_IMPLICIT || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
if (ot == type && order->GetDestination() == destination) { if (ot == type && order->GetDestination() == destination) {
/* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */ /* Remove the order backup! If a station/depot gets removed, we can't/shouldn't restore those broken orders. */
delete ob; delete ob;

View File

@ -59,7 +59,7 @@ public:
static void ClearGroup(GroupID group); static void ClearGroup(GroupID group);
static void ClearVehicle(const Vehicle *v); static void ClearVehicle(const Vehicle *v);
static void RemoveOrder(OrderType type, DestinationID destination, bool hangar); static void RemoveOrder(OrderType type, DestinationID destination);
}; };
#endif /* ORDER_BACKUP_H */ #endif /* ORDER_BACKUP_H */

View File

@ -650,7 +650,7 @@ TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
case OT_GOTO_DEPOT: case OT_GOTO_DEPOT:
if (this->GetDestination() == INVALID_DEPOT) return INVALID_TILE; if (this->GetDestination() == INVALID_DEPOT) return INVALID_TILE;
return (v->type == VEH_AIRCRAFT) ? Station::Get(this->GetDestination())->xy : Depot::Get(this->GetDestination())->xy; return Depot::Get(this->GetDestination())->xy;
default: default:
return INVALID_TILE; return INVALID_TILE;
@ -684,6 +684,28 @@ uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int
return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile); return v->type == VEH_AIRCRAFT ? DistanceSquare(prev_tile, cur_tile) : DistanceManhattan(prev_tile, cur_tile);
} }
/**
* Get the station or depot index associated to an order of a vehicle.
* For aircraft, it will return the index of the associated station, even for go to hangar orders.
* @param o Order to check.
* @param is_aircraft Whether the order is of an aircraft vehicle.
* @return index associated to a station or depot, or INVALID_STATION.
*/
DestinationID GetTargetDestination(const Order &o, bool is_aircraft)
{
DestinationID destination_id = o.GetDestination();
switch (o.GetType()) {
case OT_GOTO_STATION:
return destination_id;
case OT_GOTO_DEPOT:
assert(Depot::IsValidID(destination_id));
return is_aircraft ? GetStationIndex(Depot::Get(destination_id)->xy) : destination_id;
default:
return INVALID_STATION;
}
}
/** /**
* Add an order to the orderlist of a vehicle. * Add an order to the orderlist of a vehicle.
* @param flags operation to perform * @param flags operation to perform
@ -763,40 +785,31 @@ CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID se
case OT_GOTO_DEPOT: { case OT_GOTO_DEPOT: {
if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) { if ((new_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0) {
if (v->type == VEH_AIRCRAFT) { const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
const Station *st = Station::GetIfValid(new_order.GetDestination());
if (st == nullptr) return CMD_ERROR; if (dp == nullptr) return CMD_ERROR;
ret = CheckOwnership(st->owner); ret = CheckOwnership(GetTileOwner(dp->xy));
if (ret.Failed()) return ret; if (ret.Failed()) return ret;
if (!CanVehicleUseStation(v, st) || !st->airport.HasHangar()) { switch (v->type) {
return CMD_ERROR; case VEH_TRAIN:
} if (!IsRailDepotTile(dp->xy)) return CMD_ERROR;
} else { break;
const Depot *dp = Depot::GetIfValid(new_order.GetDestination());
if (dp == nullptr) return CMD_ERROR; case VEH_ROAD:
if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
break;
ret = CheckOwnership(GetTileOwner(dp->xy)); case VEH_SHIP:
if (ret.Failed()) return ret; if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
break;
switch (v->type) { case VEH_AIRCRAFT:
case VEH_TRAIN: if (!CanVehicleUseStation(v, Station::GetByTile(dp->xy)) || !IsHangarTile(dp->xy)) return CMD_ERROR;
if (!IsRailDepotTile(dp->xy)) return CMD_ERROR; break;
break;
case VEH_ROAD:
if (!IsRoadDepotTile(dp->xy)) return CMD_ERROR;
break;
case VEH_SHIP:
if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
break;
default: return CMD_ERROR; default: return CMD_ERROR;
}
} }
} }
@ -1780,24 +1793,11 @@ void CheckOrders(const Vehicle *v)
* Removes an order from all vehicles. Triggers when, say, a station is removed. * Removes an order from all vehicles. Triggers when, say, a station is removed.
* @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]). * @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
* @param destination The destination. Can be a StationID, DepotID or WaypointID. * @param destination The destination. Can be a StationID, DepotID or WaypointID.
* @param hangar Only used for airports in the destination.
* When false, remove airport and hangar orders.
* When true, remove either airport or hangar order.
*/ */
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar) void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination)
{ {
/* Aircraft have StationIDs for depot orders and never use DepotIDs
* This fact is handled specially below
*/
/* Go through all vehicles */ /* Go through all vehicles */
for (Vehicle *v : Vehicle::Iterate()) { for (Vehicle *v : Vehicle::Iterate()) {
if ((v->type == VEH_AIRCRAFT && v->current_order.IsType(OT_GOTO_DEPOT) && !hangar ? OT_GOTO_STATION : v->current_order.GetType()) == type &&
(!hangar || v->type == VEH_AIRCRAFT) && v->current_order.GetDestination() == destination) {
v->current_order.MakeDummy();
SetWindowDirty(WC_VEHICLE_VIEW, v->index);
}
/* Clear the order from the order-list */ /* Clear the order from the order-list */
int id = -1; int id = -1;
for (Order *order : v->Orders()) { for (Order *order : v->Orders()) {
@ -1806,8 +1806,7 @@ restart:
OrderType ot = order->GetType(); OrderType ot = order->GetType();
if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue; if (ot == OT_GOTO_DEPOT && (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) != 0) continue;
if (ot == OT_GOTO_DEPOT && hangar && v->type != VEH_AIRCRAFT) continue; // Not an aircraft? Can't have a hangar order. if (ot == OT_IMPLICIT) ot = OT_GOTO_STATION;
if (ot == OT_IMPLICIT || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
if (ot == type && order->GetDestination() == destination) { if (ot == type && order->GetDestination() == destination) {
/* We want to clear implicit orders, but we don't want to make them /* We want to clear implicit orders, but we don't want to make them
* dummy orders. They should just vanish. Also check the actual order * dummy orders. They should just vanish. Also check the actual order
@ -1841,7 +1840,7 @@ restart:
} }
} }
OrderBackup::RemoveOrder(type, destination, hangar); OrderBackup::RemoveOrder(type, destination);
} }
/** /**
@ -2054,7 +2053,8 @@ bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth, bool
v->SetDestTile(Depot::Get(order->GetDestination())->xy); v->SetDestTile(Depot::Get(order->GetDestination())->xy);
} else { } else {
Aircraft *a = Aircraft::From(v); Aircraft *a = Aircraft::From(v);
DestinationID destination = a->current_order.GetDestination(); DestinationID destination_depot = a->current_order.GetDestination();
StationID destination = GetStationIndex(Depot::Get(destination_depot)->xy);
if (a->targetairport != destination) { if (a->targetairport != destination) {
/* The aircraft is now heading for a different hangar than the next in the orders */ /* The aircraft is now heading for a different hangar than the next in the orders */
a->SetDestTile(a->GetOrderStationLocation(destination)); a->SetDestTile(a->GetOrderStationLocation(destination));

View File

@ -15,7 +15,7 @@
#include "company_type.h" #include "company_type.h"
/* Functions */ /* Functions */
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar = false); void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination);
void InvalidateVehicleOrder(const Vehicle *v, int data); void InvalidateVehicleOrder(const Vehicle *v, int data);
void CheckOrders(const Vehicle*); void CheckOrders(const Vehicle*);
void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false, bool reset_order_indices = true); void DeleteVehicleOrders(Vehicle *v, bool keep_orderlist = false, bool reset_order_indices = true);
@ -23,6 +23,7 @@ bool ProcessOrders(Vehicle *v);
bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth = 0, bool pbs_look_ahead = false); bool UpdateOrderDest(Vehicle *v, const Order *order, int conditional_depth = 0, bool pbs_look_ahead = false);
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v); VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v);
uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0); uint GetOrderDistance(const Order *prev, const Order *cur, const Vehicle *v, int conditional_depth = 0);
DestinationID GetTargetDestination(const Order &o, bool is_aircraft);
void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int y, bool selected, bool timetable, int left, int middle, int right); void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int y, bool selected, bool timetable, int left, int middle, int right);

View File

@ -34,6 +34,7 @@
#include "error.h" #include "error.h"
#include "order_cmd.h" #include "order_cmd.h"
#include "company_cmd.h" #include "company_cmd.h"
#include "depot_base.h"
#include "widgets/order_widget.h" #include "widgets/order_widget.h"
@ -309,7 +310,7 @@ void DrawOrderString(const Vehicle *v, const Order *order, int order_index, int
/* Going to a specific depot. */ /* Going to a specific depot. */
SetDParam(0, STR_ORDER_GO_TO_DEPOT_FORMAT); SetDParam(0, STR_ORDER_GO_TO_DEPOT_FORMAT);
SetDParam(2, v->type); SetDParam(2, v->type);
SetDParam(3, order->GetDestination()); SetDParam(3, GetTargetDestination(*order, v->type == VEH_AIRCRAFT));
} }
if (order->GetDepotOrderType() & ODTFB_SERVICE) { if (order->GetDepotOrderType() & ODTFB_SERVICE) {
@ -384,8 +385,7 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
/* check depot first */ /* check depot first */
if (IsDepotTypeTile(tile, (TransportType)(uint)v->type) && IsTileOwner(tile, _local_company)) { if (IsDepotTypeTile(tile, (TransportType)(uint)v->type) && IsTileOwner(tile, _local_company)) {
order.MakeGoToDepot(v->type == VEH_AIRCRAFT ? GetStationIndex(tile) : GetDepotIndex(tile), order.MakeGoToDepot(GetDepotIndex(tile), ODTFB_PART_OF_ORDERS,
ODTFB_PART_OF_ORDERS,
(_settings_client.gui.new_nonstop && v->IsGroundVehicle()) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE); (_settings_client.gui.new_nonstop && v->IsGroundVehicle()) ? ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS : ONSF_STOP_EVERYWHERE);
if (_ctrl_pressed) { if (_ctrl_pressed) {

View File

@ -2425,28 +2425,6 @@ bool AfterLoadGame()
for (Depot *d : Depot::Iterate()) d->build_date = TimerGameCalendar::date; for (Depot *d : Depot::Iterate()) d->build_date = TimerGameCalendar::date;
} }
/* In old versions it was possible to remove an airport while a plane was
* taking off or landing. This gives all kind of problems when building
* another airport in the same station so we don't allow that anymore.
* For old savegames with such aircraft we just throw them in the air and
* treat the aircraft like they were flying already. */
if (IsSavegameVersionBefore(SLV_146)) {
for (Aircraft *v : Aircraft::Iterate()) {
if (!v->IsNormalAircraft()) continue;
Station *st = GetTargetAirportIfValid(v);
if (st == nullptr && v->state != FLYING) {
v->state = FLYING;
UpdateAircraftCache(v);
AircraftNextAirportPos_and_Order(v);
/* get aircraft back on running altitude */
if ((v->vehstatus & VS_CRASHED) == 0) {
GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr);
SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v));
}
}
}
}
/* Move the animation frame to the same location (m7) for all objects. */ /* Move the animation frame to the same location (m7) for all objects. */
if (IsSavegameVersionBefore(SLV_147)) { if (IsSavegameVersionBefore(SLV_147)) {
for (auto t : Map::Iterate()) { for (auto t : Map::Iterate()) {
@ -2792,6 +2770,72 @@ bool AfterLoadGame()
} }
} }
if (IsSavegameVersionBefore(SLV_ADD_DEPOTS_TO_HANGARS)) {
for (Station *st : Station::Iterate()) {
if ((st->facilities & FACIL_AIRPORT) && st->airport.HasHangar()) {
/* Add a built-in hangar for some airport types. */
assert(Depot::CanAllocateItem());
st->airport.AddHangar();
} else {
/* If airport has no hangar, remove old go to hangar orders
* that could remain from removing an airport with a hangar
* and rebuilding it with an airport with no hangar. */
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index);
}
}
}
if (IsSavegameVersionBefore(SLV_DEPOTID_IN_HANGAR_ORDERS)) {
/* Update go to hangar orders so they store the DepotID instead of StationID. */
for (Aircraft *a : Aircraft::Iterate()) {
if (!a->IsNormalAircraft()) continue;
/* Update current order. */
if (a->current_order.IsType(OT_GOTO_DEPOT)) {
Depot *dep = Station::Get(a->current_order.GetDestination())->airport.hangar;
if (dep == nullptr) {
/* Aircraft heading to a removed hangar. */
a->current_order.MakeDummy();
} else {
a->current_order.SetDestination(dep->index);
}
}
/* Update each aircraft order list once. */
if (a->orders == nullptr) continue;
if (a->orders->GetFirstSharedVehicle() != a) continue;
for (Order *order : a->Orders()) {
if (!order->IsType(OT_GOTO_DEPOT)) continue;
StationID station_id = order->GetDestination();
Station *st = Station::Get(station_id);
order->SetDestination(st->airport.hangar->index);
}
}
}
/* In old versions it was possible to remove an airport while a plane was
* taking off or landing. This gives all kind of problems when building
* another airport in the same station so we don't allow that anymore.
* For old savegames with such aircraft we just throw them in the air and
* treat the aircraft like they were flying already. */
if (IsSavegameVersionBefore(SLV_146)) {
for (Aircraft *v : Aircraft::Iterate()) {
if (!v->IsNormalAircraft()) continue;
Station *st = GetTargetAirportIfValid(v);
if (st == nullptr && v->state != FLYING) {
v->state = FLYING;
UpdateAircraftCache(v);
AircraftNextAirportPos_and_Order(v);
/* get aircraft back on running altitude */
if ((v->vehstatus & VS_CRASHED) == 0) {
GetAircraftFlightLevelBounds(v, &v->z_pos, nullptr);
SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v));
}
}
}
}
/* This triggers only when old snow_lines were copied into the snow_line_height. */ /* This triggers only when old snow_lines were copied into the snow_line_height. */
if (IsSavegameVersionBefore(SLV_164) && _settings_game.game_creation.snow_line_height >= MIN_SNOWLINE_HEIGHT * TILE_HEIGHT) { if (IsSavegameVersionBefore(SLV_164) && _settings_game.game_creation.snow_line_height >= MIN_SNOWLINE_HEIGHT * TILE_HEIGHT) {
_settings_game.game_creation.snow_line_height /= TILE_HEIGHT; _settings_game.game_creation.snow_line_height /= TILE_HEIGHT;

View File

@ -108,6 +108,7 @@ const SaveLoadCompat _station_normal_sl_compat[] = {
SLC_VAR("airport.layout"), SLC_VAR("airport.layout"),
SLC_VAR("airport.flags"), SLC_VAR("airport.flags"),
SLC_VAR("airport.rotation"), SLC_VAR("airport.rotation"),
SLC_VAR("airport.hangar"),
SLC_VAR("storage"), SLC_VAR("storage"),
SLC_VAR("airport.psa"), SLC_VAR("airport.psa"),
SLC_VAR("indtype"), SLC_VAR("indtype"),

View File

@ -23,6 +23,7 @@
#include "../stdafx.h" #include "../stdafx.h"
#include "../debug.h" #include "../debug.h"
#include "../station_base.h" #include "../station_base.h"
#include "../depot_base.h"
#include "../thread.h" #include "../thread.h"
#include "../town.h" #include "../town.h"
#include "../network/network.h" #include "../network/network.h"
@ -1121,6 +1122,7 @@ static size_t ReferenceToInt(const void *obj, SLRefType rt)
case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1; case REF_STORAGE: return ((const PersistentStorage*)obj)->index + 1;
case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1; case REF_LINK_GRAPH: return ((const LinkGraph*)obj)->index + 1;
case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1; case REF_LINK_GRAPH_JOB: return ((const LinkGraphJob*)obj)->index + 1;
case REF_DEPOT: return ((const Depot*)obj)->index + 1;
default: NOT_REACHED(); default: NOT_REACHED();
} }
} }
@ -1202,6 +1204,10 @@ static void *IntToReference(size_t index, SLRefType rt)
if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index); if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
SlErrorCorrupt("Referencing invalid LinkGraphJob"); SlErrorCorrupt("Referencing invalid LinkGraphJob");
case REF_DEPOT:
if (Depot::IsValidID(index)) return Depot::Get(index);
SlErrorCorrupt("Referencing invalid Depot");
default: NOT_REACHED(); default: NOT_REACHED();
} }
} }

View File

@ -383,6 +383,9 @@ enum SaveLoadVersion : uint16_t {
SLV_GROUP_NUMBERS, ///< 336 PR#12297 Add per-company group numbers. SLV_GROUP_NUMBERS, ///< 336 PR#12297 Add per-company group numbers.
SLV_INCREASE_STATION_TYPE_FIELD_SIZE, ///< 337 PR#12572 Increase size of StationType field in map array SLV_INCREASE_STATION_TYPE_FIELD_SIZE, ///< 337 PR#12572 Increase size of StationType field in map array
SLV_ROAD_WAYPOINTS, ///< 338 PR#12572 Road waypoints SLV_ROAD_WAYPOINTS, ///< 338 PR#12572 Road waypoints
SLV_ADD_DEPOTS_TO_HANGARS, ///< 339 PR#10691 Add depots to airports that have a hangar.
SLV_DEPOTID_IN_HANGAR_ORDERS, ///< 340 PR#10691 Go to hangar orders store the DepotID instead of StationID.
SL_MAX_VERSION, ///< Highest possible saveload version SL_MAX_VERSION, ///< Highest possible saveload version
}; };
@ -598,6 +601,7 @@ enum SLRefType {
REF_STORAGE = 9, ///< Load/save a reference to a persistent storage. REF_STORAGE = 9, ///< Load/save a reference to a persistent storage.
REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph. REF_LINK_GRAPH = 10, ///< Load/save a reference to a link graph.
REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job. REF_LINK_GRAPH_JOB = 11, ///< Load/save a reference to a link graph job.
REF_DEPOT = 12, ///< Load/save a reference to a depot.
}; };
/** /**

View File

@ -610,6 +610,7 @@ public:
SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.layout, SLE_UINT8, SLV_145, SL_MAX_VERSION),
SLE_VAR(Station, airport.flags, SLE_UINT64), SLE_VAR(Station, airport.flags, SLE_UINT64),
SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION), SLE_CONDVAR(Station, airport.rotation, SLE_UINT8, SLV_145, SL_MAX_VERSION),
SLE_CONDREF(Station, airport.hangar, REF_DEPOT, SLV_ADD_DEPOTS_TO_HANGARS, SL_MAX_VERSION),
SLEG_CONDARR("storage", _old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161), SLEG_CONDARR("storage", _old_st_persistent_storage.storage, SLE_UINT32, 16, SLV_145, SLV_161),
SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION), SLE_CONDREF(Station, airport.psa, REF_STORAGE, SLV_161, SL_MAX_VERSION),

View File

@ -245,18 +245,13 @@ static int ScriptOrderPositionToRealOrderPosition(VehicleID vehicle_id, ScriptOr
const Order *order = ::ResolveOrder(vehicle_id, order_position); const Order *order = ::ResolveOrder(vehicle_id, order_position);
if (order == nullptr || order->GetType() == OT_CONDITIONAL) return INVALID_TILE; if (order == nullptr || order->GetType() == OT_CONDITIONAL) return INVALID_TILE;
const Vehicle *v = ::Vehicle::Get(vehicle_id);
switch (order->GetType()) { switch (order->GetType()) {
case OT_GOTO_DEPOT: { case OT_GOTO_DEPOT: {
/* We don't know where the nearest depot is... (yet) */ /* We don't know where the nearest depot is... (yet) */
if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) return INVALID_TILE; if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) return INVALID_TILE;
if (v->type != VEH_AIRCRAFT) return ::Depot::Get(order->GetDestination())->xy; return ::Depot::Get(order->GetDestination())->xy;
/* Aircraft's hangars are referenced by StationID, not DepotID */
const Station *st = ::Station::Get(order->GetDestination());
if (!st->airport.HasHangar()) return INVALID_TILE;
return st->airport.GetHangarTile(0);
} }
case OT_GOTO_STATION: { case OT_GOTO_STATION: {

View File

@ -26,6 +26,7 @@
#include "core/random_func.hpp" #include "core/random_func.hpp"
#include "linkgraph/linkgraph.h" #include "linkgraph/linkgraph.h"
#include "linkgraph/linkgraphschedule.h" #include "linkgraph/linkgraphschedule.h"
#include "depot_base.h"
#include "table/strings.h" #include "table/strings.h"
@ -727,6 +728,44 @@ Money AirportMaintenanceCost(Owner owner)
return total_cost >> 3; return total_cost >> 3;
} }
/**
* Create a hangar on the airport.
*/
void Airport::AddHangar()
{
assert(this->hangar == nullptr);
assert(Depot::CanAllocateItem());
assert(this->GetNumHangars() > 0);
Station *st = Station::GetByTile(this->GetHangarTile(0));
this->hangar = new Depot(this->GetHangarTile(0));
this->hangar->build_date = st->build_date;
this->hangar->town = st->town;
}
/**
* Delete the hangar on the airport.
*/
void Airport::RemoveHangar()
{
RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->hangar->index);
for (Aircraft *a : Aircraft::Iterate()) {
if (!a->IsNormalAircraft()) continue;
if (!a->current_order.IsType(OT_GOTO_DEPOT)) continue;
if (a->current_order.GetDestination() != this->hangar->index) continue;
a->current_order.MakeDummy();
}
delete this->hangar;
this->hangar = nullptr;
}
DepotID GetHangarIndex(TileIndex t) {
assert(IsAirportTile(t));
assert(Station::GetByTile(t)->airport.hangar != nullptr);
return Station::GetByTile(t)->airport.hangar->index;
}
bool StationCompare::operator() (const Station *lhs, const Station *rhs) const bool StationCompare::operator() (const Station *lhs, const Station *rhs) const
{ {
return lhs->index < rhs->index; return lhs->index < rhs->index;

View File

@ -18,6 +18,7 @@
#include "linkgraph/linkgraph_type.h" #include "linkgraph/linkgraph_type.h"
#include "newgrf_storage.h" #include "newgrf_storage.h"
#include "bitmap_type.h" #include "bitmap_type.h"
#include "depot_type.h"
static const uint8_t INITIAL_STATION_RATING = 175; static const uint8_t INITIAL_STATION_RATING = 175;
static const uint8_t MAX_STATION_RATING = 255; static const uint8_t MAX_STATION_RATING = 255;
@ -294,6 +295,7 @@ struct Airport : public TileArea {
uint8_t type; ///< Type of this airport, @see AirportTypes uint8_t type; ///< Type of this airport, @see AirportTypes
uint8_t layout; ///< Airport layout number. uint8_t layout; ///< Airport layout number.
Direction rotation; ///< How this airport is rotated. Direction rotation; ///< How this airport is rotated.
Depot *hangar; ///< The corresponding hangar of this airport, if any.
PersistentStorage *psa; ///< Persistent storage for NewGRF airports. PersistentStorage *psa; ///< Persistent storage for NewGRF airports.
@ -404,6 +406,9 @@ struct Airport : public TileArea {
return num; return num;
} }
void AddHangar();
void RemoveHangar();
private: private:
/** /**
* Retrieve hangar information of a hangar at a given tile. * Retrieve hangar information of a hangar at a given tile.

View File

@ -67,6 +67,7 @@
#include "timer/timer_game_tick.h" #include "timer/timer_game_tick.h"
#include "cheat_type.h" #include "cheat_type.h"
#include "road_func.h" #include "road_func.h"
#include "depot_base.h"
#include "widgets/station_widget.h" #include "widgets/station_widget.h"
@ -2547,6 +2548,8 @@ CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, uint8_t airport
/* Check if a valid, buildable airport was chosen for construction */ /* Check if a valid, buildable airport was chosen for construction */
const AirportSpec *as = AirportSpec::Get(airport_type); const AirportSpec *as = AirportSpec::Get(airport_type);
if (!as->depots.empty() && !Depot::CanAllocateItem()) return CMD_ERROR;
if (!as->IsAvailable() || layout >= as->layouts.size()) return CMD_ERROR; if (!as->IsAvailable() || layout >= as->layouts.size()) return CMD_ERROR;
if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR; if (!as->IsWithinMapBounds(layout, tile)) return CMD_ERROR;
@ -2640,6 +2643,8 @@ CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, uint8_t airport
AirportTileAnimationTrigger(st, iter, AAT_BUILT); AirportTileAnimationTrigger(st, iter, AAT_BUILT);
} }
if (!as->depots.empty()) st->airport.AddHangar();
UpdateAirplanesOnNewStation(st); UpdateAirplanesOnNewStation(st);
Company::Get(st->owner)->infrastructure.airport++; Company::Get(st->owner)->infrastructure.airport++;
@ -2687,6 +2692,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
OrderBackup::Reset(tile_cur, false); OrderBackup::Reset(tile_cur, false);
CloseWindowById(WC_VEHICLE_DEPOT, tile_cur); CloseWindowById(WC_VEHICLE_DEPOT, tile_cur);
} }
st->airport.RemoveHangar();
/* The noise level is the noise from the airport and reduce it to account for the distance to the town center. /* The noise level is the noise from the airport and reduce it to account for the distance to the town center.
* And as for construction, always remove it, even if the setting is not set, in order to avoid the * And as for construction, always remove it, even if the setting is not set, in order to avoid the

View File

@ -1619,7 +1619,7 @@ void VehicleEnterDepot(Vehicle *v)
* Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */ * Note: The target depot for nearest-/manual-depot-orders is only updated on junctions, but we want to accept every depot. */
if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) && real_order != nullptr && !(real_order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) &&
(v->type == VEH_AIRCRAFT ? v->current_order.GetDestination() != GetStationIndex(v->tile) : v->dest_tile != v->tile)) { v->current_order.GetDestination() != GetDepotIndex(v->tile)) {
/* We are heading for another depot, keep driving. */ /* We are heading for another depot, keep driving. */
return; return;
} }

View File

@ -45,6 +45,7 @@
#include "train_cmd.h" #include "train_cmd.h"
#include "hotkeys.h" #include "hotkeys.h"
#include "group_cmd.h" #include "group_cmd.h"
#include "depot_base.h"
#include "safeguards.h" #include "safeguards.h"
@ -3141,7 +3142,7 @@ public:
case OT_GOTO_DEPOT: { case OT_GOTO_DEPOT: {
SetDParam(0, v->type); SetDParam(0, v->type);
SetDParam(1, v->current_order.GetDestination()); SetDParam(1, GetTargetDestination(v->current_order, v->type == VEH_AIRCRAFT));
SetDParam(2, PackVelocity(v->GetDisplaySpeed(), v->type)); SetDParam(2, PackVelocity(v->GetDisplaySpeed(), v->type));
if (v->current_order.GetDestination() == INVALID_DEPOT) { if (v->current_order.GetDestination() == INVALID_DEPOT) {
/* This case *only* happens when multiple nearest depot orders /* This case *only* happens when multiple nearest depot orders