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 }

Generated on Wed Oct 1 17:03:19 2008 for openttd by  doxygen 1.5.6