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 "aircraft_cmd.h"
#include "vehicle_cmd.h"
#include "depot_base.h"
#include "table/strings.h"
@ -136,7 +137,7 @@ static StationID FindNearestHangar(const Aircraft *v)
if (v->current_order.IsType(OT_GOTO_STATION) ||
(v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) {
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 {
last_dest = GetTargetAirportIfValid(v);
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
@ -407,9 +408,10 @@ ClosestDepot Aircraft::FindClosestDepot()
if (station == INVALID_STATION) return ClosestDepot();
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)
@ -424,13 +426,13 @@ static void CheckIfAircraftNeedsService(Aircraft *v)
* 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;
const Station *st = Station::Get(v->current_order.GetDestination());
const Station *st = Station::Get(GetTargetDestination(v->current_order, true));
assert(st != nullptr);
/* only goto depot if the target airport has a depot */
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);
} else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
v->current_order.MakeDummy();
@ -892,7 +894,7 @@ static bool AircraftController(Aircraft *v)
/* Jump into our "holding pattern" state machine if possible */
if (v->pos >= afc->nofelements) {
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 */
v->state = FLYING;
UpdateAircraftCache(v);
@ -1449,7 +1451,7 @@ static void AircraftLandAirplane(Aircraft *v)
void AircraftNextAirportPos_and_Order(Aircraft *v)
{
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);
@ -1539,7 +1541,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
return;
/* 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);
return;
}
@ -1548,7 +1550,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
/* 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:
* 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */
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
break;
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;
case OT_CONDITIONAL:
/* 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
* airport is only updated after take off and not on the ground. */
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) {
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;
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);
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);
}
extern DepotID GetHangarIndex(TileIndex t);
/**
* Get the index of which depot is attached to the tile.
* @param t the tile
* @pre IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t)
* @pre IsDepotTile(t)
* @return DepotID
*/
inline DepotID GetDepotIndex(Tile t)
{
/* Hangars don't have a Depot class, thus store no DepotID. */
assert(IsRailDepotTile(t) || IsRoadDepotTile(t) || IsShipDepotTile(t));
assert(IsDepotTile(t));
/* Hangars don't store depot id on m2. */
if (IsTileType(t, MP_STATION)) return GetHangarIndex(t);
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.
* @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
* @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 (Order *order = ob->orders; order != nullptr; order = order->next) {
OrderType ot = order->GetType();
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 || (IsHangarTile(ob->tile) && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
if (ot == OT_IMPLICIT) ot = OT_GOTO_STATION;
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. */
delete ob;

View File

@ -59,7 +59,7 @@ public:
static void ClearGroup(GroupID group);
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 */

View File

@ -650,7 +650,7 @@ TileIndex Order::GetLocation(const Vehicle *v, bool airport) const
case OT_GOTO_DEPOT:
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:
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);
}
/**
* 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.
* @param flags operation to perform
@ -763,18 +785,6 @@ CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID se
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;
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());
if (dp == nullptr) return CMD_ERROR;
@ -795,10 +805,13 @@ CommandCost CmdInsertOrder(DoCommandFlag flags, VehicleID veh, VehicleOrderID se
if (!IsShipDepotTile(dp->xy)) return CMD_ERROR;
break;
case VEH_AIRCRAFT:
if (!CanVehicleUseStation(v, Station::GetByTile(dp->xy)) || !IsHangarTile(dp->xy)) return CMD_ERROR;
break;
default: return CMD_ERROR;
}
}
}
if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
if (new_order.GetDepotOrderType() & ~(ODTFB_PART_OF_ORDERS | ((new_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) != 0 ? ODTFB_SERVICE : 0))) 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.
* @param type The type of the order (OT_GOTO_[STATION|DEPOT|WAYPOINT]).
* @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 */
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 */
int id = -1;
for (Order *order : v->Orders()) {
@ -1806,8 +1806,7 @@ restart:
OrderType ot = order->GetType();
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 || (v->type == VEH_AIRCRAFT && ot == OT_GOTO_DEPOT && !hangar)) ot = OT_GOTO_STATION;
if (ot == OT_IMPLICIT) ot = OT_GOTO_STATION;
if (ot == type && order->GetDestination() == destination) {
/* 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
@ -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);
} else {
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) {
/* The aircraft is now heading for a different hangar than the next in the orders */
a->SetDestTile(a->GetOrderStationLocation(destination));

View File

@ -15,7 +15,7 @@
#include "company_type.h"
/* Functions */
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar = false);
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination);
void InvalidateVehicleOrder(const Vehicle *v, int data);
void CheckOrders(const Vehicle*);
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);
VehicleOrderID ProcessConditionalOrder(const Order *order, const Vehicle *v);
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);

View File

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

View File

@ -2425,28 +2425,6 @@ bool AfterLoadGame()
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. */
if (IsSavegameVersionBefore(SLV_147)) {
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. */
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;

View File

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

View File

@ -23,6 +23,7 @@
#include "../stdafx.h"
#include "../debug.h"
#include "../station_base.h"
#include "../depot_base.h"
#include "../thread.h"
#include "../town.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_LINK_GRAPH: return ((const LinkGraph*)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();
}
}
@ -1202,6 +1204,10 @@ static void *IntToReference(size_t index, SLRefType rt)
if (LinkGraphJob::IsValidID(index)) return LinkGraphJob::Get(index);
SlErrorCorrupt("Referencing invalid LinkGraphJob");
case REF_DEPOT:
if (Depot::IsValidID(index)) return Depot::Get(index);
SlErrorCorrupt("Referencing invalid Depot");
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_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_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
};
@ -598,6 +601,7 @@ enum SLRefType {
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_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_VAR(Station, airport.flags, SLE_UINT64),
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),
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);
if (order == nullptr || order->GetType() == OT_CONDITIONAL) return INVALID_TILE;
const Vehicle *v = ::Vehicle::Get(vehicle_id);
switch (order->GetType()) {
case OT_GOTO_DEPOT: {
/* We don't know where the nearest depot is... (yet) */
if (order->GetDepotActionType() & ODATFB_NEAREST_DEPOT) return INVALID_TILE;
if (v->type != VEH_AIRCRAFT) 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);
return ::Depot::Get(order->GetDestination())->xy;
}
case OT_GOTO_STATION: {

View File

@ -26,6 +26,7 @@
#include "core/random_func.hpp"
#include "linkgraph/linkgraph.h"
#include "linkgraph/linkgraphschedule.h"
#include "depot_base.h"
#include "table/strings.h"
@ -727,6 +728,44 @@ Money AirportMaintenanceCost(Owner owner)
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
{
return lhs->index < rhs->index;

View File

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

View File

@ -67,6 +67,7 @@
#include "timer/timer_game_tick.h"
#include "cheat_type.h"
#include "road_func.h"
#include "depot_base.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 */
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->IsWithinMapBounds(layout, tile)) return CMD_ERROR;
@ -2640,6 +2643,8 @@ CommandCost CmdBuildAirport(DoCommandFlag flags, TileIndex tile, uint8_t airport
AirportTileAnimationTrigger(st, iter, AAT_BUILT);
}
if (!as->depots.empty()) st->airport.AddHangar();
UpdateAirplanesOnNewStation(st);
Company::Get(st->owner)->infrastructure.airport++;
@ -2687,6 +2692,7 @@ static CommandCost RemoveAirport(TileIndex tile, DoCommandFlag flags)
OrderBackup::Reset(tile_cur, false);
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.
* 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. */
if ((v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS) &&
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. */
return;
}

View File

@ -45,6 +45,7 @@
#include "train_cmd.h"
#include "hotkeys.h"
#include "group_cmd.h"
#include "depot_base.h"
#include "safeguards.h"
@ -3141,7 +3142,7 @@ public:
case OT_GOTO_DEPOT: {
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));
if (v->current_order.GetDestination() == INVALID_DEPOT) {
/* This case *only* happens when multiple nearest depot orders