Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-06-14 17:01:17 +05:00
1132 changed files with 59430 additions and 52889 deletions

View File

@@ -107,7 +107,7 @@ bool IsValidImageIndex<VEH_AIRCRAFT>(uint8_t image_index)
}
/** Helicopter rotor animation states */
enum HelicopterRotorStates {
enum HelicopterRotorStates : uint8_t {
HRS_ROTOR_STOPPED,
HRS_ROTOR_MOVING_1,
HRS_ROTOR_MOVING_2,
@@ -116,15 +116,15 @@ enum HelicopterRotorStates {
/**
* Find the nearest hangar to v
* INVALID_STATION is returned, if the company does not have any suitable
* StationID::Invalid() is returned, if the company does not have any suitable
* airports (like helipads only)
* @param v vehicle looking for a hangar
* @return the StationID if one is found, otherwise, INVALID_STATION
* @return the StationID if one is found, otherwise, StationID::Invalid()
*/
static StationID FindNearestHangar(const Aircraft *v)
{
uint best = 0;
StationID index = INVALID_STATION;
StationID index = StationID::Invalid();
TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos);
const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
uint max_range = v->acache.cached_max_range_sqr;
@@ -136,7 +136,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(v->current_order.GetDestination().ToStationID());
} else {
last_dest = GetTargetAirportIfValid(v);
next_dest = Station::GetIfValid(v->GetNextStoppingStation().value);
@@ -144,15 +144,15 @@ static StationID FindNearestHangar(const Aircraft *v)
}
for (const Station *st : Station::Iterate()) {
if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT) || !st->airport.HasHangar()) continue;
if (st->owner != v->owner || !st->facilities.Test(StationFacility::Airport) || !st->airport.HasHangar()) continue;
const AirportFTAClass *afc = st->airport.GetFTA();
/* don't crash the plane if we know it can't land at the airport */
if ((afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue;
if (afc->flags.Test(AirportFTAClass::Flag::ShortStrip) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue;
/* the plane won't land at any helicopter station */
if (!(afc->flags & AirportFTAClass::AIRPLANES) && (avi->subtype & AIR_CTOL)) continue;
if (!afc->flags.Test(AirportFTAClass::Flag::Airplanes) && (avi->subtype & AIR_CTOL)) continue;
/* Check if our last and next destinations can be reached from the depot airport. */
if (max_range != 0) {
@@ -163,7 +163,7 @@ static StationID FindNearestHangar(const Aircraft *v)
/* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */
uint distance = DistanceSquare(vtile, st->airport.tile);
if (distance < best || index == INVALID_STATION) {
if (distance < best || index == StationID::Invalid()) {
best = distance;
index = st->index;
}
@@ -268,7 +268,7 @@ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoff
* @param[out] ret the vehicle that has been built.
* @return the cost of this operation or an error.
*/
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
CommandCost CmdBuildAircraft(DoCommandFlags flags, TileIndex tile, const Engine *e, Vehicle **ret)
{
const AircraftVehicleInfo *avi = &e->u.air;
const Station *st = Station::GetByTile(tile);
@@ -279,7 +279,7 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
/* Make sure all aircraft end up in the first tile of the hangar. */
tile = st->airport.GetHangarTile(st->airport.GetHangarNum(tile));
if (flags & DC_EXEC) {
if (flags.Test(DoCommandFlag::Execute)) {
Aircraft *v = new Aircraft(); // aircraft
Aircraft *u = new Aircraft(); // shadow
*ret = v;
@@ -299,8 +299,8 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
u->z_pos = GetSlopePixelZ(x, y);
v->z_pos = u->z_pos + 1;
v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL;
u->vehstatus = VS_HIDDEN | VS_UNCLICKABLE | VS_SHADOW;
v->vehstatus = {VehState::Hidden, VehState::Stopped, VehState::DefaultPalette};
u->vehstatus = {VehState::Hidden, VehState::Unclickable, VehState::Shadow};
v->spritenum = avi->image_index;
@@ -309,17 +309,17 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
u->refit_cap = 0;
v->cargo_type = e->GetDefaultCargoType();
assert(IsValidCargoID(v->cargo_type));
assert(IsValidCargoType(v->cargo_type));
CargoID mail = GetCargoIDByLabel(CT_MAIL);
if (IsValidCargoID(mail)) {
CargoType mail = GetCargoTypeByLabel(CT_MAIL);
if (IsValidCargoType(mail)) {
u->cargo_type = mail;
u->cargo_cap = avi->mail_capacity;
}
v->name.clear();
v->last_station_visited = INVALID_STATION;
v->last_loading_station = INVALID_STATION;
v->last_station_visited = StationID::Invalid();
v->last_loading_station = StationID::Invalid();
v->acceleration = avi->acceleration;
v->engine_type = e->index;
@@ -354,8 +354,8 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
v->random_bits = Random();
u->random_bits = Random();
v->vehicle_flags = 0;
if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE);
v->vehicle_flags = {};
if (e->flags.Test(EngineFlag::ExclusivePreview)) v->vehicle_flags.Set(VehicleFlag::BuiltAsPrototype);
v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
v->InvalidateNewGRFCacheOfChain();
@@ -378,7 +378,7 @@ CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *
w->x_pos = v->x_pos;
w->y_pos = v->y_pos;
w->z_pos = v->z_pos + ROTOR_Z_OFFSET;
w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE;
w->vehstatus = {VehState::Hidden, VehState::Unclickable};
w->spritenum = 0xFF;
w->subtype = AIR_ROTOR;
w->sprite_cache.sprite_seq.Set(SPR_ROTOR_STOPPED);
@@ -404,7 +404,7 @@ ClosestDepot Aircraft::FindClosestDepot()
/* the aircraft has to search for a hangar on its own */
StationID station = FindNearestHangar(this);
if (station == INVALID_STATION) return ClosestDepot();
if (station == StationID::Invalid()) return ClosestDepot();
st = Station::Get(station);
}
@@ -424,7 +424,7 @@ 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(v->current_order.GetDestination().ToStationID());
assert(st != nullptr);
@@ -482,11 +482,11 @@ static void HelicopterTickHandler(Aircraft *v)
{
Aircraft *u = v->Next()->Next();
if (u->vehstatus & VS_HIDDEN) return;
if (u->vehstatus.Test(VehState::Hidden)) return;
/* if true, helicopter rotors do not rotate. This should only be the case if a helicopter is
* loading/unloading at a terminal or stopped */
if (v->current_order.IsType(OT_LOADING) || (v->vehstatus & VS_STOPPED)) {
if (v->current_order.IsType(OT_LOADING) || v->vehstatus.Test(VehState::Stopped)) {
if (u->cur_speed != 0) {
u->cur_speed++;
if (u->cur_speed >= 0x80 && u->state == HRS_ROTOR_MOVING_3) {
@@ -576,10 +576,10 @@ void HandleAircraftEnterHangar(Aircraft *v)
v->progress = 0;
Aircraft *u = v->Next();
u->vehstatus |= VS_HIDDEN;
u->vehstatus.Set(VehState::Hidden);
u = u->Next();
if (u != nullptr) {
u->vehstatus |= VS_HIDDEN;
u->vehstatus.Set(VehState::Hidden);
u->cur_speed = 0;
}
@@ -660,7 +660,7 @@ static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE,
speed_limit *= _settings_game.vehicle.plane_speed;
/* adjust speed for broken vehicles */
if (v->vehstatus & VS_AIRCRAFT_BROKEN) {
if (v->vehstatus.Test(VehState::AircraftBroken)) {
if (SPEED_LIMIT_BROKEN < speed_limit) hard_limit = false;
speed_limit = std::min<uint>(speed_limit, SPEED_LIMIT_BROKEN);
}
@@ -831,7 +831,7 @@ static uint8_t AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *a
/* In the case the station doesn't exit anymore, set target tile 0.
* It doesn't hurt much, aircraft will go to next order, nearest hangar
* or it will simply crash in next tick */
TileIndex tile = 0;
TileIndex tile{};
const Station *st = Station::GetIfValid(v->targetairport);
if (st != nullptr) {
@@ -908,7 +908,7 @@ static bool AircraftController(Aircraft *v)
int y = TileY(tile) * TILE_SIZE;
/* Helicopter raise */
if (amd.flag & AMED_HELI_RAISE) {
if (amd.flags.Test(AirportMovingDataFlag::HeliRaise)) {
Aircraft *u = v->Next()->Next();
/* Make sure the rotors don't rotate too fast */
@@ -927,7 +927,7 @@ static bool AircraftController(Aircraft *v)
u->cur_speed = 32;
int count = UpdateAircraftSpeed(v);
if (count > 0) {
v->tile = 0;
v->tile = TileIndex{};
int z_dest;
GetAircraftFlightLevelBounds(v, &z_dest, nullptr);
@@ -944,13 +944,10 @@ static bool AircraftController(Aircraft *v)
}
/* Helicopter landing. */
if (amd.flag & AMED_HELI_LOWER) {
if (amd.flags.Test(AirportMovingDataFlag::HeliLower)) {
SetBit(v->flags, VAF_HELI_DIRECT_DESCENT);
if (st == nullptr) {
/* FIXME - AircraftController -> if station no longer exists, do not land
* helicopter will circle until sign disappears, then go to next order
* what to do when it is the only order left, right now it just stays in 1 place */
v->state = FLYING;
UpdateAircraftCache(v);
AircraftNextAirportPos_and_Order(v);
@@ -996,7 +993,7 @@ static bool AircraftController(Aircraft *v)
uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos);
/* Need exact position? */
if (!(amd.flag & AMED_EXACTPOS) && dist <= (amd.flag & AMED_SLOWTURN ? 8U : 4U)) return true;
if (!amd.flags.Test(AirportMovingDataFlag::ExactPosition) && dist <= (amd.flags.Test(AirportMovingDataFlag::SlowTurn) ? 8U : 4U)) return true;
/* At final pos? */
if (dist == 0) {
@@ -1018,18 +1015,18 @@ static bool AircraftController(Aircraft *v)
return false;
}
if (amd.flag & AMED_BRAKE && v->cur_speed > SPEED_LIMIT_TAXI * _settings_game.vehicle.plane_speed) {
if (amd.flags.Test(AirportMovingDataFlag::Brake) && v->cur_speed > SPEED_LIMIT_TAXI * _settings_game.vehicle.plane_speed) {
MaybeCrashAirplane(v);
if ((v->vehstatus & VS_CRASHED) != 0) return false;
if (v->vehstatus.Test(VehState::Crashed)) return false;
}
uint speed_limit = SPEED_LIMIT_TAXI;
bool hard_limit = true;
if (amd.flag & AMED_NOSPDCLAMP) speed_limit = SPEED_LIMIT_NONE;
if (amd.flag & AMED_HOLD) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; }
if (amd.flag & AMED_LAND) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; }
if (amd.flag & AMED_BRAKE) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::NoSpeedClamp)) speed_limit = SPEED_LIMIT_NONE;
if (amd.flags.Test(AirportMovingDataFlag::Hold)) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::Land)) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; }
if (amd.flags.Test(AirportMovingDataFlag::Brake)) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; }
int count = UpdateAircraftSpeed(v, speed_limit, hard_limit);
if (count == 0) return false;
@@ -1047,7 +1044,7 @@ static bool AircraftController(Aircraft *v)
GetNewVehiclePosResult gp;
if (nudge_towards_target || (amd.flag & AMED_LAND)) {
if (nudge_towards_target || amd.flags.Test(AirportMovingDataFlag::Land)) {
/* move vehicle one pixel towards target */
gp.x = (v->x_pos != (x + amd.x)) ?
v->x_pos + ((x + amd.x > v->x_pos) ? 1 : -1) :
@@ -1064,7 +1061,7 @@ static bool AircraftController(Aircraft *v)
/* Turn. Do it slowly if in the air. */
Direction newdir = GetDirectionTowards(v, x + amd.x, y + amd.y);
if (newdir != v->direction) {
if (amd.flag & AMED_SLOWTURN && v->number_consecutive_turns < 8 && v->subtype == AIR_AIRCRAFT) {
if (amd.flags.Test(AirportMovingDataFlag::SlowTurn) && v->number_consecutive_turns < 8 && v->subtype == AIR_AIRCRAFT) {
if (v->turn_counter == 0 || newdir == v->last_direction) {
if (newdir == v->last_direction) {
v->number_consecutive_turns = 0;
@@ -1100,17 +1097,17 @@ static bool AircraftController(Aircraft *v)
v->tile = gp.new_tile;
/* If vehicle is in the air, use tile coordinate 0. */
if (amd.flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0;
if (amd.flags.Any({AirportMovingDataFlag::Takeoff, AirportMovingDataFlag::SlowTurn, AirportMovingDataFlag::Land})) v->tile = TileIndex{};
/* Adjust Z for land or takeoff? */
int z = v->z_pos;
if (amd.flag & AMED_TAKEOFF) {
if (amd.flags.Test(AirportMovingDataFlag::Takeoff)) {
z = GetAircraftFlightLevel(v, true);
} else if (amd.flag & AMED_HOLD) {
} else if (amd.flags.Test(AirportMovingDataFlag::Hold)) {
/* Let the plane drop from normal flight altitude to holding pattern altitude */
if (z > GetAircraftHoldMaxAltitude(v)) z--;
} else if ((amd.flag & AMED_SLOWTURN) && (amd.flag & AMED_NOSPDCLAMP)) {
} else if (amd.flags.All({AirportMovingDataFlag::SlowTurn, AirportMovingDataFlag::NoSpeedClamp})) {
z = GetAircraftFlightLevel(v);
}
@@ -1121,13 +1118,13 @@ static bool AircraftController(Aircraft *v)
* We also know that the airport itself has to be completely flat (otherwise it is not a valid airport).
* Therefore, use the height of this hangar to calculate our z-value. */
int airport_z = v->z_pos;
if ((amd.flag & (AMED_LAND | AMED_BRAKE)) && st != nullptr) {
if (amd.flags.Any({AirportMovingDataFlag::Land, AirportMovingDataFlag::Brake}) && st != nullptr) {
assert(st->airport.HasHangar());
TileIndex hangar_tile = st->airport.GetHangarTile(0);
airport_z = GetTileMaxPixelZ(hangar_tile) + 1; // To avoid clashing with the shadow
}
if (amd.flag & AMED_LAND) {
if (amd.flags.Test(AirportMovingDataFlag::Land)) {
if (st->airport.tile == INVALID_TILE) {
/* Airport has been removed, abort the landing procedure */
v->state = FLYING;
@@ -1151,7 +1148,7 @@ static bool AircraftController(Aircraft *v)
}
/* We've landed. Decrease speed when we're reaching end of runway. */
if (amd.flag & AMED_BRAKE) {
if (amd.flags.Test(AirportMovingDataFlag::Brake)) {
if (z > airport_z) {
z--;
@@ -1209,12 +1206,12 @@ static bool HandleCrashedAircraft(Aircraft *v)
/* remove rubble of crashed airplane */
/* clear runway-in on all airports, set by crashing plane
* small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc.
* small airports use AIRPORT_BUSY, city airports use AirportBlock::RunwayInOut, etc.
* but they all share the same number */
if (st != nullptr) {
CLRBITS(st->airport.flags, RUNWAY_IN_block);
CLRBITS(st->airport.flags, RUNWAY_IN_OUT_block); // commuter airport
CLRBITS(st->airport.flags, RUNWAY_IN2_block); // intercontinental
st->airport.blocks.Reset(AirportBlock::RunwayIn);
st->airport.blocks.Reset(AirportBlock::RunwayInOut); // commuter airport
st->airport.blocks.Reset(AirportBlock::RunwayIn2); // intercontinental
}
delete v;
@@ -1247,11 +1244,11 @@ static void HandleAircraftSmoke(Aircraft *v, bool mode)
{ 0, 6 }
};
if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return;
if (!v->vehstatus.Test(VehState::AircraftBroken)) return;
/* Stop smoking when landed */
if (v->cur_speed < 10) {
v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
v->vehstatus.Reset(VehState::AircraftBroken);
v->breakdown_ctr = 0;
return;
}
@@ -1287,7 +1284,7 @@ void HandleMissingAircraftOrders(Aircraft *v)
const Station *st = GetTargetAirportIfValid(v);
if (st == nullptr) {
Backup<CompanyID> cur_company(_current_company, v->owner);
CommandCost ret = Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DC_EXEC, v->index, DepotCommand::None, {});
CommandCost ret = Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag{}, {});
cur_company.Restore();
if (ret.Failed()) CrashAirplane(v);
@@ -1305,7 +1302,7 @@ TileIndex Aircraft::GetOrderStationLocation(StationID)
}
/* Aircraft do not use dest-tile */
return 0;
return TileIndex{};
}
void Aircraft::MarkDirty()
@@ -1335,29 +1332,28 @@ static void CrashAirplane(Aircraft *v)
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
uint victims = v->Crash();
SetDParam(0, victims);
v->cargo.Truncate();
v->Next()->cargo.Truncate();
const Station *st = GetTargetAirportIfValid(v);
StringID newsitem;
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
EncodedString headline;
if (st == nullptr) {
newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL;
headline = GetEncodedString(STR_NEWS_PLANE_CRASH_OUT_OF_FUEL, victims);
} else {
SetDParam(1, st->index);
newsitem = STR_NEWS_AIRCRAFT_CRASH;
headline = GetEncodedString(STR_NEWS_AIRCRAFT_CRASH, victims, st->index);
}
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims));
Game::NewEvent(new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims));
AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims, v->owner));
Game::NewEvent(new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims, v->owner));
NewsType newstype = NT_ACCIDENT;
NewsType newstype = NewsType::Accident;
if (v->owner != _local_company) {
newstype = NT_ACCIDENT_OTHER;
newstype = NewsType::AccidentOther;
}
AddTileNewsItem(newsitem, newstype, vt, nullptr, st != nullptr ? st->index : INVALID_STATION);
AddTileNewsItem(std::move(headline), newstype, vt, st != nullptr ? st->index : StationID::Invalid());
ModifyStationRatingAround(vt, v->owner, -160, 30);
if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
@@ -1373,7 +1369,7 @@ static void MaybeCrashAirplane(Aircraft *v)
Station *st = Station::Get(v->targetairport);
uint32_t prob;
if ((st->airport.GetFTA()->flags & AirportFTAClass::SHORT_STRIP) &&
if (st->airport.GetFTA()->flags.Test(AirportFTAClass::Flag::ShortStrip) &&
(AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
!_cheats.no_jetcrash.value) {
prob = 3276;
@@ -1387,7 +1383,7 @@ static void MaybeCrashAirplane(Aircraft *v)
/* Crash the airplane. Remove all goods stored at the station. */
for (GoodsEntry &ge : st->goods) {
ge.rating = 1;
ge.cargo.Truncate();
if (ge.HasData()) ge.GetData().cargo.Truncate();
}
CrashAirplane(v);
@@ -1408,11 +1404,10 @@ static void AircraftEntersTerminal(Aircraft *v)
/* Check if station was ever visited before */
if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
st->had_vehicle_of_type |= HVOT_AIRCRAFT;
SetDParam(0, st->index);
/* show newsitem of celebrating citizens */
AddVehicleNewsItem(
STR_NEWS_FIRST_AIRCRAFT_ARRIVAL,
(v->owner == _local_company) ? NT_ARRIVAL_COMPANY : NT_ARRIVAL_OTHER,
GetEncodedString(STR_NEWS_FIRST_AIRCRAFT_ARRIVAL, st->index),
(v->owner == _local_company) ? NewsType::ArrivalCompany : NewsType::ArrivalOther,
v->index,
st->index
);
@@ -1447,7 +1442,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 = v->current_order.GetDestination().ToStationID();
}
const Station *st = GetTargetAirportIfValid(v);
@@ -1470,15 +1465,15 @@ void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
v->subspeed = 0;
v->progress = 0;
v->direction = exit_dir;
v->vehstatus &= ~VS_HIDDEN;
v->vehstatus.Reset(VehState::Hidden);
{
Vehicle *u = v->Next();
u->vehstatus &= ~VS_HIDDEN;
u->vehstatus.Reset(VehState::Hidden);
/* Rotor blades */
u = u->Next();
if (u != nullptr) {
u->vehstatus &= ~VS_HIDDEN;
u->vehstatus.Reset(VehState::Hidden);
u->cur_speed = 80;
}
}
@@ -1524,7 +1519,7 @@ static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *ap
}
/* if we were sent to the depot, stay there */
if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) {
if (v->current_order.IsType(OT_GOTO_DEPOT) && v->vehstatus.Test(VehState::Stopped)) {
v->current_order.Free();
return;
}
@@ -1653,7 +1648,7 @@ static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass
/* Send the helicopter to a hangar if needed for replacement */
if (v->NeedsAutomaticServicing()) {
Backup<CompanyID> cur_company(_current_company, v->owner);
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DC_EXEC, v->index, DepotCommand::Service | DepotCommand::LocateHangar, {});
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
cur_company.Restore();
}
}
@@ -1663,12 +1658,12 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
Station *st = Station::Get(v->targetairport);
/* Runway busy, not allowed to use this airstation or closed, circle. */
if (CanVehicleUseStation(v, st) && (st->owner == OWNER_NONE || st->owner == v->owner) && !(st->airport.flags & AIRPORT_CLOSED_block)) {
/* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
if (CanVehicleUseStation(v, st) && (st->owner == OWNER_NONE || st->owner == v->owner) && !st->airport.blocks.Test(AirportBlock::AirportClosed)) {
/* {32,FLYING,AirportBlock::Nothing,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
* if it is an airplane, look for LANDING, for helicopter HELILANDING
* it is possible to choose from multiple landing runways, so loop until a free one is found */
uint8_t landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING;
const AirportFTA *current = apc->layout[v->pos].next;
const AirportFTA *current = apc->layout[v->pos].next.get();
while (current != nullptr) {
if (current->heading == landingtype) {
/* save speed before, since if AirportHasBlock is false, it resets them to 0
@@ -1683,13 +1678,13 @@ static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
* if there are multiple runways, plane won't know which one it took (because
* they all have heading LANDING). And also occupy that block! */
v->pos = current->next_position;
SETBITS(st->airport.flags, apc->layout[v->pos].block);
st->airport.blocks.Set(apc->layout[v->pos].blocks);
return;
}
v->cur_speed = tcur_speed;
v->subspeed = tsubspeed;
}
current = current->next;
current = current->next.get();
}
}
v->state = FLYING;
@@ -1704,7 +1699,7 @@ static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *)
/* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
if (v->NeedsAutomaticServicing()) {
Backup<CompanyID> cur_company(_current_company, v->owner);
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DC_EXEC, v->index, DepotCommand::Service, {});
Command<CMD_SEND_VEHICLE_TO_DEPOT>::Do(DoCommandFlag::Execute, v->index, DepotCommandFlag::Service, {});
cur_company.Restore();
}
}
@@ -1784,10 +1779,10 @@ static AircraftStateHandler * const _aircraft_state_handlers[] = {
static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc)
{
/* we have left the previous block, and entered the new one. Free the previous block */
if (apc->layout[v->previous_pos].block != apc->layout[v->pos].block) {
if (apc->layout[v->previous_pos].blocks != apc->layout[v->pos].blocks) {
Station *st = Station::Get(v->targetairport);
CLRBITS(st->airport.flags, apc->layout[v->previous_pos].block);
st->airport.blocks.Reset(apc->layout[v->previous_pos].blocks);
}
}
@@ -1843,7 +1838,7 @@ static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
} // move to next position
return false;
}
current = current->next;
current = current->next.get();
} while (current != nullptr);
Debug(misc, 0, "[Ap] cannot move further on Airport! (pos {} state {}) for vehicle {}", v->pos, v->state, v->index);
@@ -1857,16 +1852,16 @@ static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const Ai
const AirportFTA *next = &apc->layout[current_pos->next_position];
/* same block, then of course we can move */
if (apc->layout[current_pos->position].block != next->block) {
if (apc->layout[current_pos->position].blocks != next->blocks) {
const Station *st = Station::Get(v->targetairport);
uint64_t airport_flags = next->block;
AirportBlocks blocks = next->blocks;
/* check additional possible extra blocks */
if (current_pos != reference && current_pos->block != NOTHING_block) {
airport_flags |= current_pos->block;
if (current_pos != reference && current_pos->blocks != AirportBlock::Nothing) {
blocks.Set(current_pos->blocks);
}
if (st->airport.flags & airport_flags) {
if (st->airport.blocks.Any(blocks)) {
v->cur_speed = 0;
v->subspeed = 0;
return true;
@@ -1888,33 +1883,33 @@ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const A
const AirportFTA *reference = &apc->layout[v->pos];
/* if the next position is in another block, check it and wait until it is free */
if ((apc->layout[current_pos->position].block & next->block) != next->block) {
uint64_t airport_flags = next->block;
if (!apc->layout[current_pos->position].blocks.All(next->blocks)) {
AirportBlocks blocks = next->blocks;
/* search for all all elements in the list with the same state, and blocks != N
* this means more blocks should be checked/set */
const AirportFTA *current = current_pos;
if (current == reference) current = current->next;
if (current == reference) current = current->next.get();
while (current != nullptr) {
if (current->heading == current_pos->heading && current->block != 0) {
airport_flags |= current->block;
if (current->heading == current_pos->heading && current->blocks.Any()) {
blocks.Set(current->blocks);
break;
}
current = current->next;
current = current->next.get();
}
/* if the block to be checked is in the next position, then exclude that from
* checking, because it has been set by the airplane before */
if (current_pos->block == next->block) airport_flags ^= next->block;
if (current_pos->blocks == next->blocks) blocks.Flip(next->blocks);
Station *st = Station::Get(v->targetairport);
if (st->airport.flags & airport_flags) {
if (st->airport.blocks.Any(blocks)) {
v->cur_speed = 0;
v->subspeed = 0;
return false;
}
if (next->block != NOTHING_block) {
SETBITS(st->airport.flags, airport_flags); // occupy next block
if (next->blocks != AirportBlock::Nothing) {
st->airport.blocks.Set(blocks); // occupy next block
}
}
return true;
@@ -1926,22 +1921,22 @@ static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const A
*/
struct MovementTerminalMapping {
AirportMovementStates state; ///< Aircraft movement state when going to this terminal.
uint64_t airport_flag; ///< Bitmask in the airport flags that need to be free for this terminal.
AirportBlock blocks; ///< Bitmask in the airport flags that need to be free for this terminal.
};
/** A list of all valid terminals and their associated blocks. */
static const MovementTerminalMapping _airport_terminal_mapping[] = {
{TERM1, TERM1_block},
{TERM2, TERM2_block},
{TERM3, TERM3_block},
{TERM4, TERM4_block},
{TERM5, TERM5_block},
{TERM6, TERM6_block},
{TERM7, TERM7_block},
{TERM8, TERM8_block},
{HELIPAD1, HELIPAD1_block},
{HELIPAD2, HELIPAD2_block},
{HELIPAD3, HELIPAD3_block},
{TERM1, AirportBlock::Term1},
{TERM2, AirportBlock::Term2},
{TERM3, AirportBlock::Term3},
{TERM4, AirportBlock::Term4},
{TERM5, AirportBlock::Term5},
{TERM6, AirportBlock::Term6},
{TERM7, AirportBlock::Term7},
{TERM8, AirportBlock::Term8},
{HELIPAD1, AirportBlock::Helipad1},
{HELIPAD2, AirportBlock::Helipad2},
{HELIPAD3, AirportBlock::Helipad3},
};
/**
@@ -1956,10 +1951,10 @@ static bool FreeTerminal(Aircraft *v, uint8_t i, uint8_t last_terminal)
assert(last_terminal <= lengthof(_airport_terminal_mapping));
Station *st = Station::Get(v->targetairport);
for (; i < last_terminal; i++) {
if ((st->airport.flags & _airport_terminal_mapping[i].airport_flag) == 0) {
if (!st->airport.blocks.Any(_airport_terminal_mapping[i].blocks)) {
/* TERMINAL# HELIPAD# */
v->state = _airport_terminal_mapping[i].state; // start moving to that terminal/helipad
SETBITS(st->airport.flags, _airport_terminal_mapping[i].airport_flag); // occupy terminal/helipad
st->airport.blocks.Set(_airport_terminal_mapping[i].blocks); // occupy terminal/helipad
return true;
}
}
@@ -1989,22 +1984,22 @@ static uint GetNumTerminals(const AirportFTAClass *apc)
static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc)
{
/* example of more terminalgroups
* {0,HANGAR,NOTHING_block,1}, {0,TERMGROUP,TERM_GROUP1_block,0}, {0,TERMGROUP,TERM_GROUP2_ENTER_block,1}, {0,0,N,1},
* {0,HANGAR,AirportBlock::Nothing,1}, {0,TERMGROUP,AirportBlock::TermGroup1,0}, {0,TERMGROUP,TERM_GROUP2_ENTER_block,1}, {0,0,N,1},
* Heading TERMGROUP denotes a group. We see 2 groups here:
* 1. group 0 -- TERM_GROUP1_block (check block)
* 1. group 0 -- AirportBlock::TermGroup1 (check block)
* 2. group 1 -- TERM_GROUP2_ENTER_block (check block)
* First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it
* First in line is checked first, group 0. If the block (AirportBlock::TermGroup1) is free, it
* looks at the corresponding terminals of that group. If no free ones are found, other
* possible groups are checked (in this case group 1, since that is after group 0). If that
* fails, then attempt fails and plane waits
*/
if (apc->terminals[0] > 1) {
const Station *st = Station::Get(v->targetairport);
const AirportFTA *temp = apc->layout[v->pos].next;
const AirportFTA *temp = apc->layout[v->pos].next.get();
while (temp != nullptr) {
if (temp->heading == TERMGROUP) {
if (!(st->airport.flags & temp->block)) {
if (!st->airport.blocks.Any(temp->blocks)) {
/* read which group do we want to go to?
* (the first free group) */
uint target_group = temp->next_position + 1;
@@ -2025,7 +2020,7 @@ static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc)
* So we cannot move */
return false;
}
temp = temp->next;
temp = temp->next.get();
}
}
@@ -2063,8 +2058,7 @@ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index));
if (v->owner == _local_company) {
/* Post a news message. */
SetDParam(0, v->index);
AddVehicleAdviceNewsItem(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index);
AddVehicleAdviceNewsItem(AdviceType::AircraftDestinationTooFar, GetEncodedString(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index), v->index);
}
}
return;
@@ -2074,17 +2068,17 @@ static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
/* Not too far anymore, clear flag and message. */
ClrBit(v->flags, VAF_DEST_TOO_FAR);
SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, WID_VV_START_STOP);
DeleteVehicleNews(v->index, STR_NEWS_AIRCRAFT_DEST_TOO_FAR);
DeleteVehicleNews(v->index, AdviceType::AircraftDestinationTooFar);
}
}
static bool AircraftEventHandler(Aircraft *v, int loop)
{
if (v->vehstatus & VS_CRASHED) {
if (v->vehstatus.Test(VehState::Crashed)) {
return HandleCrashedAircraft(v);
}
if (v->vehstatus & VS_STOPPED) return true;
if (v->vehstatus.Test(VehState::Stopped)) return true;
v->HandleBreakdown();
@@ -2101,7 +2095,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 = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination().ToStationID()) : nullptr;
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);
@@ -2122,7 +2116,7 @@ bool Aircraft::Tick()
this->tick_counter++;
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
if (!this->vehstatus.Test(VehState::Stopped)) this->running_ticks++;
if (this->subtype == AIR_HELICOPTER) HelicopterTickHandler(this);