OpenTTD Source 20241222-master-gc72542431a
aircraft_cmd.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
13#include "stdafx.h"
14#include "aircraft.h"
15#include "landscape.h"
16#include "news_func.h"
17#include "newgrf_engine.h"
18#include "newgrf_sound.h"
19#include "spritecache.h"
20#include "error_func.h"
21#include "strings_func.h"
22#include "command_func.h"
23#include "window_func.h"
26#include "vehicle_func.h"
27#include "sound_func.h"
28#include "cheat_type.h"
29#include "company_base.h"
30#include "ai/ai.hpp"
31#include "game/game.hpp"
32#include "company_func.h"
33#include "effectvehicle_func.h"
34#include "station_base.h"
35#include "engine_base.h"
36#include "core/random_func.hpp"
37#include "core/backup_type.hpp"
38#include "zoom_func.h"
39#include "disaster_vehicle.h"
40#include "newgrf_airporttiles.h"
41#include "framerate_type.h"
42#include "aircraft_cmd.h"
43#include "vehicle_cmd.h"
44
45#include "table/strings.h"
46
47#include "safeguards.h"
48
50{
51 this->x_offs = -1;
52 this->y_offs = -1;
53 this->x_extent = 2;
54 this->y_extent = 2;
55
56 switch (this->subtype) {
57 default: NOT_REACHED();
58
59 case AIR_AIRCRAFT:
60 case AIR_HELICOPTER:
61 switch (this->state) {
62 default: break;
63 case ENDTAKEOFF:
64 case LANDING:
65 case HELILANDING:
66 case FLYING:
67 this->x_extent = 24;
68 this->y_extent = 24;
69 break;
70 }
71 this->z_extent = 5;
72 break;
73
74 case AIR_SHADOW:
75 this->z_extent = 1;
76 this->x_offs = 0;
77 this->y_offs = 0;
78 break;
79
80 case AIR_ROTOR:
81 this->z_extent = 1;
82 break;
83 }
84}
85
86static bool AirportMove(Aircraft *v, const AirportFTAClass *apc);
87static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc);
88static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc);
89static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc);
90static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc);
91static void CrashAirplane(Aircraft *v);
92
93static const SpriteID _aircraft_sprite[] = {
94 0x0EB5, 0x0EBD, 0x0EC5, 0x0ECD,
95 0x0ED5, 0x0EDD, 0x0E9D, 0x0EA5,
96 0x0EAD, 0x0EE5, 0x0F05, 0x0F0D,
97 0x0F15, 0x0F1D, 0x0F25, 0x0F2D,
98 0x0EED, 0x0EF5, 0x0EFD, 0x0F35,
99 0x0E9D, 0x0EA5, 0x0EAD, 0x0EB5,
100 0x0EBD, 0x0EC5
101};
102
103template <>
104bool IsValidImageIndex<VEH_AIRCRAFT>(uint8_t image_index)
105{
106 return image_index < lengthof(_aircraft_sprite);
107}
108
111 HRS_ROTOR_STOPPED,
112 HRS_ROTOR_MOVING_1,
113 HRS_ROTOR_MOVING_2,
114 HRS_ROTOR_MOVING_3,
115};
116
124static StationID FindNearestHangar(const Aircraft *v)
125{
126 uint best = 0;
127 StationID index = INVALID_STATION;
128 TileIndex vtile = TileVirtXY(v->x_pos, v->y_pos);
129 const AircraftVehicleInfo *avi = AircraftVehInfo(v->engine_type);
130 uint max_range = v->acache.cached_max_range_sqr;
131
132 /* Determine destinations where it's coming from and where it's heading to */
133 const Station *last_dest = nullptr;
134 const Station *next_dest = nullptr;
135 if (max_range != 0) {
136 if (v->current_order.IsType(OT_GOTO_STATION) ||
137 (v->current_order.IsType(OT_GOTO_DEPOT) && (v->current_order.GetDepotActionType() & ODATFB_NEAREST_DEPOT) == 0)) {
140 } else {
141 last_dest = GetTargetAirportIfValid(v);
143 }
144 }
145
146 for (const Station *st : Station::Iterate()) {
147 if (st->owner != v->owner || !(st->facilities & FACIL_AIRPORT) || !st->airport.HasHangar()) continue;
148
149 const AirportFTAClass *afc = st->airport.GetFTA();
150
151 /* don't crash the plane if we know it can't land at the airport */
152 if ((afc->flags & AirportFTAClass::SHORT_STRIP) && (avi->subtype & AIR_FAST) && !_cheats.no_jetcrash.value) continue;
153
154 /* the plane won't land at any helicopter station */
155 if (!(afc->flags & AirportFTAClass::AIRPLANES) && (avi->subtype & AIR_CTOL)) continue;
156
157 /* Check if our last and next destinations can be reached from the depot airport. */
158 if (max_range != 0) {
159 uint last_dist = (last_dest != nullptr && last_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, last_dest->airport.tile) : 0;
160 uint next_dist = (next_dest != nullptr && next_dest->airport.tile != INVALID_TILE) ? DistanceSquare(st->airport.tile, next_dest->airport.tile) : 0;
161 if (last_dist > max_range || next_dist > max_range) continue;
162 }
163
164 /* v->tile can't be used here, when aircraft is flying v->tile is set to 0 */
165 uint distance = DistanceSquare(vtile, st->airport.tile);
166 if (distance < best || index == INVALID_STATION) {
167 best = distance;
168 index = st->index;
169 }
170 }
171 return index;
172}
173
174void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const
175{
176 uint8_t spritenum = this->spritenum;
177
178 if (is_custom_sprite(spritenum)) {
179 GetCustomVehicleSprite(this, direction, image_type, result);
180 if (result->IsValid()) return;
181
183 }
184
185 assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
186 result->Set(direction + _aircraft_sprite[spritenum]);
187}
188
189void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result)
190{
191 assert(v->subtype == AIR_HELICOPTER);
192
193 const Aircraft *w = v->Next()->Next();
194 if (is_custom_sprite(v->spritenum)) {
195 GetCustomRotorSprite(v, image_type, result);
196 if (result->IsValid()) return;
197 }
198
199 /* Return standard rotor sprites if there are no custom sprites for this helicopter */
200 result->Set(SPR_ROTOR_STOPPED + w->state);
201}
202
203static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result)
204{
205 const Engine *e = Engine::Get(engine);
206 uint8_t spritenum = e->u.air.image_index;
207
208 if (is_custom_sprite(spritenum)) {
209 GetCustomVehicleIcon(engine, DIR_W, image_type, result);
210 if (result->IsValid()) return;
211
212 spritenum = e->original_image_index;
213 }
214
215 assert(IsValidImageIndex<VEH_AIRCRAFT>(spritenum));
216 result->Set(DIR_W + _aircraft_sprite[spritenum]);
217}
218
219void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
220{
222 GetAircraftIcon(engine, image_type, &seq);
223
224 Rect rect;
225 seq.GetBounds(&rect);
226 preferred_x = Clamp(preferred_x,
227 left - UnScaleGUI(rect.left),
228 right - UnScaleGUI(rect.right));
229
230 seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH);
231
232 if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) {
233 VehicleSpriteSeq rotor_seq;
234 GetCustomRotorIcon(engine, image_type, &rotor_seq);
235 if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED);
236 rotor_seq.Draw(preferred_x, y - ScaleSpriteTrad(5), PAL_NONE, false);
237 }
238}
239
249void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
250{
252 GetAircraftIcon(engine, image_type, &seq);
253
254 Rect rect;
255 seq.GetBounds(&rect);
256
257 width = UnScaleGUI(rect.Width());
258 height = UnScaleGUI(rect.Height());
259 xoffs = UnScaleGUI(rect.left);
260 yoffs = UnScaleGUI(rect.top);
261}
262
272{
273 const AircraftVehicleInfo *avi = &e->u.air;
274 const Station *st = Station::GetByTile(tile);
275
276 /* Prevent building aircraft types at places which can't handle them */
277 if (!CanVehicleUseStation(e->index, st)) return CMD_ERROR;
278
279 /* Make sure all aircraft end up in the first tile of the hangar. */
280 tile = st->airport.GetHangarTile(st->airport.GetHangarNum(tile));
281
282 if (flags & DC_EXEC) {
283 Aircraft *v = new Aircraft(); // aircraft
284 Aircraft *u = new Aircraft(); // shadow
285 *ret = v;
286
287 v->direction = DIR_SE;
288
289 v->owner = u->owner = _current_company;
290
291 v->tile = tile;
292
293 uint x = TileX(tile) * TILE_SIZE + 5;
294 uint y = TileY(tile) * TILE_SIZE + 3;
295
296 v->x_pos = u->x_pos = x;
297 v->y_pos = u->y_pos = y;
298
299 u->z_pos = GetSlopePixelZ(x, y);
300 v->z_pos = u->z_pos + 1;
301
304
305 v->spritenum = avi->image_index;
306
308 v->refit_cap = 0;
309 u->refit_cap = 0;
310
312 assert(IsValidCargoID(v->cargo_type));
313
314 CargoID mail = GetCargoIDByLabel(CT_MAIL);
315 if (IsValidCargoID(mail)) {
316 u->cargo_type = mail;
317 u->cargo_cap = avi->mail_capacity;
318 }
319
320 v->name.clear();
321 v->last_station_visited = INVALID_STATION;
322 v->last_loading_station = INVALID_STATION;
323
324 v->acceleration = avi->acceleration;
325 v->engine_type = e->index;
326 u->engine_type = e->index;
327
329 v->UpdateDeltaXY();
330
331 u->subtype = AIR_SHADOW;
332 u->UpdateDeltaXY();
333
334 v->reliability = e->reliability;
337
338 v->pos = GetVehiclePosOnBuild(tile);
339
340 v->state = HANGAR;
341 v->previous_pos = v->pos;
343 v->SetNext(u);
344
345 v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_aircraft);
346
350
351 v->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
352 u->sprite_cache.sprite_seq.Set(SPR_IMG_QUERY);
353
354 v->random_bits = Random();
355 u->random_bits = Random();
356
357 v->vehicle_flags = 0;
359 v->SetServiceIntervalIsPercent(Company::Get(_current_company)->settings.vehicle.servint_ispercent);
360
362
363 v->cargo_cap = e->DetermineCapacity(v, &u->cargo_cap);
364
366
367 UpdateAircraftCache(v, true);
368
369 v->UpdatePosition();
370 u->UpdatePosition();
371
372 /* Aircraft with 3 vehicles (chopper)? */
373 if (v->subtype == AIR_HELICOPTER) {
374 Aircraft *w = new Aircraft();
375 w->engine_type = e->index;
376 w->direction = DIR_N;
378 w->x_pos = v->x_pos;
379 w->y_pos = v->y_pos;
380 w->z_pos = v->z_pos + ROTOR_Z_OFFSET;
382 w->spritenum = 0xFF;
383 w->subtype = AIR_ROTOR;
384 w->sprite_cache.sprite_seq.Set(SPR_ROTOR_STOPPED);
385 w->random_bits = Random();
386 /* Use rotor's air.state to store the rotor animation frame */
387 w->state = HRS_ROTOR_STOPPED;
388 w->UpdateDeltaXY();
389
390 u->SetNext(w);
391 w->UpdatePosition();
392 }
393 }
394
395 return CommandCost();
396}
397
398
400{
401 const Station *st = GetTargetAirportIfValid(this);
402 /* If the station is not a valid airport or if it has no hangars */
403 if (st == nullptr || !CanVehicleUseStation(this, st) || !st->airport.HasHangar()) {
404 /* the aircraft has to search for a hangar on its own */
405 StationID station = FindNearestHangar(this);
406
407 if (station == INVALID_STATION) return ClosestDepot();
408
409 st = Station::Get(station);
410 }
411
412 return ClosestDepot(st->xy, st->index);
413}
414
415static void CheckIfAircraftNeedsService(Aircraft *v)
416{
417 if (Company::Get(v->owner)->settings.vehicle.servint_aircraft == 0 || !v->NeedsAutomaticServicing()) return;
418 if (v->IsChainInDepot()) {
420 return;
421 }
422
423 /* When we're parsing conditional orders and the like
424 * we don't want to consider going to a depot too. */
425 if (!v->current_order.IsType(OT_GOTO_DEPOT) && !v->current_order.IsType(OT_GOTO_STATION)) return;
426
428
429 assert(st != nullptr);
430
431 /* only goto depot if the target airport has a depot */
432 if (st->airport.HasHangar() && CanVehicleUseStation(v, st)) {
435 } else if (v->current_order.IsType(OT_GOTO_DEPOT)) {
438 }
439}
440
442{
443 const Engine *e = this->GetEngine();
444 uint cost_factor = GetVehicleProperty(this, PROP_AIRCRAFT_RUNNING_COST_FACTOR, e->u.air.running_cost);
445 return GetPrice(PR_RUNNING_AIRCRAFT, cost_factor, e->GetGRF());
446}
447
450{
451 if (!this->IsNormalAircraft()) return;
452 AgeVehicle(this);
453}
454
457{
458 if (!this->IsNormalAircraft()) return;
459 EconomyAgeVehicle(this);
460
461 if ((++this->day_counter & 7) == 0) DecreaseVehicleValue(this);
462
463 CheckOrders(this);
464
465 CheckVehicleBreakdown(this);
466 CheckIfAircraftNeedsService(this);
467
468 if (this->running_ticks == 0) return;
469
471
472 this->profit_this_year -= cost.GetCost();
473 this->running_ticks = 0;
474
476
479}
480
481static void HelicopterTickHandler(Aircraft *v)
482{
483 Aircraft *u = v->Next()->Next();
484
485 if (u->vehstatus & VS_HIDDEN) return;
486
487 /* if true, helicopter rotors do not rotate. This should only be the case if a helicopter is
488 * loading/unloading at a terminal or stopped */
489 if (v->current_order.IsType(OT_LOADING) || (v->vehstatus & VS_STOPPED)) {
490 if (u->cur_speed != 0) {
491 u->cur_speed++;
492 if (u->cur_speed >= 0x80 && u->state == HRS_ROTOR_MOVING_3) {
493 u->cur_speed = 0;
494 }
495 }
496 } else {
497 if (u->cur_speed == 0) {
498 u->cur_speed = 0x70;
499 }
500 if (u->cur_speed >= 0x50) {
501 u->cur_speed--;
502 }
503 }
504
505 int tick = ++u->tick_counter;
506 int spd = u->cur_speed >> 4;
507
509 if (spd == 0) {
510 u->state = HRS_ROTOR_STOPPED;
511 GetRotorImage(v, EIT_ON_MAP, &seq);
512 if (u->sprite_cache.sprite_seq == seq) return;
513 } else if (tick >= spd) {
514 u->tick_counter = 0;
515 u->state++;
516 if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1;
517 GetRotorImage(v, EIT_ON_MAP, &seq);
518 } else {
519 return;
520 }
521
522 u->sprite_cache.sprite_seq = seq;
523
525}
526
534void SetAircraftPosition(Aircraft *v, int x, int y, int z)
535{
536 v->x_pos = x;
537 v->y_pos = y;
538 v->z_pos = z;
539
540 v->UpdatePosition();
541 v->UpdateViewport(true, false);
542 if (v->subtype == AIR_HELICOPTER) {
543 GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_cache.sprite_seq);
544 }
545
546 Aircraft *u = v->Next();
547
548 int safe_x = Clamp(x, 0, Map::MaxX() * TILE_SIZE);
549 int safe_y = Clamp(y - 1, 0, Map::MaxY() * TILE_SIZE);
550 u->x_pos = x;
551 u->y_pos = y - ((v->z_pos - GetSlopePixelZ(safe_x, safe_y)) >> 3);
552
553 safe_y = Clamp(u->y_pos, 0, Map::MaxY() * TILE_SIZE);
554 u->z_pos = GetSlopePixelZ(safe_x, safe_y);
555 u->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq); // the shadow is never coloured
556
558
559 u = u->Next();
560 if (u != nullptr) {
561 u->x_pos = x;
562 u->y_pos = y;
563 u->z_pos = z + ROTOR_Z_OFFSET;
564
566 }
567}
568
574{
575 v->subspeed = 0;
576 v->progress = 0;
577
578 Aircraft *u = v->Next();
579 u->vehstatus |= VS_HIDDEN;
580 u = u->Next();
581 if (u != nullptr) {
582 u->vehstatus |= VS_HIDDEN;
583 u->cur_speed = 0;
584 }
585
586 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
587}
588
589static void PlayAircraftSound(const Vehicle *v)
590{
591 if (!PlayVehicleSound(v, VSE_START)) {
592 SndPlayVehicleFx(AircraftVehInfo(v->engine_type)->sfx, v);
593 }
594}
595
596
603void UpdateAircraftCache(Aircraft *v, bool update_range)
604{
605 uint max_speed = GetVehicleProperty(v, PROP_AIRCRAFT_SPEED, 0);
606 if (max_speed != 0) {
607 /* Convert from original units to km-ish/h */
608 max_speed = (max_speed * 128) / 10;
609
610 v->vcache.cached_max_speed = max_speed;
611 } else {
612 /* Use the default max speed of the vehicle. */
613 v->vcache.cached_max_speed = AircraftVehInfo(v->engine_type)->max_speed;
614 }
615
616 /* Update cargo aging period. */
618 Aircraft *u = v->Next(); // Shadow for mail
620
621 /* Update aircraft range. */
622 if (update_range) {
623 v->acache.cached_max_range = GetVehicleProperty(v, PROP_AIRCRAFT_RANGE, AircraftVehInfo(v->engine_type)->max_range);
624 /* Squared it now so we don't have to do it later all the time. */
625 v->acache.cached_max_range_sqr = v->acache.cached_max_range * v->acache.cached_max_range;
626 }
627}
628
629
633static constexpr uint16_t SPEED_LIMIT_TAXI = 50;
634static constexpr uint16_t SPEED_LIMIT_APPROACH = 230;
635static constexpr uint16_t SPEED_LIMIT_BROKEN = 320;
636static constexpr uint16_t SPEED_LIMIT_HOLD = 425;
637static constexpr uint16_t SPEED_LIMIT_NONE = UINT16_MAX;
638
646static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit = SPEED_LIMIT_NONE, bool hard_limit = true)
647{
655 uint spd = v->acceleration * 77;
656 uint8_t t;
657
658 /* Adjust speed limits by plane speed factor to prevent taxiing
659 * and take-off speeds being too low. */
660 speed_limit *= _settings_game.vehicle.plane_speed;
661
662 /* adjust speed for broken vehicles */
663 if (v->vehstatus & VS_AIRCRAFT_BROKEN) {
664 if (SPEED_LIMIT_BROKEN < speed_limit) hard_limit = false;
665 speed_limit = std::min<uint>(speed_limit, SPEED_LIMIT_BROKEN);
666 }
667
668 if (v->vcache.cached_max_speed < speed_limit) {
669 if (v->cur_speed < speed_limit) hard_limit = false;
670 speed_limit = v->vcache.cached_max_speed;
671 }
672
673 v->subspeed = (t = v->subspeed) + (uint8_t)spd;
674
675 /* Aircraft's current speed is used twice so that very fast planes are
676 * forced to slow down rapidly in the short distance needed. The magic
677 * value 16384 was determined to give similar results to the old speed/48
678 * method at slower speeds. This also results in less reduction at slow
679 * speeds to that aircraft do not get to taxi speed straight after
680 * touchdown. */
681 if (!hard_limit && v->cur_speed > speed_limit) {
682 speed_limit = v->cur_speed - std::max(1, ((v->cur_speed * v->cur_speed) / 16384) / _settings_game.vehicle.plane_speed);
683 }
684
685 spd = std::min(v->cur_speed + (spd >> 8) + (v->subspeed < t), speed_limit);
686
687 /* updates statusbar only if speed have changed to save CPU time */
688 if (spd != v->cur_speed) {
689 v->cur_speed = spd;
691 }
692
693 /* Adjust distance moved by plane speed setting */
695
696 /* Convert direction-independent speed into direction-dependent speed. (old movement method) */
697 spd = v->GetOldAdvanceSpeed(spd);
698
699 spd += v->progress;
700 v->progress = (uint8_t)spd;
701 return spd >> 8;
702}
703
712{
713 int safe_x = Clamp(v->x_pos, 0, Map::MaxX() * TILE_SIZE);
714 int safe_y = Clamp(v->y_pos, 0, Map::MaxY() * TILE_SIZE);
715 return TileHeight(TileVirtXY(safe_x, safe_y)) * TILE_HEIGHT;
716}
717
728void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level)
729{
730 int base_altitude = GetTileHeightBelowAircraft(v);
733 }
734
735 /* Make sure eastbound and westbound planes do not "crash" into each
736 * other by providing them with vertical separation
737 */
738 switch (v->direction) {
739 case DIR_N:
740 case DIR_NE:
741 case DIR_E:
742 case DIR_SE:
743 base_altitude += 10;
744 break;
745
746 default: break;
747 }
748
749 /* Make faster planes fly higher so that they can overtake slower ones */
750 base_altitude += std::min(20 * (v->vcache.cached_max_speed / 200) - 90, 0);
751
752 if (min_level != nullptr) *min_level = base_altitude + AIRCRAFT_MIN_FLYING_ALTITUDE;
753 if (max_level != nullptr) *max_level = base_altitude + AIRCRAFT_MAX_FLYING_ALTITUDE;
754}
755
764{
765 int tile_height = GetTileHeightBelowAircraft(v);
766
768}
769
770template <class T>
771int GetAircraftFlightLevel(T *v, bool takeoff)
772{
773 /* Aircraft is in flight. We want to enforce it being somewhere
774 * between the minimum and the maximum allowed altitude. */
775 int aircraft_min_altitude;
776 int aircraft_max_altitude;
777 GetAircraftFlightLevelBounds(v, &aircraft_min_altitude, &aircraft_max_altitude);
778 int aircraft_middle_altitude = (aircraft_min_altitude + aircraft_max_altitude) / 2;
779
780 /* If those assumptions would be violated, aircraft would behave fairly strange. */
781 assert(aircraft_min_altitude < aircraft_middle_altitude);
782 assert(aircraft_middle_altitude < aircraft_max_altitude);
783
784 int z = v->z_pos;
785 if (z < aircraft_min_altitude ||
786 (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z < aircraft_middle_altitude)) {
787 /* Ascend. And don't fly into that mountain right ahead.
788 * And avoid our aircraft become a stairclimber, so if we start
789 * correcting altitude, then we stop correction not too early. */
791 z += takeoff ? 2 : 1;
792 } else if (!takeoff && (z > aircraft_max_altitude ||
793 (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z > aircraft_middle_altitude))) {
794 /* Descend lower. You are an aircraft, not an space ship.
795 * And again, don't stop correcting altitude too early. */
797 z--;
798 } else if (HasBit(v->flags, VAF_IN_MIN_HEIGHT_CORRECTION) && z >= aircraft_middle_altitude) {
799 /* Now, we have corrected altitude enough. */
801 } else if (HasBit(v->flags, VAF_IN_MAX_HEIGHT_CORRECTION) && z <= aircraft_middle_altitude) {
802 /* Now, we have corrected altitude enough. */
804 }
805
806 return z;
807}
808
809template int GetAircraftFlightLevel(DisasterVehicle *v, bool takeoff);
810template int GetAircraftFlightLevel(Aircraft *v, bool takeoff);
811
826static uint8_t AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation)
827{
828 assert(v != nullptr);
829 assert(apc != nullptr);
830
831 /* In the case the station doesn't exit anymore, set target tile 0.
832 * It doesn't hurt much, aircraft will go to next order, nearest hangar
833 * or it will simply crash in next tick */
834 TileIndex tile = 0;
835
837 if (st != nullptr) {
838 /* Make sure we don't go to INVALID_TILE if the airport has been removed. */
839 tile = (st->airport.tile != INVALID_TILE) ? st->airport.tile : st->xy;
840 }
841
842 int delta_x = v->x_pos - TileX(tile) * TILE_SIZE;
843 int delta_y = v->y_pos - TileY(tile) * TILE_SIZE;
844
845 DiagDirection dir;
846 if (abs(delta_y) < abs(delta_x)) {
847 /* We are northeast or southwest of the airport */
848 dir = delta_x < 0 ? DIAGDIR_NE : DIAGDIR_SW;
849 } else {
850 /* We are northwest or southeast of the airport */
851 dir = delta_y < 0 ? DIAGDIR_NW : DIAGDIR_SE;
852 }
854 return apc->entry_points[dir];
855}
856
857
858static void MaybeCrashAirplane(Aircraft *v);
859
868{
869 /* nullptr if station is invalid */
871 /* INVALID_TILE if there is no station */
872 TileIndex tile = INVALID_TILE;
873 Direction rotation = DIR_N;
874 uint size_x = 1, size_y = 1;
875 if (st != nullptr) {
876 if (st->airport.tile != INVALID_TILE) {
877 tile = st->airport.tile;
878 rotation = st->airport.rotation;
879 size_x = st->airport.w;
880 size_y = st->airport.h;
881 } else {
882 tile = st->xy;
883 }
884 }
885 /* DUMMY if there is no station or no airport */
886 const AirportFTAClass *afc = tile == INVALID_TILE ? GetAirport(AT_DUMMY) : st->airport.GetFTA();
887
888 /* prevent going to INVALID_TILE if airport is deleted. */
889 if (st == nullptr || st->airport.tile == INVALID_TILE) {
890 /* Jump into our "holding pattern" state machine if possible */
891 if (v->pos >= afc->nofelements) {
892 v->pos = v->previous_pos = AircraftGetEntryPoint(v, afc, DIR_N);
893 } else if (v->targetairport != v->current_order.GetDestination()) {
894 /* If not possible, just get out of here fast */
895 v->state = FLYING;
898 /* get aircraft back on running altitude */
899 SetAircraftPosition(v, v->x_pos, v->y_pos, GetAircraftFlightLevel(v));
900 return false;
901 }
902 }
903
904 /* get airport moving data */
905 const AirportMovingData amd = RotateAirportMovingData(afc->MovingData(v->pos), rotation, size_x, size_y);
906
907 int x = TileX(tile) * TILE_SIZE;
908 int y = TileY(tile) * TILE_SIZE;
909
910 /* Helicopter raise */
911 if (amd.flag & AMED_HELI_RAISE) {
912 Aircraft *u = v->Next()->Next();
913
914 /* Make sure the rotors don't rotate too fast */
915 if (u->cur_speed > 32) {
916 v->cur_speed = 0;
917 if (--u->cur_speed == 32) {
918 if (!PlayVehicleSound(v, VSE_START)) {
919 SoundID sfx = AircraftVehInfo(v->engine_type)->sfx;
920 /* For compatibility with old NewGRF we ignore the sfx property, unless a NewGRF-defined sound is used.
921 * The baseset has only one helicopter sound, so this only limits using plane or cow sounds. */
923 SndPlayVehicleFx(sfx, v);
924 }
925 }
926 } else {
927 u->cur_speed = 32;
928 int count = UpdateAircraftSpeed(v);
929 if (count > 0) {
930 v->tile = 0;
931
932 int z_dest;
933 GetAircraftFlightLevelBounds(v, &z_dest, nullptr);
934
935 /* Reached altitude? */
936 if (v->z_pos >= z_dest) {
937 v->cur_speed = 0;
938 return true;
939 }
940 SetAircraftPosition(v, v->x_pos, v->y_pos, std::min(v->z_pos + count, z_dest));
941 }
942 }
943 return false;
944 }
945
946 /* Helicopter landing. */
947 if (amd.flag & AMED_HELI_LOWER) {
949
950 if (st == nullptr) {
951 /* FIXME - AircraftController -> if station no longer exists, do not land
952 * helicopter will circle until sign disappears, then go to next order
953 * what to do when it is the only order left, right now it just stays in 1 place */
954 v->state = FLYING;
957 return false;
958 }
959
960 /* Vehicle is now at the airport.
961 * Helicopter has arrived at the target landing pad, so the current position is also where it should land.
962 * Except for Oilrigs which are special due to being a 1x1 station, and helicopters land outside it. */
963 if (st->airport.type != AT_OILRIG) {
964 x = v->x_pos;
965 y = v->y_pos;
966 tile = TileVirtXY(x, y);
967 }
968 v->tile = tile;
969
970 /* Find altitude of landing position. */
971 int z = GetSlopePixelZ(x, y) + 1 + afc->delta_z;
972
973 if (z == v->z_pos) {
974 Vehicle *u = v->Next()->Next();
975
976 /* Increase speed of rotors. When speed is 80, we've landed. */
977 if (u->cur_speed >= 80) {
979 return true;
980 }
981 u->cur_speed += 4;
982 } else {
983 int count = UpdateAircraftSpeed(v);
984 if (count > 0) {
985 if (v->z_pos > z) {
986 SetAircraftPosition(v, v->x_pos, v->y_pos, std::max(v->z_pos - count, z));
987 } else {
988 SetAircraftPosition(v, v->x_pos, v->y_pos, std::min(v->z_pos + count, z));
989 }
990 }
991 }
992 return false;
993 }
994
995 /* Get distance from destination pos to current pos. */
996 uint dist = abs(x + amd.x - v->x_pos) + abs(y + amd.y - v->y_pos);
997
998 /* Need exact position? */
999 if (!(amd.flag & AMED_EXACTPOS) && dist <= (amd.flag & AMED_SLOWTURN ? 8U : 4U)) return true;
1000
1001 /* At final pos? */
1002 if (dist == 0) {
1003 /* Change direction smoothly to final direction. */
1004 DirDiff dirdiff = DirDifference(amd.direction, v->direction);
1005 /* if distance is 0, and plane points in right direction, no point in calling
1006 * UpdateAircraftSpeed(). So do it only afterwards */
1007 if (dirdiff == DIRDIFF_SAME) {
1008 v->cur_speed = 0;
1009 return true;
1010 }
1011
1012 if (!UpdateAircraftSpeed(v, SPEED_LIMIT_TAXI)) return false;
1013
1015 v->cur_speed >>= 1;
1016
1017 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
1018 return false;
1019 }
1020
1023 if ((v->vehstatus & VS_CRASHED) != 0) return false;
1024 }
1025
1026 uint speed_limit = SPEED_LIMIT_TAXI;
1027 bool hard_limit = true;
1028
1029 if (amd.flag & AMED_NOSPDCLAMP) speed_limit = SPEED_LIMIT_NONE;
1030 if (amd.flag & AMED_HOLD) { speed_limit = SPEED_LIMIT_HOLD; hard_limit = false; }
1031 if (amd.flag & AMED_LAND) { speed_limit = SPEED_LIMIT_APPROACH; hard_limit = false; }
1032 if (amd.flag & AMED_BRAKE) { speed_limit = SPEED_LIMIT_TAXI; hard_limit = false; }
1033
1034 int count = UpdateAircraftSpeed(v, speed_limit, hard_limit);
1035 if (count == 0) return false;
1036
1037 /* If the plane will be a few subpixels away from the destination after
1038 * this movement loop, start nudging it towards the exact position for
1039 * the whole loop. Otherwise, heavily depending on the speed of the plane,
1040 * it is possible we totally overshoot the target, causing the plane to
1041 * make a loop, and trying again, and again, and again .. */
1042 bool nudge_towards_target = static_cast<uint>(count) + 3 > dist;
1043
1044 if (v->turn_counter != 0) v->turn_counter--;
1045
1046 do {
1047
1049
1050 if (nudge_towards_target || (amd.flag & AMED_LAND)) {
1051 /* move vehicle one pixel towards target */
1052 gp.x = (v->x_pos != (x + amd.x)) ?
1053 v->x_pos + ((x + amd.x > v->x_pos) ? 1 : -1) :
1054 v->x_pos;
1055 gp.y = (v->y_pos != (y + amd.y)) ?
1056 v->y_pos + ((y + amd.y > v->y_pos) ? 1 : -1) :
1057 v->y_pos;
1058
1059 /* Oilrigs must keep v->tile as st->airport.tile, since the landing pad is in a non-airport tile */
1060 gp.new_tile = (st->airport.type == AT_OILRIG) ? st->airport.tile : TileVirtXY(gp.x, gp.y);
1061
1062 } else {
1063
1064 /* Turn. Do it slowly if in the air. */
1065 Direction newdir = GetDirectionTowards(v, x + amd.x, y + amd.y);
1066 if (newdir != v->direction) {
1067 if (amd.flag & AMED_SLOWTURN && v->number_consecutive_turns < 8 && v->subtype == AIR_AIRCRAFT) {
1068 if (v->turn_counter == 0 || newdir == v->last_direction) {
1069 if (newdir == v->last_direction) {
1071 } else {
1073 }
1075 v->last_direction = v->direction;
1076 v->direction = newdir;
1077 }
1078
1079 /* Move vehicle. */
1080 gp = GetNewVehiclePos(v);
1081 } else {
1082 v->cur_speed >>= 1;
1083 v->direction = newdir;
1084
1085 /* When leaving a terminal an aircraft often goes to a position
1086 * directly in front of it. If it would move while turning it
1087 * would need an two extra turns to end up at the correct position.
1088 * To make it easier just disallow all moving while turning as
1089 * long as an aircraft is on the ground. */
1090 gp.x = v->x_pos;
1091 gp.y = v->y_pos;
1092 gp.new_tile = gp.old_tile = v->tile;
1093 }
1094 } else {
1096 /* Move vehicle. */
1097 gp = GetNewVehiclePos(v);
1098 }
1099 }
1100
1101 v->tile = gp.new_tile;
1102 /* If vehicle is in the air, use tile coordinate 0. */
1103 if (amd.flag & (AMED_TAKEOFF | AMED_SLOWTURN | AMED_LAND)) v->tile = 0;
1104
1105 /* Adjust Z for land or takeoff? */
1106 int z = v->z_pos;
1107
1108 if (amd.flag & AMED_TAKEOFF) {
1109 z = GetAircraftFlightLevel(v, true);
1110 } else if (amd.flag & AMED_HOLD) {
1111 /* Let the plane drop from normal flight altitude to holding pattern altitude */
1112 if (z > GetAircraftHoldMaxAltitude(v)) z--;
1113 } else if ((amd.flag & AMED_SLOWTURN) && (amd.flag & AMED_NOSPDCLAMP)) {
1114 z = GetAircraftFlightLevel(v);
1115 }
1116
1117 /* NewGRF airports (like a rotated intercontinental from OpenGFX+Airports) can be non-rectangular
1118 * and their primary (north-most) tile does not have to be part of the airport.
1119 * As such, the height of the primary tile can be different from the rest of the airport.
1120 * Given we are landing/breaking, and as such are not a helicopter, we know that there has to be a hangar.
1121 * We also know that the airport itself has to be completely flat (otherwise it is not a valid airport).
1122 * Therefore, use the height of this hangar to calculate our z-value. */
1123 int airport_z = v->z_pos;
1124 if ((amd.flag & (AMED_LAND | AMED_BRAKE)) && st != nullptr) {
1125 assert(st->airport.HasHangar());
1126 TileIndex hangar_tile = st->airport.GetHangarTile(0);
1127 airport_z = GetTileMaxPixelZ(hangar_tile) + 1; // To avoid clashing with the shadow
1128 }
1129
1130 if (amd.flag & AMED_LAND) {
1131 if (st->airport.tile == INVALID_TILE) {
1132 /* Airport has been removed, abort the landing procedure */
1133 v->state = FLYING;
1136 /* get aircraft back on running altitude */
1137 SetAircraftPosition(v, gp.x, gp.y, GetAircraftFlightLevel(v));
1138 continue;
1139 }
1140
1141 /* We're not flying below our destination, right? */
1142 assert(airport_z <= z);
1143 int t = std::max(1U, dist - 4);
1144 int delta = z - airport_z;
1145
1146 /* Only start lowering when we're sufficiently close for a 1:1 glide */
1147 if (delta >= t) {
1148 z -= CeilDiv(z - airport_z, t);
1149 }
1150 if (z < airport_z) z = airport_z;
1151 }
1152
1153 /* We've landed. Decrease speed when we're reaching end of runway. */
1154 if (amd.flag & AMED_BRAKE) {
1155
1156 if (z > airport_z) {
1157 z--;
1158 } else if (z < airport_z) {
1159 z++;
1160 }
1161
1162 }
1163
1164 SetAircraftPosition(v, gp.x, gp.y, z);
1165 } while (--count != 0);
1166 return false;
1167}
1168
1174{
1175 v->crashed_counter += 3;
1176
1178
1179 /* make aircraft crash down to the ground */
1180 if (v->crashed_counter < 500 && st == nullptr && ((v->crashed_counter % 3) == 0) ) {
1181 int z = GetSlopePixelZ(Clamp(v->x_pos, 0, Map::MaxX() * TILE_SIZE), Clamp(v->y_pos, 0, Map::MaxY() * TILE_SIZE));
1182 v->z_pos -= 1;
1183 if (v->z_pos <= z) {
1184 v->crashed_counter = 500;
1185 v->z_pos = z + 1;
1186 } else {
1187 v->crashed_counter = 0;
1188 }
1189 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
1190 }
1191
1192 if (v->crashed_counter < 650) {
1193 uint32_t r;
1194 if (Chance16R(1, 32, r)) {
1195 static const DirDiff delta[] = {
1197 };
1198
1199 v->direction = ChangeDir(v->direction, delta[GB(r, 16, 2)]);
1200 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
1201 r = Random();
1203 GB(r, 0, 4) - 4,
1204 GB(r, 4, 4) - 4,
1205 GB(r, 8, 4),
1207 }
1208 } else if (v->crashed_counter >= 10000) {
1209 /* remove rubble of crashed airplane */
1210
1211 /* clear runway-in on all airports, set by crashing plane
1212 * small airports use AIRPORT_BUSY, city airports use RUNWAY_IN_OUT_block, etc.
1213 * but they all share the same number */
1214 if (st != nullptr) {
1215 CLRBITS(st->airport.flags, RUNWAY_IN_block);
1216 CLRBITS(st->airport.flags, RUNWAY_IN_OUT_block); // commuter airport
1217 CLRBITS(st->airport.flags, RUNWAY_IN2_block); // intercontinental
1218 }
1219
1220 delete v;
1221
1222 return false;
1223 }
1224
1225 return true;
1226}
1227
1228
1234static void HandleAircraftSmoke(Aircraft *v, bool mode)
1235{
1236 static const struct {
1237 int8_t x;
1238 int8_t y;
1239 } smoke_pos[] = {
1240 { 5, 5 },
1241 { 6, 0 },
1242 { 5, -5 },
1243 { 0, -6 },
1244 { -5, -5 },
1245 { -6, 0 },
1246 { -5, 5 },
1247 { 0, 6 }
1248 };
1249
1250 if (!(v->vehstatus & VS_AIRCRAFT_BROKEN)) return;
1251
1252 /* Stop smoking when landed */
1253 if (v->cur_speed < 10) {
1254 v->vehstatus &= ~VS_AIRCRAFT_BROKEN;
1255 v->breakdown_ctr = 0;
1256 return;
1257 }
1258
1259 /* Spawn effect et most once per Tick, i.e. !mode */
1260 if (!mode && (v->tick_counter & 0x0F) == 0) {
1262 smoke_pos[v->direction].x,
1263 smoke_pos[v->direction].y,
1264 2,
1266 );
1267 }
1268}
1269
1270void HandleMissingAircraftOrders(Aircraft *v)
1271{
1272 /*
1273 * We do not have an order. This can be divided into two cases:
1274 * 1) we are heading to an invalid station. In this case we must
1275 * find another airport to go to. If there is nowhere to go,
1276 * we will destroy the aircraft as it otherwise will enter
1277 * the holding pattern for the first airport, which can cause
1278 * the plane to go into an undefined state when building an
1279 * airport with the same StationID.
1280 * 2) we are (still) heading to a (still) valid airport, then we
1281 * can continue going there. This can happen when you are
1282 * changing the aircraft's orders while in-flight or in for
1283 * example a depot. However, when we have a current order to
1284 * go to a depot, we have to keep that order so the aircraft
1285 * actually stops.
1286 */
1287 const Station *st = GetTargetAirportIfValid(v);
1288 if (st == nullptr) {
1289 Backup<CompanyID> cur_company(_current_company, v->owner);
1291 cur_company.Restore();
1292
1293 if (ret.Failed()) CrashAirplane(v);
1294 } else if (!v->current_order.IsType(OT_GOTO_DEPOT)) {
1295 v->current_order.Free();
1296 }
1297}
1298
1299
1301{
1302 /* Orders are changed in flight, ensure going to the right station. */
1303 if (this->state == FLYING) {
1305 }
1306
1307 /* Aircraft do not use dest-tile */
1308 return 0;
1309}
1310
1312{
1313 this->colourmap = PAL_NONE;
1314 this->UpdateViewport(true, false);
1315 if (this->subtype == AIR_HELICOPTER) {
1316 GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_cache.sprite_seq);
1317 }
1318}
1319
1320
1321uint Aircraft::Crash(bool flooded)
1322{
1323 uint victims = Vehicle::Crash(flooded) + 2; // pilots
1324 this->crashed_counter = flooded ? 9000 : 0; // max 10000, disappear pretty fast when flooded
1325
1326 return victims;
1327}
1328
1334{
1336
1337 uint victims = v->Crash();
1338 SetDParam(0, victims);
1339
1340 v->cargo.Truncate();
1341 v->Next()->cargo.Truncate();
1342 const Station *st = GetTargetAirportIfValid(v);
1343 StringID newsitem;
1344 TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
1345 if (st == nullptr) {
1346 newsitem = STR_NEWS_PLANE_CRASH_OUT_OF_FUEL;
1347 } else {
1348 SetDParam(1, st->index);
1349 newsitem = STR_NEWS_AIRCRAFT_CRASH;
1350 }
1351
1352 AI::NewEvent(v->owner, new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims));
1353 Game::NewEvent(new ScriptEventVehicleCrashed(v->index, vt, st == nullptr ? ScriptEventVehicleCrashed::CRASH_AIRCRAFT_NO_AIRPORT : ScriptEventVehicleCrashed::CRASH_PLANE_LANDING, victims));
1354
1355 NewsType newstype = NT_ACCIDENT;
1356 if (v->owner != _local_company) {
1357 newstype = NT_ACCIDENT_OTHER;
1358 }
1359
1360 AddTileNewsItem(newsitem, newstype, vt, nullptr, st != nullptr ? st->index : INVALID_STATION);
1361
1362 ModifyStationRatingAround(vt, v->owner, -160, 30);
1363 if (_settings_client.sound.disaster) SndPlayVehicleFx(SND_12_EXPLOSION, v);
1364}
1365
1371{
1372
1374
1375 uint32_t prob;
1377 (AircraftVehInfo(v->engine_type)->subtype & AIR_FAST) &&
1379 prob = 3276;
1380 } else {
1381 if (_settings_game.vehicle.plane_crashes == 0) return;
1382 prob = (0x4000 << _settings_game.vehicle.plane_crashes) / 1500;
1383 }
1384
1385 if (GB(Random(), 0, 22) > prob) return;
1386
1387 /* Crash the airplane. Remove all goods stored at the station. */
1388 for (GoodsEntry &ge : st->goods) {
1389 ge.rating = 1;
1390 ge.cargo.Truncate();
1391 }
1392
1393 CrashAirplane(v);
1394}
1395
1402{
1403 if (v->current_order.IsType(OT_GOTO_DEPOT)) return;
1404
1407
1408 /* Check if station was ever visited before */
1409 if (!(st->had_vehicle_of_type & HVOT_AIRCRAFT)) {
1410 st->had_vehicle_of_type |= HVOT_AIRCRAFT;
1411 SetDParam(0, st->index);
1412 /* show newsitem of celebrating citizens */
1414 STR_NEWS_FIRST_AIRCRAFT_ARRIVAL,
1416 v->index,
1417 st->index
1418 );
1419 AI::NewEvent(v->owner, new ScriptEventStationFirstVehicle(st->index, v->index));
1420 Game::NewEvent(new ScriptEventStationFirstVehicle(st->index, v->index));
1421 }
1422
1423 v->BeginLoading();
1424}
1425
1431{
1433
1434 TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
1435
1436 v->UpdateDeltaXY();
1437
1438 AirportTileAnimationTrigger(st, vt, AAT_STATION_AIRPLANE_LAND);
1439
1441 SndPlayVehicleFx(SND_17_SKID_PLANE, v);
1442 }
1443}
1444
1445
1448{
1449 if (v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT)) {
1451 }
1452
1453 const Station *st = GetTargetAirportIfValid(v);
1454 const AirportFTAClass *apc = st == nullptr ? GetAirport(AT_DUMMY) : st->airport.GetFTA();
1455 Direction rotation = st == nullptr ? DIR_N : st->airport.rotation;
1456 v->pos = v->previous_pos = AircraftGetEntryPoint(v, apc, rotation);
1457}
1458
1468{
1469 v->cur_speed = 0;
1470 v->subspeed = 0;
1471 v->progress = 0;
1472 v->direction = exit_dir;
1473 v->vehstatus &= ~VS_HIDDEN;
1474 {
1475 Vehicle *u = v->Next();
1476 u->vehstatus &= ~VS_HIDDEN;
1477
1478 /* Rotor blades */
1479 u = u->Next();
1480 if (u != nullptr) {
1481 u->vehstatus &= ~VS_HIDDEN;
1482 u->cur_speed = 80;
1483 }
1484 }
1485
1488 SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
1491}
1492
1496static void AircraftEventHandler_EnterTerminal(Aircraft *v, const AirportFTAClass *apc)
1497{
1499 v->state = apc->layout[v->pos].heading;
1500}
1501
1508{
1510 v->state = apc->layout[v->pos].heading;
1511}
1512
1519{
1520 /* if we just arrived, execute EnterHangar first */
1521 if (v->previous_pos != v->pos) {
1523 return;
1524 }
1525
1526 /* if we were sent to the depot, stay there */
1527 if (v->current_order.IsType(OT_GOTO_DEPOT) && (v->vehstatus & VS_STOPPED)) {
1528 v->current_order.Free();
1529 return;
1530 }
1531
1532 /* Check if we should wait here for unbunching. */
1533 if (v->IsWaitingForUnbunching()) return;
1534
1535 if (!v->current_order.IsType(OT_GOTO_STATION) &&
1536 !v->current_order.IsType(OT_GOTO_DEPOT))
1537 return;
1538
1539 /* We are leaving a hangar, but have to go to the exact same one; re-enter */
1540 if (v->current_order.IsType(OT_GOTO_DEPOT) && v->current_order.GetDestination() == v->targetairport) {
1542 return;
1543 }
1544
1545 /* if the block of the next position is busy, stay put */
1546 if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
1547
1548 /* We are already at the target airport, we need to find a terminal */
1550 /* FindFreeTerminal:
1551 * 1. Find a free terminal, 2. Occupy it, 3. Set the vehicle's state to that terminal */
1552 if (v->subtype == AIR_HELICOPTER) {
1553 if (!AirportFindFreeHelipad(v, apc)) return; // helicopter
1554 } else {
1555 if (!AirportFindFreeTerminal(v, apc)) return; // airplane
1556 }
1557 } else { // Else prepare for launch.
1558 /* airplane goto state takeoff, helicopter to helitakeoff */
1560 }
1561 const Station *st = Station::GetByTile(v->tile);
1563 AirportMove(v, apc);
1564}
1565
1568{
1569 /* if we just arrived, execute EnterTerminal first */
1570 if (v->previous_pos != v->pos) {
1571 AircraftEventHandler_EnterTerminal(v, apc);
1572 /* on an airport with helipads, a helicopter will always land there
1573 * and get serviced at the same time - setting */
1575 if (v->subtype == AIR_HELICOPTER && apc->num_helipads > 0) {
1576 /* an excerpt of ServiceAircraft, without the invisibility stuff */
1582 }
1583 }
1584 return;
1585 }
1586
1587 if (v->current_order.IsType(OT_NOTHING)) return;
1588
1589 /* if the block of the next position is busy, stay put */
1590 if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
1591
1592 /* airport-road is free. We either have to go to another airport, or to the hangar
1593 * ---> start moving */
1594
1595 bool go_to_hangar = false;
1596 switch (v->current_order.GetType()) {
1597 case OT_GOTO_STATION: // ready to fly to another airport
1598 break;
1599 case OT_GOTO_DEPOT: // visit hangar for servicing, sale, etc.
1600 go_to_hangar = v->current_order.GetDestination() == v->targetairport;
1601 break;
1602 case OT_CONDITIONAL:
1603 /* In case of a conditional order we just have to wait a tick
1604 * longer, so the conditional order can actually be processed;
1605 * we should not clear the order as that makes us go nowhere. */
1606 return;
1607 default: // orders have been deleted (no orders), goto depot and don't bother us
1608 v->current_order.Free();
1609 go_to_hangar = true;
1610 }
1611
1612 if (go_to_hangar && Station::Get(v->targetairport)->airport.HasHangar()) {
1613 v->state = HANGAR;
1614 } else {
1615 /* airplane goto state takeoff, helicopter to helitakeoff */
1617 }
1618 AirportMove(v, apc);
1619}
1620
1621static void AircraftEventHandler_General(Aircraft *, const AirportFTAClass *)
1622{
1623 FatalError("OK, you shouldn't be here, check your Airport Scheme!");
1624}
1625
1626static void AircraftEventHandler_TakeOff(Aircraft *v, const AirportFTAClass *)
1627{
1628 PlayAircraftSound(v); // play takeoffsound for airplanes
1629 v->state = STARTTAKEOFF;
1630}
1631
1632static void AircraftEventHandler_StartTakeOff(Aircraft *v, const AirportFTAClass *)
1633{
1634 v->state = ENDTAKEOFF;
1635 v->UpdateDeltaXY();
1636}
1637
1638static void AircraftEventHandler_EndTakeOff(Aircraft *v, const AirportFTAClass *)
1639{
1640 v->state = FLYING;
1641 /* get the next position to go to, differs per airport */
1643}
1644
1645static void AircraftEventHandler_HeliTakeOff(Aircraft *v, const AirportFTAClass *)
1646{
1647 v->state = FLYING;
1648 v->UpdateDeltaXY();
1649
1650 /* get the next position to go to, differs per airport */
1652
1653 /* Send the helicopter to a hangar if needed for replacement */
1654 if (v->NeedsAutomaticServicing()) {
1655 Backup<CompanyID> cur_company(_current_company, v->owner);
1657 cur_company.Restore();
1658 }
1659}
1660
1661static void AircraftEventHandler_Flying(Aircraft *v, const AirportFTAClass *apc)
1662{
1664
1665 /* Runway busy, not allowed to use this airstation or closed, circle. */
1666 if (CanVehicleUseStation(v, st) && (st->owner == OWNER_NONE || st->owner == v->owner) && !(st->airport.flags & AIRPORT_CLOSED_block)) {
1667 /* {32,FLYING,NOTHING_block,37}, {32,LANDING,N,33}, {32,HELILANDING,N,41},
1668 * if it is an airplane, look for LANDING, for helicopter HELILANDING
1669 * it is possible to choose from multiple landing runways, so loop until a free one is found */
1670 uint8_t landingtype = (v->subtype == AIR_HELICOPTER) ? HELILANDING : LANDING;
1671 const AirportFTA *current = apc->layout[v->pos].next;
1672 while (current != nullptr) {
1673 if (current->heading == landingtype) {
1674 /* save speed before, since if AirportHasBlock is false, it resets them to 0
1675 * we don't want that for plane in air
1676 * hack for speed thingie */
1677 uint16_t tcur_speed = v->cur_speed;
1678 uint16_t tsubspeed = v->subspeed;
1679 if (!AirportHasBlock(v, current, apc)) {
1680 v->state = landingtype; // LANDING / HELILANDING
1682 /* it's a bit dirty, but I need to set position to next position, otherwise
1683 * if there are multiple runways, plane won't know which one it took (because
1684 * they all have heading LANDING). And also occupy that block! */
1685 v->pos = current->next_position;
1686 SETBITS(st->airport.flags, apc->layout[v->pos].block);
1687 return;
1688 }
1689 v->cur_speed = tcur_speed;
1690 v->subspeed = tsubspeed;
1691 }
1692 current = current->next;
1693 }
1694 }
1695 v->state = FLYING;
1696 v->pos = apc->layout[v->pos].next_position;
1697}
1698
1699static void AircraftEventHandler_Landing(Aircraft *v, const AirportFTAClass *)
1700{
1701 v->state = ENDLANDING;
1702 AircraftLandAirplane(v); // maybe crash airplane
1703
1704 /* check if the aircraft needs to be replaced or renewed and send it to a hangar if needed */
1705 if (v->NeedsAutomaticServicing()) {
1706 Backup<CompanyID> cur_company(_current_company, v->owner);
1708 cur_company.Restore();
1709 }
1710}
1711
1712static void AircraftEventHandler_HeliLanding(Aircraft *v, const AirportFTAClass *)
1713{
1714 v->state = HELIENDLANDING;
1715 v->UpdateDeltaXY();
1716}
1717
1718static void AircraftEventHandler_EndLanding(Aircraft *v, const AirportFTAClass *apc)
1719{
1720 /* next block busy, don't do a thing, just wait */
1721 if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
1722
1723 /* if going to terminal (OT_GOTO_STATION) choose one
1724 * 1. in case all terminals are busy AirportFindFreeTerminal() returns false or
1725 * 2. not going for terminal (but depot, no order),
1726 * --> get out of the way to the hangar. */
1727 if (v->current_order.IsType(OT_GOTO_STATION)) {
1728 if (AirportFindFreeTerminal(v, apc)) return;
1729 }
1730 v->state = HANGAR;
1731
1732}
1733
1734static void AircraftEventHandler_HeliEndLanding(Aircraft *v, const AirportFTAClass *apc)
1735{
1736 /* next block busy, don't do a thing, just wait */
1737 if (AirportHasBlock(v, &apc->layout[v->pos], apc)) return;
1738
1739 /* if going to helipad (OT_GOTO_STATION) choose one. If airport doesn't have helipads, choose terminal
1740 * 1. in case all terminals/helipads are busy (AirportFindFreeHelipad() returns false) or
1741 * 2. not going for terminal (but depot, no order),
1742 * --> get out of the way to the hangar IF there are terminals on the airport.
1743 * --> else TAKEOFF
1744 * the reason behind this is that if an airport has a terminal, it also has a hangar. Airplanes
1745 * must go to a hangar. */
1746 if (v->current_order.IsType(OT_GOTO_STATION)) {
1747 if (AirportFindFreeHelipad(v, apc)) return;
1748 }
1750}
1751
1757typedef void AircraftStateHandler(Aircraft *v, const AirportFTAClass *apc);
1760 AircraftEventHandler_General, // TO_ALL = 0
1761 AircraftEventHandler_InHangar, // HANGAR = 1
1768 AircraftEventHandler_AtTerminal, // HELIPAD1 = 8
1769 AircraftEventHandler_AtTerminal, // HELIPAD2 = 9
1770 AircraftEventHandler_TakeOff, // TAKEOFF = 10
1771 AircraftEventHandler_StartTakeOff, // STARTTAKEOFF = 11
1772 AircraftEventHandler_EndTakeOff, // ENDTAKEOFF = 12
1773 AircraftEventHandler_HeliTakeOff, // HELITAKEOFF = 13
1774 AircraftEventHandler_Flying, // FLYING = 14
1775 AircraftEventHandler_Landing, // LANDING = 15
1776 AircraftEventHandler_EndLanding, // ENDLANDING = 16
1777 AircraftEventHandler_HeliLanding, // HELILANDING = 17
1778 AircraftEventHandler_HeliEndLanding, // HELIENDLANDING = 18
1779 AircraftEventHandler_AtTerminal, // TERM7 = 19
1780 AircraftEventHandler_AtTerminal, // TERM8 = 20
1781 AircraftEventHandler_AtTerminal, // HELIPAD3 = 21
1782};
1783
1784static void AirportClearBlock(const Aircraft *v, const AirportFTAClass *apc)
1785{
1786 /* we have left the previous block, and entered the new one. Free the previous block */
1787 if (apc->layout[v->previous_pos].block != apc->layout[v->pos].block) {
1789
1791 }
1792}
1793
1794static void AirportGoToNextPosition(Aircraft *v)
1795{
1796 /* if aircraft is not in position, wait until it is */
1797 if (!AircraftController(v)) return;
1798
1800
1801 AirportClearBlock(v, apc);
1802 AirportMove(v, apc); // move aircraft to next position
1803}
1804
1805/* gets pos from vehicle and next orders */
1806static bool AirportMove(Aircraft *v, const AirportFTAClass *apc)
1807{
1808 /* error handling */
1809 if (v->pos >= apc->nofelements) {
1810 Debug(misc, 0, "[Ap] position {} is not valid for current airport. Max position is {}", v->pos, apc->nofelements-1);
1811 assert(v->pos < apc->nofelements);
1812 }
1813
1814 const AirportFTA *current = &apc->layout[v->pos];
1815 /* we have arrived in an important state (eg terminal, hangar, etc.) */
1816 if (current->heading == v->state) {
1817 uint8_t prev_pos = v->pos; // location could be changed in state, so save it before-hand
1818 uint8_t prev_state = v->state;
1819 _aircraft_state_handlers[v->state](v, apc);
1820 if (v->state != FLYING) v->previous_pos = prev_pos;
1821 if (v->state != prev_state || v->pos != prev_pos) UpdateAircraftCache(v);
1822 return true;
1823 }
1824
1825 v->previous_pos = v->pos; // save previous location
1826
1827 /* there is only one choice to move to */
1828 if (current->next == nullptr) {
1829 if (AirportSetBlocks(v, current, apc)) {
1830 v->pos = current->next_position;
1832 } // move to next position
1833 return false;
1834 }
1835
1836 /* there are more choices to choose from, choose the one that
1837 * matches our heading */
1838 do {
1839 if (v->state == current->heading || current->heading == TO_ALL) {
1840 if (AirportSetBlocks(v, current, apc)) {
1841 v->pos = current->next_position;
1843 } // move to next position
1844 return false;
1845 }
1846 current = current->next;
1847 } while (current != nullptr);
1848
1849 Debug(misc, 0, "[Ap] cannot move further on Airport! (pos {} state {}) for vehicle {}", v->pos, v->state, v->index);
1850 NOT_REACHED();
1851}
1852
1854static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc)
1855{
1856 const AirportFTA *reference = &apc->layout[v->pos];
1857 const AirportFTA *next = &apc->layout[current_pos->next_position];
1858
1859 /* same block, then of course we can move */
1860 if (apc->layout[current_pos->position].block != next->block) {
1861 const Station *st = Station::Get(v->targetairport);
1862 uint64_t airport_flags = next->block;
1863
1864 /* check additional possible extra blocks */
1865 if (current_pos != reference && current_pos->block != NOTHING_block) {
1866 airport_flags |= current_pos->block;
1867 }
1868
1869 if (st->airport.flags & airport_flags) {
1870 v->cur_speed = 0;
1871 v->subspeed = 0;
1872 return true;
1873 }
1874 }
1875 return false;
1876}
1877
1885static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc)
1886{
1887 const AirportFTA *next = &apc->layout[current_pos->next_position];
1888 const AirportFTA *reference = &apc->layout[v->pos];
1889
1890 /* if the next position is in another block, check it and wait until it is free */
1891 if ((apc->layout[current_pos->position].block & next->block) != next->block) {
1892 uint64_t airport_flags = next->block;
1893 /* search for all all elements in the list with the same state, and blocks != N
1894 * this means more blocks should be checked/set */
1895 const AirportFTA *current = current_pos;
1896 if (current == reference) current = current->next;
1897 while (current != nullptr) {
1898 if (current->heading == current_pos->heading && current->block != 0) {
1899 airport_flags |= current->block;
1900 break;
1901 }
1902 current = current->next;
1903 }
1904
1905 /* if the block to be checked is in the next position, then exclude that from
1906 * checking, because it has been set by the airplane before */
1907 if (current_pos->block == next->block) airport_flags ^= next->block;
1908
1910 if (st->airport.flags & airport_flags) {
1911 v->cur_speed = 0;
1912 v->subspeed = 0;
1913 return false;
1914 }
1915
1916 if (next->block != NOTHING_block) {
1917 SETBITS(st->airport.flags, airport_flags); // occupy next block
1918 }
1919 }
1920 return true;
1921}
1922
1931
1946
1954static bool FreeTerminal(Aircraft *v, uint8_t i, uint8_t last_terminal)
1955{
1956 assert(last_terminal <= lengthof(_airport_terminal_mapping));
1958 for (; i < last_terminal; i++) {
1960 /* TERMINAL# HELIPAD# */
1961 v->state = _airport_terminal_mapping[i].state; // start moving to that terminal/helipad
1962 SETBITS(st->airport.flags, _airport_terminal_mapping[i].airport_flag); // occupy terminal/helipad
1963 return true;
1964 }
1965 }
1966 return false;
1967}
1968
1974static uint GetNumTerminals(const AirportFTAClass *apc)
1975{
1976 uint num = 0;
1977
1978 for (uint i = apc->terminals[0]; i > 0; i--) num += apc->terminals[i];
1979
1980 return num;
1981}
1982
1990{
1991 /* example of more terminalgroups
1992 * {0,HANGAR,NOTHING_block,1}, {0,TERMGROUP,TERM_GROUP1_block,0}, {0,TERMGROUP,TERM_GROUP2_ENTER_block,1}, {0,0,N,1},
1993 * Heading TERMGROUP denotes a group. We see 2 groups here:
1994 * 1. group 0 -- TERM_GROUP1_block (check block)
1995 * 2. group 1 -- TERM_GROUP2_ENTER_block (check block)
1996 * First in line is checked first, group 0. If the block (TERM_GROUP1_block) is free, it
1997 * looks at the corresponding terminals of that group. If no free ones are found, other
1998 * possible groups are checked (in this case group 1, since that is after group 0). If that
1999 * fails, then attempt fails and plane waits
2000 */
2001 if (apc->terminals[0] > 1) {
2002 const Station *st = Station::Get(v->targetairport);
2003 const AirportFTA *temp = apc->layout[v->pos].next;
2004
2005 while (temp != nullptr) {
2006 if (temp->heading == TERMGROUP) {
2007 if (!(st->airport.flags & temp->block)) {
2008 /* read which group do we want to go to?
2009 * (the first free group) */
2010 uint target_group = temp->next_position + 1;
2011
2012 /* at what terminal does the group start?
2013 * that means, sum up all terminals of
2014 * groups with lower number */
2015 uint group_start = 0;
2016 for (uint i = 1; i < target_group; i++) {
2017 group_start += apc->terminals[i];
2018 }
2019
2020 uint group_end = group_start + apc->terminals[target_group];
2021 if (FreeTerminal(v, group_start, group_end)) return true;
2022 }
2023 } else {
2024 /* once the heading isn't 255, we've exhausted the possible blocks.
2025 * So we cannot move */
2026 return false;
2027 }
2028 temp = temp->next;
2029 }
2030 }
2031
2032 /* if there is only 1 terminalgroup, all terminals are checked (starting from 0 to max) */
2033 return FreeTerminal(v, 0, GetNumTerminals(apc));
2034}
2035
2043{
2044 /* if an airport doesn't have helipads, use terminals */
2045 if (apc->num_helipads == 0) return AirportFindFreeTerminal(v, apc);
2046
2047 /* only 1 helicoptergroup, check all helipads
2048 * The blocks for helipads start after the last terminal (MAX_TERMINALS) */
2050}
2051
2057static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
2058{
2059 if (too_far) {
2060 if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) {
2063 AI::NewEvent(v->owner, new ScriptEventAircraftDestTooFar(v->index));
2064 if (v->owner == _local_company) {
2065 /* Post a news message. */
2066 SetDParam(0, v->index);
2067 AddVehicleAdviceNewsItem(STR_NEWS_AIRCRAFT_DEST_TOO_FAR, v->index);
2068 }
2069 }
2070 return;
2071 }
2072
2073 if (HasBit(v->flags, VAF_DEST_TOO_FAR)) {
2074 /* Not too far anymore, clear flag and message. */
2077 DeleteVehicleNews(v->index, STR_NEWS_AIRCRAFT_DEST_TOO_FAR);
2078 }
2079}
2080
2081static bool AircraftEventHandler(Aircraft *v, int loop)
2082{
2083 if (v->vehstatus & VS_CRASHED) {
2084 return HandleCrashedAircraft(v);
2085 }
2086
2087 if (v->vehstatus & VS_STOPPED) return true;
2088
2089 v->HandleBreakdown();
2090
2091 HandleAircraftSmoke(v, loop != 0);
2092 ProcessOrders(v);
2093 v->HandleLoading(loop != 0);
2094
2095 if (v->current_order.IsType(OT_LOADING) || v->current_order.IsType(OT_LEAVESTATION)) return true;
2096
2097 if (v->state >= ENDTAKEOFF && v->state <= HELIENDLANDING) {
2098 /* If we are flying, unconditionally clear the 'dest too far' state. */
2099 AircraftHandleDestTooFar(v, false);
2100 } else if (v->acache.cached_max_range_sqr != 0) {
2101 /* Check the distance to the next destination. This code works because the target
2102 * airport is only updated after take off and not on the ground. */
2104 Station *next_st = v->current_order.IsType(OT_GOTO_STATION) || v->current_order.IsType(OT_GOTO_DEPOT) ? Station::GetIfValid(v->current_order.GetDestination()) : nullptr;
2105
2106 if (cur_st != nullptr && cur_st->airport.tile != INVALID_TILE && next_st != nullptr && next_st->airport.tile != INVALID_TILE) {
2107 uint dist = DistanceSquare(cur_st->airport.tile, next_st->airport.tile);
2109 }
2110 }
2111
2112 if (!HasBit(v->flags, VAF_DEST_TOO_FAR)) AirportGoToNextPosition(v);
2113
2114 return true;
2115}
2116
2118{
2119 if (!this->IsNormalAircraft()) return true;
2120
2122
2123 this->tick_counter++;
2124
2125 if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
2126
2127 if (this->subtype == AIR_HELICOPTER) HelicopterTickHandler(this);
2128
2129 this->current_order_time++;
2130
2131 for (uint i = 0; i != 2; i++) {
2132 /* stop if the aircraft was deleted */
2133 if (!AircraftEventHandler(this, i)) return false;
2134 }
2135
2136 return true;
2137}
2138
2139
2147{
2148 assert(v->type == VEH_AIRCRAFT);
2149
2151 if (st == nullptr) return nullptr;
2152
2153 return st->airport.tile == INVALID_TILE ? nullptr : st;
2154}
2155
2161{
2162 /* only 1 station is updated per function call, so it is enough to get entry_point once */
2163 const AirportFTAClass *ap = st->airport.GetFTA();
2164 Direction rotation = st->airport.tile == INVALID_TILE ? DIR_N : st->airport.rotation;
2165
2166 for (Aircraft *v : Aircraft::Iterate()) {
2167 if (!v->IsNormalAircraft() || v->targetairport != st->index) continue;
2168 assert(v->state == FLYING);
2169
2170 Order *o = &v->current_order;
2171 /* The aircraft is heading to a hangar, but the new station doesn't have one,
2172 * or the aircraft can't land on the new station. Cancel current order. */
2173 if (o->IsType(OT_GOTO_DEPOT) && !(o->GetDepotOrderType() & ODTFB_PART_OF_ORDERS) && o->GetDestination() == st->index &&
2174 (!st->airport.HasHangar() || !CanVehicleUseStation(v, st))) {
2175 o->MakeDummy();
2177 }
2178 v->pos = v->previous_pos = AircraftGetEntryPoint(v, ap, rotation);
2180 }
2181
2182 /* Heliports don't have a hangar. Invalidate all go to hangar orders from all aircraft. */
2183 if (!st->airport.HasHangar()) RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, st->index, true);
2184}
Base functions for all AIs.
Base for aircraft.
@ VAF_HELI_DIRECT_DESCENT
The helicopter is descending directly at its destination (helipad or in front of hangar)
Definition aircraft.h:45
@ VAF_DEST_TOO_FAR
Next destination is too far away.
Definition aircraft.h:37
@ VAF_IN_MIN_HEIGHT_CORRECTION
The vehicle is currently raising its altitude because it hit the lower bound.
Definition aircraft.h:43
@ VAF_IN_MAX_HEIGHT_CORRECTION
The vehicle is currently lowering its altitude because it hit the upper bound.
Definition aircraft.h:42
static constexpr int AIRCRAFT_MIN_FLYING_ALTITUDE
Base values for flight levels above ground level for 'normal' flight and holding patterns.
Definition aircraft.h:20
static constexpr int HELICOPTER_HOLD_MAX_FLYING_ALTITUDE
holding flying altitude above tile of helicopters.
Definition aircraft.h:23
static const int ROTOR_Z_OFFSET
Z Offset between helicopter- and rotorsprite.
Definition aircraft.h:48
static constexpr int PLANE_HOLD_MAX_FLYING_ALTITUDE
holding flying altitude above tile of planes.
Definition aircraft.h:22
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
Station * GetTargetAirportIfValid(const Aircraft *v)
Returns aircraft's target station if v->target_airport is a valid station with airport.
@ AIR_AIRCRAFT
an airplane
Definition aircraft.h:30
@ AIR_ROTOR
rotor of an helicopter
Definition aircraft.h:32
@ AIR_SHADOW
shadow of the aircraft
Definition aircraft.h:31
@ AIR_HELICOPTER
an helicopter
Definition aircraft.h:29
static constexpr int AIRCRAFT_MAX_FLYING_ALTITUDE
Maximum flying altitude above tile.
Definition aircraft.h:21
static void HandleAircraftSmoke(Aircraft *v, bool mode)
Handle smoke of broken aircraft.
static void AircraftEventHandler_InHangar(Aircraft *v, const AirportFTAClass *apc)
Handle aircraft movement/decision making in an airport hangar.
static StationID FindNearestHangar(const Aircraft *v)
Find the nearest hangar to v INVALID_STATION is returned, if the company does not have any suitable a...
static uint GetNumTerminals(const AirportFTAClass *apc)
Get the number of terminals at the airport.
void UpdateAirplanesOnNewStation(const Station *st)
Updates the status of the Aircraft heading or in the station.
void AircraftNextAirportPos_and_Order(Aircraft *v)
set the right pos when heading to other airports after takeoff
int GetTileHeightBelowAircraft(const Vehicle *v)
Get the tile height below the aircraft.
void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type)
Get the size of the sprite of an aircraft sprite heading west (used for lists).
static uint8_t AircraftGetEntryPoint(const Aircraft *v, const AirportFTAClass *apc, Direction rotation)
Find the entry point to an airport depending on direction which the airport is being approached from.
static const MovementTerminalMapping _airport_terminal_mapping[]
A list of all valid terminals and their associated blocks.
CommandCost CmdBuildAircraft(DoCommandFlag flags, TileIndex tile, const Engine *e, Vehicle **ret)
Build an aircraft.
static bool AirportHasBlock(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc)
returns true if the road ahead is busy, eg.
static bool AirportSetBlocks(Aircraft *v, const AirportFTA *current_pos, const AirportFTAClass *apc)
"reserve" a block for the plane
Station * GetTargetAirportIfValid(const Aircraft *v)
Returns aircraft's target station if v->target_airport is a valid station with airport.
static void AircraftLandAirplane(Aircraft *v)
Aircraft touched down at the landing strip.
int GetAircraftHoldMaxAltitude(const Aircraft *v)
Gets the maximum 'flight level' for the holding pattern of the aircraft, in pixels 'z_pos' 0,...
static bool FreeTerminal(Aircraft *v, uint8_t i, uint8_t last_terminal)
Find a free terminal or helipad, and if available, assign it.
static constexpr uint16_t SPEED_LIMIT_BROKEN
Maximum speed of an aircraft that is broken.
static void AircraftHandleDestTooFar(Aircraft *v, bool too_far)
Handle the 'dest too far' flag and the corresponding news message for aircraft.
static bool AircraftController(Aircraft *v)
Controls the movement of an aircraft.
void AircraftLeaveHangar(Aircraft *v, Direction exit_dir)
Aircraft is about to leave the hangar.
static bool AirportFindFreeHelipad(Aircraft *v, const AirportFTAClass *apc)
Find a free helipad, and assign it if available.
static constexpr uint16_t SPEED_LIMIT_NONE
No environmental speed limit. Speed limit is type dependent.
static void AircraftEntersTerminal(Aircraft *v)
Aircraft arrives at a terminal.
static void AircraftEventHandler_AtTerminal(Aircraft *v, const AirportFTAClass *apc)
At one of the Airport's Terminals.
void SetAircraftPosition(Aircraft *v, int x, int y, int z)
Set aircraft position.
static int UpdateAircraftSpeed(Aircraft *v, uint speed_limit=SPEED_LIMIT_NONE, bool hard_limit=true)
Sets the new speed for an aircraft.
static void MaybeCrashAirplane(Aircraft *v)
Decide whether aircraft v should crash.
static constexpr uint16_t SPEED_LIMIT_HOLD
Maximum speed of an aircraft that flies the holding pattern.
void GetAircraftFlightLevelBounds(const Vehicle *v, int *min_level, int *max_level)
Get the 'flight level' bounds, in pixels from 'z_pos' 0 for a particular vehicle for normal flight si...
static bool HandleCrashedAircraft(Aircraft *v)
Handle crashed aircraft v.
void UpdateAircraftCache(Aircraft *v, bool update_range)
Update cached values of an aircraft.
HelicopterRotorStates
Helicopter rotor animation states.
static AircraftStateHandler *const _aircraft_state_handlers[]
Array of handler functions for each target of the aircraft.
static void AircraftEventHandler_EnterHangar(Aircraft *v, const AirportFTAClass *apc)
Aircraft arrived in an airport hangar.
static bool AirportFindFreeTerminal(Aircraft *v, const AirportFTAClass *apc)
Find a free terminal, and assign it if available.
void HandleAircraftEnterHangar(Aircraft *v)
Handle Aircraft specific tasks when an Aircraft enters a hangar.
static constexpr uint16_t SPEED_LIMIT_APPROACH
Maximum speed of an aircraft on finals.
static void CrashAirplane(Aircraft *v)
Bring the aircraft in a crashed state, create the explosion animation, and create a news item about t...
static constexpr uint16_t SPEED_LIMIT_TAXI
Special velocities for aircraft.
void AircraftStateHandler(Aircraft *v, const AirportFTAClass *apc)
Signature of the aircraft handler function.
Command definitions related to aircraft.
uint8_t GetVehiclePosOnBuild(TileIndex hangar_tile)
Get the vehicle position when an aircraft is build at the given tile.
Definition airport.cpp:218
const AirportFTAClass * GetAirport(const uint8_t airport_type)
Get the finite state machine of an airport type.
Definition airport.cpp:207
AirportMovingData RotateAirportMovingData(const AirportMovingData *orig, Direction rotation, uint num_tiles_x, uint num_tiles_y)
Rotate the airport moving data to another rotation.
Definition airport.cpp:80
static const uint64_t TERM7_block
Block belonging to terminal 7.
Definition airport.h:115
static const uint64_t TERM4_block
Block belonging to terminal 4.
Definition airport.h:92
static const uint64_t TERM2_block
Block belonging to terminal 2.
Definition airport.h:90
static const uint64_t TERM1_block
Movement Blocks on Airports blocks (eg_airport_flags).
Definition airport.h:89
static const uint64_t TERM5_block
Block belonging to terminal 5.
Definition airport.h:93
static const uint64_t TERM3_block
Block belonging to terminal 3.
Definition airport.h:91
static const uint64_t TERM8_block
Block belonging to terminal 8.
Definition airport.h:116
static const uint MAX_TERMINALS
Some airport-related constants.
Definition airport.h:17
@ AT_DUMMY
Dummy airport.
Definition airport.h:43
@ AT_OILRIG
Oilrig airport.
Definition airport.h:38
@ AMED_BRAKE
Taxiing at the airport.
Definition airport.h:53
@ AMED_HOLD
Holding pattern movement (above the airport).
Definition airport.h:56
@ AMED_SLOWTURN
Turn slowly (mostly used in the air).
Definition airport.h:50
@ AMED_HELI_LOWER
Helicopter landing.
Definition airport.h:55
@ AMED_LAND
Landing onto landing strip.
Definition airport.h:51
@ AMED_NOSPDCLAMP
No speed restrictions.
Definition airport.h:48
@ AMED_TAKEOFF
Takeoff movement.
Definition airport.h:49
@ AMED_EXACTPOS
Go exactly to the destination coordinates.
Definition airport.h:52
@ AMED_HELI_RAISE
Helicopter take-off.
Definition airport.h:54
static const uint64_t AIRPORT_CLOSED_block
Dummy block for indicating a closed airport.
Definition airport.h:128
static const uint64_t HELIPAD2_block
Block belonging to helipad 2.
Definition airport.h:96
static const uint64_t TERM6_block
Block belonging to terminal 6.
Definition airport.h:94
static const uint64_t HELIPAD3_block
Block belonging to helipad 3.
Definition airport.h:117
static const uint64_t HELIPAD1_block
Block belonging to helipad 1.
Definition airport.h:95
AirportMovementStates
Movement States on Airports (headings target)
Definition airport.h:60
@ HELITAKEOFF
Helicopter wants to leave the airport.
Definition airport.h:74
@ TERM4
Heading for terminal 4.
Definition airport.h:66
@ STARTTAKEOFF
Airplane has arrived at a runway for take-off.
Definition airport.h:72
@ HELIPAD2
Heading for helipad 2.
Definition airport.h:70
@ ENDTAKEOFF
Airplane has reached end-point of the take-off runway.
Definition airport.h:73
@ TERM5
Heading for terminal 5.
Definition airport.h:67
@ TERM6
Heading for terminal 6.
Definition airport.h:68
@ TERM3
Heading for terminal 3.
Definition airport.h:65
@ TERM8
Heading for terminal 8.
Definition airport.h:81
@ HELIPAD3
Heading for helipad 3.
Definition airport.h:82
@ HELIPAD1
Heading for helipad 1.
Definition airport.h:69
@ TERM2
Heading for terminal 2.
Definition airport.h:64
@ HANGAR
Heading for hangar.
Definition airport.h:62
@ FLYING
Vehicle is flying in the air.
Definition airport.h:75
@ TAKEOFF
Airplane wants to leave the airport.
Definition airport.h:71
@ HELILANDING
Helicopter wants to land.
Definition airport.h:78
@ TO_ALL
Go in this direction for every target.
Definition airport.h:61
@ ENDLANDING
Airplane wants to finish landing.
Definition airport.h:77
@ HELIENDLANDING
Helicopter wants to finish landing.
Definition airport.h:79
@ TERM1
Heading for terminal 1.
Definition airport.h:63
@ LANDING
Airplane wants to land.
Definition airport.h:76
@ TERM7
Heading for terminal 7.
Definition airport.h:80
@ TERMGROUP
Aircraft is looking for a free terminal in a terminalgroup.
Definition airport.h:84
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
#define CLRBITS(x, y)
Clears several bits in a variable.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
#define SETBITS(x, y)
Sets several bits in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
uint8_t CargoID
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:22
bool IsValidCargoID(CargoID t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:107
Cheats _cheats
All the cheats.
Definition cheat.cpp:16
Types related to cheating.
static void NewEvent(CompanyID company, ScriptEvent *event)
Queue a new event for an AI.
Definition ai_core.cpp:243
Common return value for all commands.
Money GetCost() const
The costs as made up to this moment.
bool Failed() const
Did this command fail?
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
RAII class for measuring multi-step elements of performance.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Date date
Current date in days (day counter).
static Year year
Current year, starting at 0.
static constexpr int DAYS_IN_YEAR
days per year
static Date date
Current date in days (day counter).
uint Truncate(uint max_move=UINT_MAX)
Truncates the cargo in this list to the given amount.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
execute the given command
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
void SubtractMoneyFromCompanyFract(CompanyID company, const CommandCost &cst)
Subtract money from a company, including the money fraction.
Functions related to companies.
@ OWNER_NONE
The tile has no ownership.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
DirDiff DirDifference(Direction d0, Direction d1)
Calculate the difference between two directions.
Direction ChangeDir(Direction d, DirDiff delta)
Change a direction by a given difference.
DiagDirection ChangeDiagDir(DiagDirection d, DiagDirDiff delta)
Applies a difference on a DiagDirection.
DiagDirDiff DiagDirDifference(DiagDirection d0, DiagDirection d1)
Calculate the difference between two DiagDirection values.
DiagDirection DirToDiagDir(Direction dir)
Convert a Direction to a DiagDirection.
Direction
Defines the 8 directions on the map.
@ DIR_N
North.
@ DIR_SE
Southeast.
@ DIR_NE
Northeast.
@ DIR_W
West.
@ DIR_E
East.
DiagDirection
Enumeration for diagonal directions.
@ DIAGDIR_NE
Northeast, upper right on your monitor.
@ DIAGDIR_NW
Northwest.
@ DIAGDIR_SE
Southeast.
@ DIAGDIR_SW
Southwest.
DirDiff
Allow incrementing of Direction variables.
@ DIRDIFF_45LEFT
Angle of 45 degrees left.
@ DIRDIFF_REVERSE
One direction is the opposite of the other one.
@ DIRDIFF_45RIGHT
Angle of 45 degrees right.
@ DIRDIFF_SAME
Both directions faces to the same direction.
All disaster vehicles.
Money GetPrice(Price index, uint cost_factor, const GRFFile *grf_file, int shift)
Determine a certain price.
Definition economy.cpp:966
@ EXPENSES_AIRCRAFT_RUN
Running costs aircraft.
EffectVehicle * CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type)
Create an effect vehicle above a particular vehicle.
Functions related to effect vehicles.
@ EV_EXPLOSION_SMALL
Various explosions.
@ EV_EXPLOSION_LARGE
Various explosions.
@ EV_BREAKDOWN_SMOKE_AIRCRAFT
Smoke of broken aircraft.
Base class for engines.
uint16_t EngineID
Unique identification number of an engine.
Definition engine_type.h:21
@ AIR_CTOL
Conventional Take Off and Landing, i.e. planes.
Definition engine_type.h:95
@ ENGINE_EXCLUSIVE_PREVIEW
This vehicle is in the exclusive preview stage, either being used or being offered to a company.
Error reporting related functions.
fluid_settings_t * settings
FluidSynth settings handle.
Types for recording game performance data.
@ PFE_GL_AIRCRAFT
Time spent processing aircraft.
Base functions for all Games.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:18
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:19
int GetSlopePixelZ(int x, int y, bool ground_vehicle)
Return world Z coordinate of a given point of a tile.
Functions related to OTTD's landscape.
uint DistanceSquare(TileIndex t0, TileIndex t1)
Gets the 'Square' distance between the two given tiles.
Definition map.cpp:163
static debug_inline uint TileY(TileIndex tile)
Get the Y component of a tile.
Definition map_func.h:425
static debug_inline uint TileX(TileIndex tile)
Get the X component of a tile.
Definition map_func.h:415
static debug_inline TileIndex TileVirtXY(uint x, uint y)
Get a tile from the virtual XY-coordinate.
Definition map_func.h:404
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
Definition math_func.hpp:23
constexpr uint CeilDiv(uint a, uint b)
Computes ceil(a / b) for non-negative a and b.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
NewGRF handling of airport tiles.
@ AAT_STATION_AIRPLANE_LAND
Triggered when an airplane (not a helicopter) touches down at the airport (for single tile).
Functions for NewGRF engines.
@ PROP_AIRCRAFT_RANGE
Aircraft range.
@ PROP_AIRCRAFT_RUNNING_COST_FACTOR
Yearly runningcost.
@ PROP_AIRCRAFT_SPEED
Max. speed: 1 unit = 8 mph = 12.8 km-ish/h.
@ PROP_AIRCRAFT_CARGO_AGE_PERIOD
Number of ticks before carried cargo is aged.
bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event, bool force)
Checks whether a NewGRF wants to play a different vehicle sound effect.
Functions related to NewGRF provided sounds.
@ VSE_TOUCHDOWN
Whenever a plane touches down.
@ VSE_START
Vehicle starting, i.e. leaving, the station.
Functions related to news.
void DeleteVehicleNews(VehicleID vid, StringID news)
Delete a news item type about a vehicle.
Definition news_gui.cpp:998
void AddVehicleAdviceNewsItem(StringID string, VehicleID vehicle)
Adds a vehicle-advice news item.
Definition news_func.h:40
void AddVehicleNewsItem(StringID string, NewsType type, VehicleID vehicle, StationID station=INVALID_STATION)
Adds a newsitem referencing a vehicle.
Definition news_func.h:30
NewsType
Type of news.
Definition news_type.h:23
@ NT_ACCIDENT_OTHER
An accident or disaster has occurred.
Definition news_type.h:27
@ NT_ARRIVAL_COMPANY
First vehicle arrived for company.
Definition news_type.h:24
@ NT_ARRIVAL_OTHER
First vehicle arrived for competitor.
Definition news_type.h:25
@ NT_ACCIDENT
An accident or disaster has occurred.
Definition news_type.h:26
bool ProcessOrders(Vehicle *v)
Handle the orders of a vehicle and determine the next place to go to if needed.
void CheckOrders(const Vehicle *v)
Check the orders of a vehicle, to see if there are invalid orders and stuff.
void RemoveOrderFromAllVehicles(OrderType type, DestinationID destination, bool hangar)
Removes an order from all vehicles.
@ ODATFB_NEAREST_DEPOT
Send the vehicle to the nearest depot.
Definition order_type.h:105
@ ODTFB_PART_OF_ORDERS
This depot order is because of a regular order.
Definition order_type.h:96
@ ODTFB_SERVICE
This depot order is because of the servicing limit.
Definition order_type.h:95
Pseudo random number generator.
bool Chance16R(const uint32_t a, const uint32_t b, uint32_t &r, const std::source_location location=std::source_location::current())
Flips a coin with a given probability and saves the randomize-number in a variable.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Functions related to sound.
static const uint ORIGINAL_SAMPLE_COUNT
The number of sounds in the original sample.cat.
Definition sound_type.h:124
@ SND_18_TAKEOFF_HELICOPTER
22 == 0x16 Takeoff: helicopter
Definition sound_type.h:69
@ SND_17_SKID_PLANE
21 == 0x15 Plane landing / touching ground
Definition sound_type.h:68
@ SND_12_EXPLOSION
16 == 0x10 Destruction, crashes, disasters, ...
Definition sound_type.h:63
Functions to cache sprites in memory.
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition sprites.h:1605
Base classes/functions for stations.
StationID GetStationIndex(Tile t)
Get StationID from a tile.
Definition station_map.h:28
@ HVOT_AIRCRAFT
Station has seen an aircraft.
@ FACIL_AIRPORT
Station with an airport.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:280
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
uint32_t cached_max_range_sqr
Cached squared maximum range.
Definition aircraft.h:65
uint16_t cached_max_range
Cached maximum range.
Definition aircraft.h:66
Information about a aircraft vehicle.
uint16_t max_speed
Maximum speed (1 unit = 8 mph = 12.8 km-ish/h)
uint8_t mail_capacity
Mail capacity (bags).
uint8_t subtype
Type of aircraft.
uint16_t passenger_capacity
Passenger capacity (persons).
uint16_t max_range
Maximum range of this aircraft.
Aircraft, helicopters, rotors and their shadows belong to this class.
Definition aircraft.h:72
bool Tick() override
Calls the tick handler of the vehicle.
uint8_t pos
Next desired position of the aircraft.
Definition aircraft.h:74
uint8_t state
State of the airport.
Definition aircraft.h:77
uint8_t flags
Aircraft flags.
Definition aircraft.h:81
Money GetRunningCost() const override
Gets the running cost of a vehicle.
void UpdateDeltaXY() override
Updates the x and y offsets and the size of the sprite used for this vehicle.
uint8_t number_consecutive_turns
Protection to prevent the aircraft of making a lot of turns in order to reach a specific point.
Definition aircraft.h:79
void OnNewEconomyDay() override
Economy day handler.
uint Crash(bool flooded=false) override
Crash the (whole) vehicle chain.
void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const override
Gets the sprite to show for the given direction.
void OnNewCalendarDay() override
Calendar day handler.
uint8_t turn_counter
Ticks between each turn to prevent > 45 degree turns.
Definition aircraft.h:80
TileIndex GetOrderStationLocation(StationID station) override
Determine the location for the station where the vehicle goes to next.
bool IsNormalAircraft() const
Check if the aircraft type is a normal flying device; eg not a rotor or a shadow.
Definition aircraft.h:121
void MarkDirty() override
Marks the vehicles to be redrawn and updates cached variables.
uint8_t previous_pos
Previous desired position of the aircraft.
Definition aircraft.h:75
StationID targetairport
Airport to go to next.
Definition aircraft.h:76
ClosestDepot FindClosestDepot() override
Find the closest depot for this vehicle and tell us the location, DestinationID and whether we should...
uint16_t crashed_counter
Timer for handling crash animations.
Definition aircraft.h:73
Finite sTate mAchine (FTA) of an airport.
Definition airport.h:143
struct AirportFTA * layout
state machine for airport
Definition airport.h:177
const uint8_t num_helipads
Number of helipads on this airport. When 0 helicopters will go to normal terminals.
Definition airport.h:179
const AirportMovingData * MovingData(uint8_t position) const
Get movement data at a position.
Definition airport.h:170
uint8_t delta_z
Z adjustment for helicopter pads.
Definition airport.h:183
const uint8_t * terminals
Array with the number of terminal groups, followed by the number of terminals in each group.
Definition airport.h:178
const uint8_t * entry_points
when an airplane arrives at this airport, enter it at position entry_point, index depends on directio...
Definition airport.h:182
uint8_t nofelements
number of positions the airport consists of
Definition airport.h:181
Flags flags
Flags for this airport type.
Definition airport.h:180
@ AIRPLANES
Can planes land on this airport type?
Definition airport.h:147
@ SHORT_STRIP
This airport has a short landing strip, dangerous for fast aircraft.
Definition airport.h:150
Internal structure used in openttd - Finite sTate mAchine --> FTA.
Definition airport.h:190
AirportFTA * next
possible extra movement choices from this position
Definition airport.h:191
uint8_t heading
heading (current orders), guiding an airplane to its target on an airport
Definition airport.h:195
uint64_t block
64 bit blocks (st->airport.flags), should be enough for the most complex airports
Definition airport.h:192
uint8_t position
the position that an airplane is at
Definition airport.h:193
uint8_t next_position
next position from this position
Definition airport.h:194
A single location on an airport where aircraft can move to.
Definition airport.h:131
uint16_t flag
special flags when moving towards the destination.
Definition airport.h:134
int16_t x
x-coordinate of the destination.
Definition airport.h:132
int16_t y
y-coordinate of the destination.
Definition airport.h:133
Direction direction
Direction to turn the aircraft after reaching the destination.
Definition airport.h:135
bool HasHangar() const
Check if this airport has at least one hangar.
uint GetHangarNum(TileIndex tile) const
Get the hangar number of the hangar at a specific tile.
Direction rotation
How this airport is rotated.
uint8_t type
Type of this airport,.
Direction GetHangarExitDirection(TileIndex tile) const
Get the exit direction of the hangar at a specific tile.
uint64_t flags
stores which blocks on the airport are taken. was 16 bit earlier on, then 32
const AirportFTAClass * GetFTA() const
Get the finite-state machine for this airport or the finite-state machine for the dummy airport in ca...
TileIndex GetHangarTile(uint hangar_num) const
Get the first tile of the given hangar.
Class to backup a specific variable and restore it later.
std::string name
Name of vehicle.
TimerGameTick::Ticks current_order_time
How many ticks have passed since this order started.
uint16_t vehicle_flags
Used for gradual loading and other miscellaneous things (.
TileIndex xy
Base tile of the station.
Owner owner
The owner of this station.
static BaseStation * GetByTile(TileIndex tile)
Get the base station belonging to a specific tile.
VehicleType type
Type of vehicle.
bool value
tells if the bool cheat is active or not
Definition cheat_type.h:18
Cheat no_jetcrash
no jet will crash on small airports anymore
Definition cheat_type.h:31
SoundSettings sound
sound effect settings
Structure to return information about the closest depot location, and whether it could be found.
Disasters, like submarines, skyrangers and their shadows, belong to this class.
uint16_t cargo_age_period
Number of ticks before carried cargo is aged.
CargoID GetDefaultCargoType() const
Determines the default cargo type of an engine.
uint16_t reliability_spd_dec
Speed of reliability decay between services (per day).
Definition engine_base.h:48
const GRFFile * GetGRF() const
Retrieve the NewGRF the engine is tied to.
uint DetermineCapacity(const Vehicle *v, uint16_t *mail_capacity=nullptr) const
Determines capacity of a given vehicle from scratch.
Definition engine.cpp:201
uint8_t original_image_index
Original vehicle image index, thus the image index of the overridden vehicle.
Definition engine_base.h:59
TimerGameCalendar::Date GetLifeLengthInDays() const
Returns the vehicle's (not model's!) life length in days.
Definition engine.cpp:443
uint16_t reliability
Current reliability of the engine.
Definition engine_base.h:47
uint8_t flags
Flags of the engine.
Definition engine_base.h:55
VehicleSettings vehicle
options for vehicles
OrderSettings order
settings related to orders
Position information of a vehicle after it moved.
TileIndex new_tile
Tile of the vehicle after moving.
int y
x and y position of the vehicle after moving
TileIndex old_tile
Current tile of the vehicle.
Stores station stats for a single cargo.
static uint MaxY()
Gets the maximum Y coordinate within the map, including MP_VOID.
Definition map_func.h:306
static debug_inline uint MaxX()
Gets the maximum X coordinate within the map, including MP_VOID.
Definition map_func.h:297
Combination of aircraft state for going to a certain terminal and the airport flag for that terminal ...
uint64_t airport_flag
Bitmask in the airport flags that need to be free for this terminal.
AirportMovementStates state
Aircraft movement state when going to this terminal.
VehicleSpriteSeq sprite_seq
Vehicle appearance.
bool serviceathelipad
service helicopters at helipads automatically (no need to send to depot)
OrderDepotTypeFlags GetDepotOrderType() const
What caused us going to the depot?
Definition order_base.h:144
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
OrderType GetType() const
Get the type of order of this order.
Definition order_base.h:76
void MakeDummy()
Makes this order a Dummy order.
void MakeGoToDepot(DepotID destination, OrderDepotTypeFlags order, OrderNonStopFlags non_stop_type=ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS, OrderDepotActionFlags action=ODATF_SERVICE_ONLY, CargoID cargo=CARGO_NO_REFIT)
Makes this order a Go To Depot order.
Definition order_cmd.cpp:90
OrderDepotActionFlags GetDepotActionType() const
What are we going to do when in the depot.
Definition order_base.h:146
void Free()
'Free' the order
Definition order_cmd.cpp:63
uint16_t w
The width of the area.
TileIndex tile
The base tile of the area.
uint16_t h
The height of the area.
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(size_t index)
Returns Titem with given index.
Specification of a rectangle with absolute coordinates of all edges.
int Width() const
Get width of Rect.
int Height() const
Get height of Rect.
Titem value
Value of current item.
bool disaster
Play disaster and accident sounds.
static Pool::IterateWrapper< Station > Iterate(size_t from=0)
Returns an iterable ensemble of all valid stations of type T.
static Station * Get(size_t index)
Gets station with given index.
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
T * Next() const
Get next vehicle in the chain.
static Aircraft * From(Vehicle *v)
Converts a Vehicle to SpecializedVehicle with type checking.
void UpdateViewport(bool force_update, bool update_delta)
Update vehicle sprite- and position caches.
Station data structure.
GoodsEntry goods[NUM_CARGO]
Goods at this station.
Airport airport
Tile area the airport covers.
uint16_t cached_cargo_age_period
Number of ticks before carried cargo is aged.
uint16_t cached_max_speed
Maximum speed of the consist (minimum of the max speed of all vehicles in the consist).
uint8_t plane_crashes
number of plane crashes, 0 = none, 1 = reduced, 2 = normal
uint8_t plane_speed
divisor for speed of aircraft
Sprite sequence for a vehicle part.
bool IsValid() const
Check whether the sequence contains any sprites.
void GetBounds(Rect *bounds) const
Determine shared bounds of all sprites.
Definition vehicle.cpp:103
void Set(SpriteID sprite)
Assign a single sprite to the sequence.
void CopyWithoutPalette(const VehicleSpriteSeq &src)
Copy data from another sprite sequence, while dropping all recolouring information.
void Draw(int x, int y, PaletteID default_pal, bool force_pal) const
Draw the sprite sequence.
Definition vehicle.cpp:131
Vehicle data structure.
EngineID engine_type
The type of engine used for this vehicle.
int32_t z_pos
z coordinate.
Direction direction
facing
StationIDStack GetNextStoppingStation() const
Get the next station the vehicle will stop at.
const Engine * GetEngine() const
Retrieves the engine of the vehicle.
Definition vehicle.cpp:747
virtual uint Crash(bool flooded=false)
Crash the (whole) vehicle chain.
Definition vehicle.cpp:280
virtual bool IsChainInDepot() const
Check whether the whole vehicle chain is in the depot.
VehicleCargoList cargo
The cargo this vehicle is carrying.
uint8_t x_extent
x-extent of vehicle bounding box
TimerGameEconomy::Date date_of_last_service
Last economy date the vehicle had a service at a depot.
uint16_t cargo_cap
total capacity
StationID last_loading_station
Last station the vehicle has stopped at and could possibly leave from with any cargo loaded.
uint8_t subtype
subtype (Filled with values from AircraftSubType/DisasterSubType/EffectVehicleType/GroundVehicleSubty...
uint16_t random_bits
Bits used for randomized variational spritegroups.
uint8_t day_counter
Increased by one for each day.
void HandleLoading(bool mode=false)
Handle the loading of the vehicle; when not it skips through dummy orders and does nothing in all oth...
Definition vehicle.cpp:2430
Money profit_this_year
Profit this year << 8, low 8 bits are fract.
SpriteID colourmap
NOSAVE: cached colour mapping.
uint8_t breakdown_ctr
Counter for managing breakdown events.
uint GetOldAdvanceSpeed(uint speed)
Determines the effective direction-specific vehicle movement speed.
uint8_t z_extent
z-extent of vehicle bounding box
TimerGameCalendar::Date date_of_last_service_newgrf
Last calendar date the vehicle had a service at a depot, unchanged by the date cheat to protect again...
uint8_t subspeed
fractional speed
void LeaveUnbunchingDepot()
Leave an unbunching depot and calculate the next departure time for shared order vehicles.
Definition vehicle.cpp:2514
int8_t y_offs
y offset for vehicle sprite
uint8_t acceleration
used by train & aircraft
Order current_order
The current order (+ status, like: loading)
CargoID cargo_type
type of cargo this vehicle is carrying
Vehicle * Next() const
Get the next vehicle of this vehicle.
int8_t x_offs
x offset for vehicle sprite
int32_t y_pos
y coordinate.
int32_t x_pos
x coordinate.
uint8_t y_extent
y-extent of vehicle bounding box
uint16_t refit_cap
Capacity left over from before last refit.
uint8_t vehstatus
Status.
VehicleCache vcache
Cache of often used vehicle values.
void BeginLoading()
Prepare everything to begin the loading when arriving at a station.
Definition vehicle.cpp:2203
uint8_t spritenum
currently displayed sprite index 0xfd == custom sprite, 0xfe == custom second head sprite 0xff == res...
uint16_t cur_speed
current speed
bool IsWaitingForUnbunching() const
Check whether a vehicle inside a depot is waiting for unbunching.
Definition vehicle.cpp:2561
void SetNext(Vehicle *next)
Set the next vehicle of this vehicle.
Definition vehicle.cpp:2937
uint8_t breakdowns_since_last_service
Counter for the amount of breakdowns.
TimerGameCalendar::Date max_age
Maximum age.
MutableSpriteCache sprite_cache
Cache of sprites and values related to recalculating them, see MutableSpriteCache.
uint16_t reliability
Reliability.
bool HandleBreakdown()
Handle all of the aspects of a vehicle breakdown This includes adding smoke and sounds,...
Definition vehicle.cpp:1363
uint8_t progress
The percentage (if divided by 256) this vehicle already crossed the tile unit.
void UpdatePositionAndViewport()
Update the position of the vehicle, and update the viewport.
Definition vehicle.cpp:1764
uint16_t reliability_spd_dec
Reliability decrease speed.
uint8_t tick_counter
Increased by one for each tick.
TileIndex tile
Current tile index.
void UpdatePosition()
Update the position of the vehicle.
Definition vehicle.cpp:1693
StationID last_station_visited
The last station we stopped at.
void InvalidateNewGRFCacheOfChain()
Invalidates cached NewGRF variables of all vehicles in the chain (after the current vehicle)
TimerGameCalendar::Year build_year
Year the vehicle has been built.
Owner owner
Which company owns the vehicle?
bool NeedsAutomaticServicing() const
Checks if the current order should be interrupted for a service-in-depot order.
Definition vehicle.cpp:272
uint8_t running_ticks
Number of ticks this vehicle was not stopped this day.
int GetTileMaxPixelZ(TileIndex tile)
Get top height of the tile.
Definition tile_map.h:312
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
static const uint TILE_HEIGHT
Height of a height level in world coordinate AND in pixels in ZOOM_BASE.
Definition tile_type.h:18
static const uint TILE_SIZE
Tile size in world coordinates.
Definition tile_type.h:15
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
Definition of the game-calendar-timer.
Definition of the game-economy-timer.
void VehicleEnterDepot(Vehicle *v)
Vehicle entirely entered the depot, update its status, orders, vehicle windows, service it,...
Definition vehicle.cpp:1552
void VehicleServiceInDepot(Vehicle *v)
Service a vehicle and all subsequent vehicles in the consist.
Definition vehicle.cpp:167
GetNewVehiclePosResult GetNewVehiclePos(const Vehicle *v)
Get position information of a vehicle when moving one pixel in the direction it is facing.
Definition vehicle.cpp:1784
void DecreaseVehicleValue(Vehicle *v)
Decrease the value of a vehicle.
Definition vehicle.cpp:1301
void EconomyAgeVehicle(Vehicle *v)
Update economy age of a vehicle.
Definition vehicle.cpp:1429
bool CanVehicleUseStation(EngineID engine_type, const Station *st)
Can this station be used by the given engine type?
Definition vehicle.cpp:3058
void AgeVehicle(Vehicle *v)
Update age of a vehicle.
Definition vehicle.cpp:1441
@ VF_BUILT_AS_PROTOTYPE
Vehicle is a prototype (accepted as exclusive preview).
@ VS_UNCLICKABLE
Vehicle is not clickable by the user (shadow vehicles).
@ VS_AIRCRAFT_BROKEN
Aircraft is broken down.
@ VS_SHADOW
Vehicle is a shadow vehicle.
@ VS_STOPPED
Vehicle is stopped by the player.
@ VS_HIDDEN
Vehicle is not visible.
@ VS_CRASHED
Vehicle is crashed.
@ VS_DEFPAL
Use default vehicle palette.
Command definitions for vehicles.
Functions related to vehicles.
EngineImageType
Visualisation contexts of vehicles and engines.
@ EIT_ON_MAP
Vehicle drawn in viewport.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ LocateHangar
Find another airport if the target one lacks a hangar.
@ None
No special flags.
@ Service
The vehicle will leave the depot right after arrival (service only)
@ WID_VV_START_STOP
Start or stop this vehicle, and show information about the current state.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3127
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition window.cpp:3219
void SetWindowWidgetDirty(WindowClass cls, WindowNumber number, WidgetID widget_index)
Mark a particular widget in a particular window as dirty (in need of repainting)
Definition window.cpp:3114
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3101
Window functions not directly related to making/drawing windows.
@ WC_VEHICLE_DEPOT
Depot view; Window numbers:
@ WC_VEHICLE_DETAILS
Vehicle details; Window numbers:
@ WC_VEHICLE_VIEW
Vehicle view; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers:
Functions related to zooming.
int ScaleSpriteTrad(int value)
Scale traditional pixel dimensions to GUI zoom level, for drawing sprites.
Definition zoom_func.h:107
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition zoom_func.h:77