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 }

Generated on Mon Feb 16 23:12:05 2009 for openttd by  doxygen 1.5.6