airport.cpp

Go to the documentation of this file.
00001 /* $Id: airport.cpp 13325 2008-05-29 15:13:28Z 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, 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, 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, 5,
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, 8,
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, 17,
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, 25,
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, 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, 0,
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, 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, 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, 3,
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 noise_level_,
00229   byte delta_z_,
00230   byte catchment_
00231 ) :
00232   moving_data(moving_data_),
00233   terminals(terminals_),
00234   helipads(helipads_),
00235   airport_depots(depots_),
00236   flags(flags_),
00237   nof_depots(nof_depots_),
00238   nofelements(AirportGetNofElements(apFA)),
00239   entry_points(entry_points_),
00240   size_x(size_x_),
00241   size_y(size_y_),
00242   noise_level(noise_level_),
00243   delta_z(delta_z_),
00244   catchment(catchment_)
00245 {
00246   byte nofterminalgroups, nofhelipadgroups;
00247 
00248   /* Set up the terminal and helipad count for an airport.
00249    * TODO: If there are more than 10 terminals or 4 helipads, internal variables
00250    * need to be changed, so don't allow that for now */
00251   uint nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
00252   if (nofterminals > MAX_TERMINALS) {
00253     DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
00254     assert(nofterminals <= MAX_TERMINALS);
00255   }
00256 
00257   uint nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
00258   if (nofhelipads > MAX_HELIPADS) {
00259     DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
00260     assert(nofhelipads <= MAX_HELIPADS);
00261   }
00262 
00263   /* Get the number of elements from the source table. We also double check this
00264    * with the entry point which must be within bounds and use this information
00265    * later on to build and validate the state machine */
00266   for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
00267     if (entry_points[i] >= nofelements) {
00268       DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_points[i], nofelements);
00269       assert(entry_points[i] < nofelements);
00270     }
00271   }
00272 
00273   /* Build the state machine itself */
00274   layout = AirportBuildAutomata(nofelements, apFA);
00275   DEBUG(misc, 2, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entries %3d, %3d, %3d, %3d",
00276     nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups,
00277     entry_points[DIAGDIR_NE], entry_points[DIAGDIR_SE], entry_points[DIAGDIR_SW], entry_points[DIAGDIR_NW]);
00278 
00279   /* Test if everything went allright. This is only a rude static test checking
00280    * the symantic correctness. By no means does passing the test mean that the
00281    * airport is working correctly or will not deadlock for example */
00282   uint ret = AirportTestFTA(nofelements, layout, terminals);
00283   if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
00284   assert(ret == MAX_ELEMENTS);
00285 
00286 #ifdef DEBUG_AIRPORT
00287   AirportPrintOut(nofelements, layout, DEBUG_AIRPORT);
00288 #endif
00289 }
00290 
00291 
00292 AirportFTAClass::~AirportFTAClass()
00293 {
00294   for (uint i = 0; i < nofelements; i++) {
00295     AirportFTA *current = layout[i].next;
00296     while (current != NULL) {
00297       AirportFTA *next = current->next;
00298       free(current);
00299       current = next;
00300     };
00301   }
00302   free(layout);
00303 }
00304 
00308 static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
00309 {
00310   uint16 nofelements = 0;
00311   int temp = apFA[0].position;
00312 
00313   for (uint i = 0; i < MAX_ELEMENTS; i++) {
00314     if (temp != apFA[i].position) {
00315       nofelements++;
00316       temp = apFA[i].position;
00317     }
00318     if (apFA[i].position == MAX_ELEMENTS) break;
00319   }
00320   return nofelements;
00321 }
00322 
00323 /* We calculate the terminal/helipod count based on the data passed to us
00324  * This data (terminals) contains an index as a first element as to how many
00325  * groups there are, and then the number of terminals for each group */
00326 static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
00327 {
00328   byte nof_terminals = 0;
00329   *groups = 0;
00330 
00331   if (terminals != NULL) {
00332     uint i = terminals[0];
00333     *groups = i;
00334     while (i-- > 0) {
00335       terminals++;
00336       assert(*terminals != 0); // no empty groups please
00337       nof_terminals += *terminals;
00338     }
00339   }
00340   return nof_terminals;
00341 }
00342 
00343 
00344 static AirportFTA* AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA)
00345 {
00346   AirportFTA *FAutomata = MallocT<AirportFTA>(nofelements);
00347   uint16 internalcounter = 0;
00348 
00349   for (uint i = 0; i < nofelements; i++) {
00350     AirportFTA *current = &FAutomata[i];
00351     current->position      = apFA[internalcounter].position;
00352     current->heading       = apFA[internalcounter].heading;
00353     current->block         = apFA[internalcounter].block;
00354     current->next_position = apFA[internalcounter].next;
00355 
00356     // outgoing nodes from the same position, create linked list
00357     while (current->position == apFA[internalcounter + 1].position) {
00358       AirportFTA *newNode = MallocT<AirportFTA>(1);
00359 
00360       newNode->position      = apFA[internalcounter + 1].position;
00361       newNode->heading       = apFA[internalcounter + 1].heading;
00362       newNode->block         = apFA[internalcounter + 1].block;
00363       newNode->next_position = apFA[internalcounter + 1].next;
00364       // create link
00365       current->next = newNode;
00366       current = current->next;
00367       internalcounter++;
00368     }
00369     current->next = NULL;
00370     internalcounter++;
00371   }
00372   return FAutomata;
00373 }
00374 
00375 
00376 static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals)
00377 {
00378   uint next_position = 0;
00379 
00380   for (uint i = 0; i < nofelements; i++) {
00381     uint position = layout[i].position;
00382     if (position != next_position) return i;
00383     const AirportFTA *first = &layout[i];
00384 
00385     for (const AirportFTA *current = first; current != NULL; current = current->next) {
00386       /* A heading must always be valid. The only exceptions are
00387        * - multiple choices as start, identified by a special value of 255
00388        * - terminal group which is identified by a special value of 255 */
00389       if (current->heading > MAX_HEADINGS) {
00390         if (current->heading != 255) return i;
00391         if (current == first && current->next == NULL) return i;
00392         if (current != first && current->next_position > terminals[0]) return i;
00393       }
00394 
00395       /* If there is only one choice, it must be at the end */
00396       if (current->heading == 0 && current->next != NULL) return i;
00397       /* Obviously the elements of the linked list must have the same identifier */
00398       if (position != current->position) return i;
00399       /* A next position must be within bounds */
00400       if (current->next_position >= nofelements) return i;
00401     }
00402     next_position++;
00403   }
00404   return MAX_ELEMENTS;
00405 }
00406 
00407 #ifdef DEBUG_AIRPORT
00408 static const char* const _airport_heading_strings[] = {
00409   "TO_ALL",
00410   "HANGAR",
00411   "TERM1",
00412   "TERM2",
00413   "TERM3",
00414   "TERM4",
00415   "TERM5",
00416   "TERM6",
00417   "HELIPAD1",
00418   "HELIPAD2",
00419   "TAKEOFF",
00420   "STARTTAKEOFF",
00421   "ENDTAKEOFF",
00422   "HELITAKEOFF",
00423   "FLYING",
00424   "LANDING",
00425   "ENDLANDING",
00426   "HELILANDING",
00427   "HELIENDLANDING",
00428   "TERM7",
00429   "TERM8",
00430   "HELIPAD3",
00431   "HELIPAD4",
00432   "DUMMY" // extra heading for 255
00433 };
00434 
00435 static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report)
00436 {
00437   if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
00438 
00439   for (uint i = 0; i < nofelements; i++) {
00440     for (const AirportFTA *current = &layout[i]; current != NULL; current = current->next) {
00441       if (full_report) {
00442         byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
00443         printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
00444               current->next_position, _airport_heading_strings[heading],
00445               FindLastBit(current->block));
00446       } else {
00447         printf("P:%2d NP:%2d", current->position, current->next_position);
00448       }
00449     }
00450     printf("\n");
00451   }
00452 }
00453 #endif
00454 
00455 const AirportFTAClass *GetAirport(const byte airport_type)
00456 {
00457   //FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
00458   // needs constant change if more airports are added
00459   switch (airport_type) {
00460     default:               NOT_REACHED();
00461     case AT_SMALL:         return CountryAirport;
00462     case AT_LARGE:         return CityAirport;
00463     case AT_METROPOLITAN:  return MetropolitanAirport;
00464     case AT_HELIPORT:      return Heliport;
00465     case AT_OILRIG:        return Oilrig;
00466     case AT_INTERNATIONAL: return InternationalAirport;
00467     case AT_COMMUTER:      return CommuterAirport;
00468     case AT_HELIDEPOT:     return HeliDepot;
00469     case AT_INTERCON:      return IntercontinentalAirport;
00470     case AT_HELISTATION:   return HeliStation;
00471     case AT_DUMMY:         return DummyAirport;
00472   }
00473 }
00474 
00475 
00476 uint32 GetValidAirports()
00477 {
00478   uint32 mask = 0;
00479 
00480   if (_cur_year <  1960 || _settings_game.station.always_small_airport) SetBit(mask, 0);  // small airport
00481   if (_cur_year >= 1955) SetBit(mask, 1); // city airport
00482   if (_cur_year >= 1963) SetBit(mask, 2); // heliport
00483   if (_cur_year >= 1980) SetBit(mask, 3); // metropolitan airport
00484   if (_cur_year >= 1990) SetBit(mask, 4); // international airport
00485   if (_cur_year >= 1983) SetBit(mask, 5); // commuter airport
00486   if (_cur_year >= 1976) SetBit(mask, 6); // helidepot
00487   if (_cur_year >= 2002) SetBit(mask, 7); // intercontinental airport
00488   if (_cur_year >= 1980) SetBit(mask, 8); // helistation
00489   return mask;
00490 }

Generated on Fri Nov 21 19:01:31 2008 for openttd by  doxygen 1.5.6