# airport.cpp

Go to the documentation of this file.

    00001 /* $Id: airport.cpp 11834 2008-01-13 14:37:30Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "debug.h"
    00008 #include "airport.h"
    00009 #include "airport_movement.h"
    00010 #include "core/bitmath_func.hpp"
    00011 #include "core/alloc_func.hpp"
    00012 #include "date_func.h"
    00013 #include "settings_type.h"
    00014
    00015 /* Uncomment this to print out a full report of the airport-structure
    00016  * You should either use
    00017  * - true: full-report, print out every state and choice with string-names
    00018  * OR
    00019  * - false: give a summarized report which only shows current and next position */
    00020 //#define DEBUG_AIRPORT false
    00021
    00022 static AirportFTAClass *DummyAirport;
    00023 static AirportFTAClass *CountryAirport;
    00024 static AirportFTAClass *CityAirport;
    00025 static AirportFTAClass *Oilrig;
    00026 static AirportFTAClass *Heliport;
    00027 static AirportFTAClass *MetropolitanAirport;
    00028 static AirportFTAClass *InternationalAirport;
    00029 static AirportFTAClass *CommuterAirport;
    00030 static AirportFTAClass *HeliDepot;
    00031 static AirportFTAClass *IntercontinentalAirport;
    00032 static AirportFTAClass *HeliStation;
    00033
    00034
    00035 void InitializeAirports()
    00036 {
    00037   DummyAirport = new AirportFTAClass(
    00038     _airport_moving_data_dummy,
    00039     NULL,
    00040     NULL,
    00041     _airport_entries_dummy,
    00042     AirportFTAClass::ALL,
    00043     _airport_fta_dummy,
    00044     NULL,
    00045     0,
    00046     0, 0,
    00047     0,
    00048     0
    00049   );
    00050
    00051   CountryAirport = new AirportFTAClass(
    00052     _airport_moving_data_country,
    00053     _airport_terminal_country,
    00054     NULL,
    00055     _airport_entries_country,
    00056     AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
    00057     _airport_fta_country,
    00058     _airport_depots_country,
    00059     lengthof(_airport_depots_country),
    00060     4, 3,
    00061     0,
    00062     4
    00063   );
    00064
    00065   CityAirport = new AirportFTAClass(
    00066     _airport_moving_data_town,
    00067     _airport_terminal_city,
    00068     NULL,
    00069     _airport_entries_city,
    00070     AirportFTAClass::ALL,
    00071     _airport_fta_city,
    00072     _airport_depots_city,
    00073     lengthof(_airport_depots_city),
    00074     6, 6,
    00075     0,
    00076     5
    00077   );
    00078
    00079   MetropolitanAirport = new AirportFTAClass(
    00080     _airport_moving_data_metropolitan,
    00081     _airport_terminal_metropolitan,
    00082     NULL,
    00083     _airport_entries_metropolitan,
    00084     AirportFTAClass::ALL,
    00085     _airport_fta_metropolitan,
    00086     _airport_depots_metropolitan,
    00087     lengthof(_airport_depots_metropolitan),
    00088     6, 6,
    00089     0,
    00090     6
    00091   );
    00092
    00093   InternationalAirport = new AirportFTAClass(
    00094     _airport_moving_data_international,
    00095     _airport_terminal_international,
    00096     _airport_helipad_international,
    00097     _airport_entries_international,
    00098     AirportFTAClass::ALL,
    00099     _airport_fta_international,
    00100     _airport_depots_international,
    00101     lengthof(_airport_depots_international),
    00102     7, 7,
    00103     0,
    00104     8
    00105   );
    00106
    00107   IntercontinentalAirport = new AirportFTAClass(
    00108     _airport_moving_data_intercontinental,
    00109     _airport_terminal_intercontinental,
    00110     _airport_helipad_intercontinental,
    00111     _airport_entries_intercontinental,
    00112     AirportFTAClass::ALL,
    00113     _airport_fta_intercontinental,
    00114     _airport_depots_intercontinental,
    00115     lengthof(_airport_depots_intercontinental),
    00116     9, 11,
    00117     0,
    00118     10
    00119   );
    00120
    00121   Heliport = new AirportFTAClass(
    00122     _airport_moving_data_heliport,
    00123     NULL,
    00124     _airport_helipad_heliport_oilrig,
    00125     _airport_entries_heliport_oilrig,
    00126     AirportFTAClass::HELICOPTERS,
    00127     _airport_fta_heliport_oilrig,
    00128     NULL,
    00129     0,
    00130     1, 1,
    00131     60,
    00132     4
    00133   );
    00134
    00135   Oilrig = new AirportFTAClass(
    00136     _airport_moving_data_oilrig,
    00137     NULL,
    00138     _airport_helipad_heliport_oilrig,
    00139     _airport_entries_heliport_oilrig,
    00140     AirportFTAClass::HELICOPTERS,
    00141     _airport_fta_heliport_oilrig,
    00142     NULL,
    00143     0,
    00144     1, 1,
    00145     54,
    00146     3
    00147   );
    00148
    00149   CommuterAirport = new AirportFTAClass(
    00150     _airport_moving_data_commuter,
    00151     _airport_terminal_commuter,
    00152     _airport_helipad_commuter,
    00153     _airport_entries_commuter,
    00154     AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
    00155     _airport_fta_commuter,
    00156     _airport_depots_commuter,
    00157     lengthof(_airport_depots_commuter),
    00158     5, 4,
    00159     0,
    00160     4
    00161   );
    00162
    00163   HeliDepot = new AirportFTAClass(
    00164     _airport_moving_data_helidepot,
    00165     NULL,
    00166     _airport_helipad_helidepot,
    00167     _airport_entries_helidepot,
    00168     AirportFTAClass::HELICOPTERS,
    00169     _airport_fta_helidepot,
    00170     _airport_depots_helidepot,
    00171     lengthof(_airport_depots_helidepot),
    00172     2, 2,
    00173     0,
    00174     4
    00175   );
    00176
    00177   HeliStation = new AirportFTAClass(
    00178     _airport_moving_data_helistation,
    00179     NULL,
    00180     _airport_helipad_helistation,
    00181     _airport_entries_helistation,
    00182     AirportFTAClass::HELICOPTERS,
    00183     _airport_fta_helistation,
    00184     _airport_depots_helistation,
    00185     lengthof(_airport_depots_helistation),
    00186     4, 2,
    00187     0,
    00188     4
    00189   );
    00190 }
    00191
    00192 void UnInitializeAirports()
    00193 {
    00194   delete DummyAirport;
    00195   delete CountryAirport;
    00196   delete CityAirport;
    00197   delete Heliport;
    00198   delete MetropolitanAirport;
    00199   delete InternationalAirport;
    00200   delete CommuterAirport;
    00201   delete HeliDepot;
    00202   delete IntercontinentalAirport;
    00203   delete HeliStation;
    00204 }
    00205
    00206
    00207 static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
    00208 static AirportFTA* AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA);
    00209 static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
    00210 static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals);
    00211
    00212 #ifdef DEBUG_AIRPORT
    00213 static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report);
    00214 #endif
    00215
    00216
    00217 AirportFTAClass::AirportFTAClass(
    00218   const AirportMovingData *moving_data_,
    00219   const byte *terminals_,
    00220   const byte *helipads_,
    00221   const byte *entry_points_,
    00222   Flags flags_,
    00223   const AirportFTAbuildup *apFA,
    00224   const TileIndexDiffC *depots_,
    00225   const byte nof_depots_,
    00226   uint size_x_,
    00227   uint size_y_,
    00228   byte delta_z_,
    00229   byte catchment_
    00230 ) :
    00231   moving_data(moving_data_),
    00232   terminals(terminals_),
    00233   helipads(helipads_),
    00234   airport_depots(depots_),
    00235   flags(flags_),
    00236   nof_depots(nof_depots_),
    00237   nofelements(AirportGetNofElements(apFA)),
    00238   entry_points(entry_points_),
    00239   size_x(size_x_),
    00240   size_y(size_y_),
    00241   delta_z(delta_z_),
    00242   catchment(catchment_)
    00243 {
    00244   byte nofterminalgroups, nofhelipadgroups;
    00245
    00246   /* Set up the terminal and helipad count for an airport.
    00247    * TODO: If there are more than 10 terminals or 4 helipads, internal variables
    00248    * need to be changed, so don't allow that for now */
    00249   uint nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
    00250   if (nofterminals > MAX_TERMINALS) {
    00251     DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
    00252     assert(nofterminals <= MAX_TERMINALS);
    00253   }
    00254
    00255   uint nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
    00256   if (nofhelipads > MAX_HELIPADS) {
    00257     DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
    00258     assert(nofhelipads <= MAX_HELIPADS);
    00259   }
    00260
    00261   /* Get the number of elements from the source table. We also double check this
    00262    * with the entry point which must be within bounds and use this information
    00263    * later on to build and validate the state machine */
    00264   for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
    00265     if (entry_points[i] >= nofelements) {
    00266       DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_points[i], nofelements);
    00267       assert(entry_points[i] < nofelements);
    00268     }
    00269   }
    00270
    00271   /* Build the state machine itself */
    00272   layout = AirportBuildAutomata(nofelements, apFA);
    00273   DEBUG(misc, 2, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entries %3d, %3d, %3d, %3d",
    00274     nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups,
    00275     entry_points[DIAGDIR_NE], entry_points[DIAGDIR_SE], entry_points[DIAGDIR_SW], entry_points[DIAGDIR_NW]);
    00276
    00277   /* Test if everything went allright. This is only a rude static test checking
    00278    * the symantic correctness. By no means does passing the test mean that the
    00279    * airport is working correctly or will not deadlock for example */
    00280   uint ret = AirportTestFTA(nofelements, layout, terminals);
    00281   if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
    00282   assert(ret == MAX_ELEMENTS);
    00283
    00284 #ifdef DEBUG_AIRPORT
    00285   AirportPrintOut(nofelements, layout, DEBUG_AIRPORT);
    00286 #endif
    00287 }
    00288
    00289
    00290 AirportFTAClass::~AirportFTAClass()
    00291 {
    00292   for (uint i = 0; i < nofelements; i++) {
    00293     AirportFTA *current = layout[i].next;
    00294     while (current != NULL) {
    00295       AirportFTA *next = current->next;
    00296       free(current);
    00297       current = next;
    00298     };
    00299   }
    00300   free(layout);
    00301 }
    00302
    00306 static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
    00307 {
    00308   uint16 nofelements = 0;
    00309   int temp = apFA[0].position;
    00310
    00311   for (uint i = 0; i < MAX_ELEMENTS; i++) {
    00312     if (temp != apFA[i].position) {
    00313       nofelements++;
    00314       temp = apFA[i].position;
    00315     }
    00316     if (apFA[i].position == MAX_ELEMENTS) break;
    00317   }
    00318   return nofelements;
    00319 }
    00320
    00321 /* We calculate the terminal/helipod count based on the data passed to us
    00322  * This data (terminals) contains an index as a first element as to how many
    00323  * groups there are, and then the number of terminals for each group */
    00324 static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
    00325 {
    00326   byte nof_terminals = 0;
    00327   *groups = 0;
    00328
    00329   if (terminals != NULL) {
    00330     uint i = terminals[0];
    00331     *groups = i;
    00332     while (i-- > 0) {
    00333       terminals++;
    00334       assert(*terminals != 0); // no empty groups please
    00335       nof_terminals += *terminals;
    00336     }
    00337   }
    00338   return nof_terminals;
    00339 }
    00340
    00341
    00342 static AirportFTA* AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA)
    00343 {
    00344   AirportFTA *FAutomata = MallocT<AirportFTA>(nofelements);
    00345   uint16 internalcounter = 0;
    00346
    00347   for (uint i = 0; i < nofelements; i++) {
    00348     AirportFTA *current = &FAutomata[i];
    00349     current->position      = apFA[internalcounter].position;
    00350     current->heading       = apFA[internalcounter].heading;
    00351     current->block         = apFA[internalcounter].block;
    00352     current->next_position = apFA[internalcounter].next;
    00353
    00354     // outgoing nodes from the same position, create linked list
    00355     while (current->position == apFA[internalcounter + 1].position) {
    00356       AirportFTA *newNode = MallocT<AirportFTA>(1);
    00357
    00358       newNode->position      = apFA[internalcounter + 1].position;
    00359       newNode->heading       = apFA[internalcounter + 1].heading;
    00360       newNode->block         = apFA[internalcounter + 1].block;
    00361       newNode->next_position = apFA[internalcounter + 1].next;
    00362       // create link
    00363       current->next = newNode;
    00364       current = current->next;
    00365       internalcounter++;
    00366     }
    00367     current->next = NULL;
    00368     internalcounter++;
    00369   }
    00370   return FAutomata;
    00371 }
    00372
    00373
    00374 static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals)
    00375 {
    00376   uint next_position = 0;
    00377
    00378   for (uint i = 0; i < nofelements; i++) {
    00379     uint position = layout[i].position;
    00380     if (position != next_position) return i;
    00381     const AirportFTA *first = &layout[i];
    00382
    00383     for (const AirportFTA *current = first; current != NULL; current = current->next) {
    00384       /* A heading must always be valid. The only exceptions are
    00385        * - multiple choices as start, identified by a special value of 255
    00386        * - terminal group which is identified by a special value of 255 */
    00387       if (current->heading > MAX_HEADINGS) {
    00388         if (current->heading != 255) return i;
    00389         if (current == first && current->next == NULL) return i;
    00390         if (current != first && current->next_position > terminals[0]) return i;
    00391       }
    00392
    00393       /* If there is only one choice, it must be at the end */
    00394       if (current->heading == 0 && current->next != NULL) return i;
    00395       /* Obviously the elements of the linked list must have the same identifier */
    00396       if (position != current->position) return i;
    00397       /* A next position must be within bounds */
    00398       if (current->next_position >= nofelements) return i;
    00399     }
    00400     next_position++;
    00401   }
    00402   return MAX_ELEMENTS;
    00403 }
    00404
    00405 #ifdef DEBUG_AIRPORT
    00406 static const char* const _airport_heading_strings[] = {
    00407   "TO_ALL",
    00408   "HANGAR",
    00409   "TERM1",
    00410   "TERM2",
    00411   "TERM3",
    00412   "TERM4",
    00413   "TERM5",
    00414   "TERM6",
    00415   "HELIPAD1",
    00416   "HELIPAD2",
    00417   "TAKEOFF",
    00418   "STARTTAKEOFF",
    00419   "ENDTAKEOFF",
    00420   "HELITAKEOFF",
    00421   "FLYING",
    00422   "LANDING",
    00423   "ENDLANDING",
    00424   "HELILANDING",
    00425   "HELIENDLANDING",
    00426   "TERM7",
    00427   "TERM8",
    00428   "HELIPAD3",
    00429   "HELIPAD4",
    00430   "DUMMY" // extra heading for 255
    00431 };
    00432
    00433 static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report)
    00434 {
    00435   if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
    00436
    00437   for (uint i = 0; i < nofelements; i++) {
    00438     for (const AirportFTA *current = &layout[i]; current != NULL; current = current->next) {
    00439       if (full_report) {
    00440         byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
    00441         printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
    00442               current->next_position, _airport_heading_strings[heading],
    00443               FindLastBit(current->block));
    00444       } else {
    00445         printf("P:%2d NP:%2d", current->position, current->next_position);
    00446       }
    00447     }
    00448     printf("\n");
    00449   }
    00450 }
    00451 #endif
    00452
    00453 const AirportFTAClass *GetAirport(const byte airport_type)
    00454 {
    00455   //FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
    00456   // needs constant change if more airports are added
    00457   switch (airport_type) {
    00458     default:               NOT_REACHED();
    00459     case AT_SMALL:         return CountryAirport;
    00460     case AT_LARGE:         return CityAirport;
    00461     case AT_METROPOLITAN:  return MetropolitanAirport;
    00462     case AT_HELIPORT:      return Heliport;
    00463     case AT_OILRIG:        return Oilrig;
    00464     case AT_INTERNATIONAL: return InternationalAirport;
    00465     case AT_COMMUTER:      return CommuterAirport;
    00466     case AT_HELIDEPOT:     return HeliDepot;
    00467     case AT_INTERCON:      return IntercontinentalAirport;
    00468     case AT_HELISTATION:   return HeliStation;
    00469     case AT_DUMMY:         return DummyAirport;
    00470   }
    00471 }
    00472
    00473
    00474 uint32 GetValidAirports()
    00475 {
    00476   uint32 mask = 0;
    00477
    00478   if (_cur_year <  1960 || _patches.always_small_airport) SetBit(mask, 0);  // small airport
    00479   if (_cur_year >= 1955) SetBit(mask, 1); // city airport
    00480   if (_cur_year >= 1963) SetBit(mask, 2); // heliport
    00481   if (_cur_year >= 1980) SetBit(mask, 3); // metropolitan airport
    00482   if (_cur_year >= 1990) SetBit(mask, 4); // international airport
    00483   if (_cur_year >= 1983) SetBit(mask, 5); // commuter airport
    00484   if (_cur_year >= 1976) SetBit(mask, 6); // helidepot
    00485   if (_cur_year >= 2002) SetBit(mask, 7); // intercontinental airport
    00486   if (_cur_year >= 1980) SetBit(mask, 8); // helistation
    00487   return mask;
    00488 }