# airport.cpp

Go to the documentation of this file.

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