summaryrefslogtreecommitdiff
path: root/src/airport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/airport.cpp')
-rw-r--r--src/airport.cpp489
1 files changed, 489 insertions, 0 deletions
diff --git a/src/airport.cpp b/src/airport.cpp
new file mode 100644
index 000000000..2135bd11b
--- /dev/null
+++ b/src/airport.cpp
@@ -0,0 +1,489 @@
+/* $Id$ */
+
+#include "stdafx.h"
+#include "openttd.h"
+#include "debug.h"
+#include "map.h"
+#include "airport.h"
+#include "macros.h"
+#include "variables.h"
+#include "airport_movement.h"
+#include "date.h"
+
+/* Uncomment this to print out a full report of the airport-structure
+ * You should either use
+ * - true: full-report, print out every state and choice with string-names
+ * OR
+ * - false: give a summarized report which only shows current and next position */
+//#define DEBUG_AIRPORT false
+
+static AirportFTAClass *CountryAirport;
+static AirportFTAClass *CityAirport;
+static AirportFTAClass *Oilrig;
+static AirportFTAClass *Heliport;
+static AirportFTAClass *MetropolitanAirport;
+static AirportFTAClass *InternationalAirport;
+static AirportFTAClass *CommuterAirport;
+static AirportFTAClass *HeliDepot;
+static AirportFTAClass *IntercontinentalAirport;
+static AirportFTAClass *HeliStation;
+
+static void AirportFTAClass_Constructor(AirportFTAClass *apc,
+ const byte *terminals, const byte *helipads,
+ const byte entry_point, const byte acc_planes,
+ const AirportFTAbuildup *apFA,
+ const TileIndexDiffC *depots, const byte nof_depots,
+ uint size_x, uint size_y
+);
+static void AirportFTAClass_Destructor(AirportFTAClass *apc);
+
+static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
+static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA);
+static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
+static byte AirportTestFTA(const AirportFTAClass *apc);
+
+#ifdef DEBUG_AIRPORT
+static void AirportPrintOut(const AirportFTAClass *apc, bool full_report);
+#endif /* DEBUG_AIRPORT */
+
+void InitializeAirports(void)
+{
+ // country airport
+ CountryAirport = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ CountryAirport,
+ _airport_terminal_country,
+ NULL,
+ 16,
+ ALL,
+ _airport_fta_country,
+ _airport_depots_country,
+ lengthof(_airport_depots_country),
+ 4, 3
+ );
+
+ // city airport
+ CityAirport = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ CityAirport,
+ _airport_terminal_city,
+ NULL,
+ 19,
+ ALL,
+ _airport_fta_city,
+ _airport_depots_city,
+ lengthof(_airport_depots_city),
+ 6, 6
+ );
+
+ // metropolitan airport
+ MetropolitanAirport = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ MetropolitanAirport,
+ _airport_terminal_metropolitan,
+ NULL,
+ 20,
+ ALL,
+ _airport_fta_metropolitan,
+ _airport_depots_metropolitan,
+ lengthof(_airport_depots_metropolitan),
+ 6, 6
+ );
+
+ // international airport
+ InternationalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ InternationalAirport,
+ _airport_terminal_international,
+ _airport_helipad_international,
+ 37,
+ ALL,
+ _airport_fta_international,
+ _airport_depots_international,
+ lengthof(_airport_depots_international),
+ 7, 7
+ );
+
+ // intercontintental airport
+ IntercontinentalAirport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ IntercontinentalAirport,
+ _airport_terminal_intercontinental,
+ _airport_helipad_intercontinental,
+ 43,
+ ALL,
+ _airport_fta_intercontinental,
+ _airport_depots_intercontinental,
+ lengthof(_airport_depots_intercontinental),
+ 9,11
+ );
+
+ // heliport, oilrig
+ Heliport = (AirportFTAClass *)malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ Heliport,
+ NULL,
+ _airport_helipad_heliport_oilrig,
+ 7,
+ HELICOPTERS_ONLY,
+ _airport_fta_heliport_oilrig,
+ NULL,
+ 0,
+ 1, 1
+ );
+
+ Oilrig = Heliport; // exactly the same structure for heliport/oilrig, so share state machine
+
+ // commuter airport
+ CommuterAirport = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ CommuterAirport,
+ _airport_terminal_commuter,
+ _airport_helipad_commuter,
+ 22,
+ ALL,
+ _airport_fta_commuter,
+ _airport_depots_commuter,
+ lengthof(_airport_depots_commuter),
+ 5,4
+ );
+
+ // helidepot airport
+ HeliDepot = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ HeliDepot,
+ NULL,
+ _airport_helipad_helidepot,
+ 4,
+ HELICOPTERS_ONLY,
+ _airport_fta_helidepot,
+ _airport_depots_helidepot,
+ lengthof(_airport_depots_helidepot),
+ 2,2
+ );
+
+ // helistation airport
+ HeliStation = malloc(sizeof(AirportFTAClass));
+
+ AirportFTAClass_Constructor(
+ HeliStation,
+ NULL,
+ _airport_helipad_helistation,
+ 25,
+ HELICOPTERS_ONLY,
+ _airport_fta_helistation,
+ _airport_depots_helistation,
+ lengthof(_airport_depots_helistation),
+ 4,2
+ );
+
+}
+
+void UnInitializeAirports(void)
+{
+ AirportFTAClass_Destructor(CountryAirport);
+ AirportFTAClass_Destructor(CityAirport);
+ AirportFTAClass_Destructor(Heliport);
+ AirportFTAClass_Destructor(MetropolitanAirport);
+ AirportFTAClass_Destructor(InternationalAirport);
+ AirportFTAClass_Destructor(CommuterAirport);
+ AirportFTAClass_Destructor(HeliDepot);
+ AirportFTAClass_Destructor(IntercontinentalAirport);
+ AirportFTAClass_Destructor(HeliStation);
+}
+
+static void AirportFTAClass_Constructor(AirportFTAClass *apc,
+ const byte *terminals, const byte *helipads,
+ const byte entry_point, const byte acc_planes,
+ const AirportFTAbuildup *apFA,
+ const TileIndexDiffC *depots, const byte nof_depots,
+ uint size_x, uint size_y
+)
+{
+ byte nofterminals, nofhelipads;
+ byte nofterminalgroups, nofhelipadgroups;
+
+ apc->size_x = size_x;
+ apc->size_y = size_y;
+
+ /* Set up the terminal and helipad count for an airport.
+ * TODO: If there are more than 10 terminals or 4 helipads, internal variables
+ * need to be changed, so don't allow that for now */
+ nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
+ if (nofterminals > MAX_TERMINALS) {
+ DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
+ assert(nofterminals <= MAX_TERMINALS);
+ }
+ apc->terminals = terminals;
+
+ nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
+ if (nofhelipads > MAX_HELIPADS) {
+ DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
+ assert(nofhelipads <= MAX_HELIPADS);
+ }
+ apc->helipads = helipads;
+
+ /* Get the number of elements from the source table. We also double check this
+ * with the entry point which must be within bounds and use this information
+ * later on to build and validate the state machine */
+ apc->nofelements = AirportGetNofElements(apFA);
+ if (entry_point >= apc->nofelements) {
+ DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_point, apc->nofelements);
+ assert(entry_point < apc->nofelements);
+ }
+
+ apc->acc_planes = acc_planes;
+ apc->entry_point = entry_point;
+ apc->airport_depots = depots;
+ apc->nof_depots = nof_depots;
+
+ /* Build the state machine itself */
+ AirportBuildAutomata(apc, apFA);
+ DEBUG(misc, 2, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entry %3d",
+ apc->nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups, apc->entry_point);
+
+ /* Test if everything went allright. This is only a rude static test checking
+ * the symantic correctness. By no means does passing the test mean that the
+ * airport is working correctly or will not deadlock for example */
+ { byte ret = AirportTestFTA(apc);
+ if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
+ assert(ret == MAX_ELEMENTS);
+ }
+
+#ifdef DEBUG_AIRPORT
+ AirportPrintOut(apc, DEBUG_AIRPORT);
+#endif
+}
+
+static void AirportFTAClass_Destructor(AirportFTAClass *apc)
+{
+ int i;
+ AirportFTA *current, *next;
+
+ for (i = 0; i < apc->nofelements; i++) {
+ current = apc->layout[i].next;
+ while (current != NULL) {
+ next = current->next;
+ free(current);
+ current = next;
+ };
+ }
+ free(apc->layout);
+ free(apc);
+}
+
+/** Get the number of elements of a source Airport state automata
+ * Since it is actually just a big array of AirportFTA types, we only
+ * know one element from the other by differing 'position' identifiers */
+static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
+{
+ int i;
+ uint16 nofelements = 0;
+ int temp = apFA[0].position;
+
+ for (i = 0; i < MAX_ELEMENTS; i++) {
+ if (temp != apFA[i].position) {
+ nofelements++;
+ temp = apFA[i].position;
+ }
+ if (apFA[i].position == MAX_ELEMENTS) break;
+ }
+ return nofelements;
+}
+
+/* We calculate the terminal/helipod count based on the data passed to us
+ * This data (terminals) contains an index as a first element as to how many
+ * groups there are, and then the number of terminals for each group */
+static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
+{
+ byte i;
+ byte nof_terminals = 0;
+ *groups = 0;
+
+ if (terminals != NULL) {
+ i = terminals[0];
+ *groups = i;
+ while (i-- > 0) {
+ terminals++;
+ assert(*terminals != 0); // no empty groups please
+ nof_terminals += *terminals;
+ }
+ }
+ return nof_terminals;
+}
+
+static void AirportBuildAutomata(AirportFTAClass *apc, const AirportFTAbuildup *apFA)
+{
+ AirportFTA *current;
+ AirportFTA *FAutomata = malloc(sizeof(AirportFTA) * apc->nofelements);
+ uint16 internalcounter = 0;
+ uint16 i;
+
+ apc->layout = FAutomata;
+ for (i = 0; i < apc->nofelements; i++) {
+ current = &apc->layout[i];
+ current->position = apFA[internalcounter].position;
+ current->heading = apFA[internalcounter].heading;
+ current->block = apFA[internalcounter].block;
+ current->next_position = apFA[internalcounter].next;
+
+ // outgoing nodes from the same position, create linked list
+ while (current->position == apFA[internalcounter + 1].position) {
+ AirportFTA *newNode = malloc(sizeof(AirportFTA));
+
+ newNode->position = apFA[internalcounter + 1].position;
+ newNode->heading = apFA[internalcounter + 1].heading;
+ newNode->block = apFA[internalcounter + 1].block;
+ newNode->next_position = apFA[internalcounter + 1].next;
+ // create link
+ current->next = newNode;
+ current = current->next;
+ internalcounter++;
+ } // while
+ current->next = NULL;
+ internalcounter++;
+ }
+}
+
+static byte AirportTestFTA(const AirportFTAClass *apc)
+{
+ byte position, i, next_position;
+ AirportFTA *current, *first;
+ next_position = 0;
+
+ for (i = 0; i < apc->nofelements; i++) {
+ position = apc->layout[i].position;
+ if (position != next_position) return i;
+ current = first = &apc->layout[i];
+
+ for (; current != NULL; current = current->next) {
+ /* A heading must always be valid. The only exceptions are
+ * - multiple choices as start, identified by a special value of 255
+ * - terminal group which is identified by a special value of 255 */
+ if (current->heading > MAX_HEADINGS) {
+ if (current->heading != 255) return i;
+ if (current == first && current->next == NULL) return i;
+ if (current != first && current->next_position > apc->terminals[0]) return i;
+ }
+
+ /* If there is only one choice, it must be at the end */
+ if (current->heading == 0 && current->next != NULL) return i;
+ /* Obviously the elements of the linked list must have the same identifier */
+ if (position != current->position) return i;
+ /* A next position must be within bounds */
+ if (current->next_position >= apc->nofelements) return i;
+ }
+ next_position++;
+ }
+ return MAX_ELEMENTS;
+}
+
+#ifdef DEBUG_AIRPORT
+static const char* const _airport_heading_strings[] = {
+ "TO_ALL",
+ "HANGAR",
+ "TERM1",
+ "TERM2",
+ "TERM3",
+ "TERM4",
+ "TERM5",
+ "TERM6",
+ "HELIPAD1",
+ "HELIPAD2",
+ "TAKEOFF",
+ "STARTTAKEOFF",
+ "ENDTAKEOFF",
+ "HELITAKEOFF",
+ "FLYING",
+ "LANDING",
+ "ENDLANDING",
+ "HELILANDING",
+ "HELIENDLANDING",
+ "TERM7",
+ "TERM8",
+ "HELIPAD3",
+ "HELIPAD4",
+ "DUMMY" // extra heading for 255
+};
+
+static uint AirportBlockToString(uint32 block)
+{
+ uint i = 0;
+ if (block & 0xffff0000) { block >>= 16; i += 16; }
+ if (block & 0x0000ff00) { block >>= 8; i += 8; }
+ if (block & 0x000000f0) { block >>= 4; i += 4; }
+ if (block & 0x0000000c) { block >>= 2; i += 2; }
+ if (block & 0x00000002) { i += 1; }
+ return i;
+}
+
+static void AirportPrintOut(const AirportFTAClass *apc, bool full_report)
+{
+ uint16 i;
+
+ if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
+
+ for (i = 0; i < apc->nofelements; i++) {
+ AirportFTA *current = &apc->layout[i];
+
+ for (; current != NULL; current = current->next) {
+ if (full_report) {
+ byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
+ printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
+ current->next_position, _airport_heading_strings[heading],
+ AirportBlockToString(current->block));
+ } else {
+ printf("P:%2d NP:%2d", current->position, current->next_position);
+ }
+ }
+ printf("\n");
+ }
+}
+#endif
+
+const AirportFTAClass *GetAirport(const byte airport_type)
+{
+ //FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
+ // needs constant change if more airports are added
+ switch (airport_type) {
+ default: NOT_REACHED();
+ case AT_SMALL: return CountryAirport;
+ case AT_LARGE: return CityAirport;
+ case AT_METROPOLITAN: return MetropolitanAirport;
+ case AT_HELIPORT: return Heliport;
+ case AT_OILRIG: return Oilrig;
+ case AT_INTERNATIONAL: return InternationalAirport;
+ case AT_COMMUTER: return CommuterAirport;
+ case AT_HELIDEPOT: return HeliDepot;
+ case AT_INTERCON: return IntercontinentalAirport;
+ case AT_HELISTATION: return HeliStation;
+ }
+}
+
+const AirportMovingData *GetAirportMovingData(byte airport_type, byte position)
+{
+ assert(airport_type < lengthof(_airport_moving_datas));
+ assert(position < GetAirport(airport_type)->nofelements);
+ return &_airport_moving_datas[airport_type][position];
+}
+
+uint32 GetValidAirports(void)
+{
+ uint32 bytemask = _avail_aircraft; /// sets the first 3 bytes, 0 - 2, @see AdjustAvailAircraft()
+
+ if (_cur_year >= 1980) SETBIT(bytemask, 3); // metropolitan airport
+ if (_cur_year >= 1990) SETBIT(bytemask, 4); // international airport
+ if (_cur_year >= 1983) SETBIT(bytemask, 5); // commuter airport
+ if (_cur_year >= 1976) SETBIT(bytemask, 6); // helidepot
+ if (_cur_year >= 2002) SETBIT(bytemask, 7); // intercontinental airport
+ if (_cur_year >= 1980) SETBIT(bytemask, 8); // helistation
+ return bytemask;
+}