airport.cpp

Go to the documentation of this file.
00001 /* $Id: airport.cpp 18845 2010-01-17 14:22:07Z yexo $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "debug.h"
00014 #include "airport.h"
00015 #include "table/airport_movement.h"
00016 #include "core/alloc_func.hpp"
00017 #include "date_func.h"
00018 #include "settings_type.h"
00019 
00020 
00021 /* 8-66 are mapped to 0-58, 83+ are mapped to 59+ */
00022 enum AirportTiles {
00023   APT_APRON                  = 0,
00024   APT_APRON_FENCE_NW         = 1,
00025   APT_APRON_FENCE_SW         = 2,
00026   APT_STAND                  = 3,
00027   APT_APRON_W                = 4,
00028   APT_APRON_S                = 5,
00029   APT_APRON_VER_CROSSING_S   = 6,
00030   APT_APRON_HOR_CROSSING_W   = 7,
00031   APT_APRON_VER_CROSSING_N   = 8,
00032   APT_APRON_HOR_CROSSING_E   = 9,
00033   APT_APRON_E                = 10,
00034   APT_ARPON_N                = 11,
00035   APT_APRON_HOR              = 12,
00036   APT_APRON_N_FENCE_SW       = 13,
00037   APT_RUNWAY_1               = 14,
00038   APT_RUNWAY_2               = 15,
00039   APT_RUNWAY_3               = 16,
00040   APT_RUNWAY_4               = 17,
00041   APT_RUNWAY_END_FENCE_SE    = 18,
00042   APT_BUILDING_2             = 19,
00043   APT_TOWER_FENCE_SW         = 20,
00044   APT_ROUND_TERMINAL         = 21,
00045   APT_BUILDING_3             = 22,
00046   APT_BUILDING_1             = 23,
00047   APT_DEPOT_SE               = 24,
00048   APT_STAND_1                = 25,
00049   APT_STAND_PIER_NE          = 26,
00050   APT_PIER_NW_NE             = 27,
00051   APT_PIER                   = 28,
00052   APT_EMPTY                  = 29,
00053   APT_EMPTY_FENCE_NE         = 30,
00054   APT_RADAR_GRASS_FENCE_SW   = 31,
00055   /* 32-42 are for turning the radar */
00056   APT_RADIO_TOWER_FENCE_NE   = 43,
00057   APT_SMALL_BUILDING_3       = 44,
00058   APT_SMALL_BUILDING_2       = 45,
00059   APT_SMALL_BUILDING_1       = 46,
00060   APT_GRASS_FENCE_SW         = 47,
00061   APT_GRASS_2                = 48,
00062   APT_GRASS_1                = 49,
00063   APT_GRASS_FENCE_NE_FLAG    = 50,
00064   /* 51-53 are for flag animation */
00065   APT_RUNWAY_SMALL_NEAR_END  = 54,
00066   APT_RUNWAY_SMALL_MIDDLE    = 55,
00067   APT_RUNWAY_SMALL_FAR_END   = 56,
00068   APT_SMALL_DEPOT_SE         = 57,
00069   APT_HELIPORT               = 58,
00070   APT_RUNWAY_END             = 59,
00071   APT_RUNWAY_5               = 60,
00072   APT_TOWER                  = 61,
00073   APT_SMALL_DEPOT_SE_2       = 62, // unused (copy of APT_SMALL_DEPOT_SE)
00074   APT_APRON_FENCE_NE         = 63,
00075   APT_RUNWAY_END_FENCE_NW    = 64,
00076   APT_RUNWAY_FENCE_NW        = 65,
00077   APT_RADAR_FENCE_SW         = 66,
00078   /* 67-77 are for turning the radar */
00079   APT_RADAR_FENCE_NE         = 78,
00080   /* 79-89 are for turning the radar */
00081   APT_HELIPAD_1              = 90,
00082   APT_HELIPAD_2_FENCE_NW     = 91,
00083   APT_HELIPAD_2              = 92,
00084   APT_APRON_FENCE_NE_SW      = 93,
00085   APT_RUNWAY_END_FENCE_NW_SW = 94,
00086   APT_RUNWAY_END_FENCE_SE_SW = 95,
00087   APT_RUNWAY_END_FENCE_NE_NW = 96,
00088   APT_RUNWAY_END_FENCE_NE_SE = 97,
00089   APT_HELIPAD_2_FENCE_NE_SE  = 98,
00090   APT_APRON_FENCE_SE_SW      = 99,
00091   APT_LOW_BUILDING_FENCE_N   = 100,
00092   APT_ROT_RUNWAY_FENCE_NE    = 101, // unused
00093   APT_ROT_RUNWAY_END_FENCE_NE= 102, // unused
00094   APT_ROT_RUNWAY_FENCE_SW    = 103, // unused
00095   APT_ROT_RUNWAY_END_FENCE_SW= 104, // unused
00096   APT_DEPOT_SW               = 105, // unused
00097   APT_DEPOT_NW               = 106, // unused
00098   APT_DEPOT_NE               = 107, // unused
00099   APT_HELIPAD_2_FENCE_SE_SW  = 108, // unused
00100   APT_HELIPAD_2_FENCE_SE     = 109, // unused
00101   APT_LOW_BUILDING_FENCE_NW  = 110,
00102   APT_LOW_BUILDING_FENCE_NE  = 111, // unused
00103   APT_LOW_BUILDING_FENCE_SW  = 112, // unused
00104   APT_LOW_BUILDING_FENCE_SE  = 113, // unused
00105   APT_STAND_FENCE_NE         = 114, // unused
00106   APT_STAND_FENCE_SE         = 115, // unused
00107   APT_STAND_FENCE_SW         = 116, // unused
00108   APT_APRON_FENCE_NE_2       = 117, // unused (copy of APT_APRON_FENCE_NE)
00109   APT_APRON_FENCE_SE         = 118,
00110   APT_HELIPAD_2_FENCE_NW_SW  = 119, // unused
00111   APT_HELIPAD_2_FENCE_SW     = 120, // unused
00112   APT_RADAR_FENCE_SE         = 121, // unused
00113   /* 122-132 used for radar rotation */
00114   APT_HELIPAD_3_FENCE_SE_SW  = 133,
00115   APT_HELIPAD_3_FENCE_NW_SW  = 134,
00116   APT_HELIPAD_3_FENCE_NW     = 135,
00117   APT_LOW_BUILDING           = 136,
00118   APT_APRON_FENCE_NE_SE      = 137,
00119   APT_APRON_HALF_EAST        = 138,
00120   APT_APRON_HALF_WEST        = 139,
00121   APT_GRASS_FENCE_NE_FLAG_2  = 140,
00122   /* 141-143 used for flag animation */
00123 };
00124 
00125 #include "table/airport_defaults.h"
00126 #include "table/airporttiles.h"
00127 
00128 AirportSpec AirportSpec::dummy = {NULL, NULL, 0, 0, 0, 0, 0, MIN_YEAR, MIN_YEAR};
00129 AirportSpec AirportSpec::oilrig = {NULL, NULL, 0, 1, 1, 0, 4, MIN_YEAR, MIN_YEAR};
00130 
00131 
00137 /* static */ const AirportSpec *AirportSpec::Get(byte type)
00138 {
00139   if (type == AT_OILRIG) return &oilrig;
00140   assert(type < NUM_AIRPORTS);
00141   extern const AirportSpec _origin_airport_specs[];
00142   return &_origin_airport_specs[type];
00143 }
00144 
00150 /* static */ const AirportTileSpec *AirportTileSpec::Get(StationGfx gfx)
00151 {
00152   assert(gfx < NUM_AIRPORTTILES);
00153   extern const AirportTileSpec _origin_airporttile_specs[];
00154   return &_origin_airporttile_specs[gfx];
00155 }
00156 
00157 /* Uncomment this to print out a full report of the airport-structure
00158  * You should either use
00159  * - true: full-report, print out every state and choice with string-names
00160  * OR
00161  * - false: give a summarized report which only shows current and next position */
00162 //#define DEBUG_AIRPORT false
00163 
00164 static AirportFTAClass *_dummy_airport;
00165 static AirportFTAClass *_country_airport;
00166 static AirportFTAClass *_city_airport;
00167 static AirportFTAClass *_oilrig;
00168 static AirportFTAClass *_heliport;
00169 static AirportFTAClass *_metropolitan_airport;
00170 static AirportFTAClass *_international_airport;
00171 static AirportFTAClass *_commuter_airport;
00172 static AirportFTAClass *_heli_depot;
00173 static AirportFTAClass *_intercontinental_airport;
00174 static AirportFTAClass *_heli_station;
00175 
00176 
00177 void InitializeAirports()
00178 {
00179   _dummy_airport = new AirportFTAClass(
00180     _airport_moving_data_dummy,
00181     NULL,
00182     NULL,
00183     _airport_entries_dummy,
00184     AirportFTAClass::ALL,
00185     _airport_fta_dummy,
00186     0
00187   );
00188 
00189   _country_airport = new AirportFTAClass(
00190     _airport_moving_data_country,
00191     _airport_terminal_country,
00192     NULL,
00193     _airport_entries_country,
00194     AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
00195     _airport_fta_country,
00196     0
00197   );
00198 
00199   _city_airport = new AirportFTAClass(
00200     _airport_moving_data_town,
00201     _airport_terminal_city,
00202     NULL,
00203     _airport_entries_city,
00204     AirportFTAClass::ALL,
00205     _airport_fta_city,
00206     0
00207   );
00208 
00209   _metropolitan_airport = new AirportFTAClass(
00210     _airport_moving_data_metropolitan,
00211     _airport_terminal_metropolitan,
00212     NULL,
00213     _airport_entries_metropolitan,
00214     AirportFTAClass::ALL,
00215     _airport_fta_metropolitan,
00216     0
00217   );
00218 
00219   _international_airport = new AirportFTAClass(
00220     _airport_moving_data_international,
00221     _airport_terminal_international,
00222     _airport_helipad_international,
00223     _airport_entries_international,
00224     AirportFTAClass::ALL,
00225     _airport_fta_international,
00226     0
00227   );
00228 
00229   _intercontinental_airport = new AirportFTAClass(
00230     _airport_moving_data_intercontinental,
00231     _airport_terminal_intercontinental,
00232     _airport_helipad_intercontinental,
00233     _airport_entries_intercontinental,
00234     AirportFTAClass::ALL,
00235     _airport_fta_intercontinental,
00236     0
00237   );
00238 
00239   _heliport = new AirportFTAClass(
00240     _airport_moving_data_heliport,
00241     NULL,
00242     _airport_helipad_heliport_oilrig,
00243     _airport_entries_heliport_oilrig,
00244     AirportFTAClass::HELICOPTERS,
00245     _airport_fta_heliport_oilrig,
00246     60
00247   );
00248 
00249   _oilrig = new AirportFTAClass(
00250     _airport_moving_data_oilrig,
00251     NULL,
00252     _airport_helipad_heliport_oilrig,
00253     _airport_entries_heliport_oilrig,
00254     AirportFTAClass::HELICOPTERS,
00255     _airport_fta_heliport_oilrig,
00256     54
00257   );
00258 
00259   _commuter_airport = new AirportFTAClass(
00260     _airport_moving_data_commuter,
00261     _airport_terminal_commuter,
00262     _airport_helipad_commuter,
00263     _airport_entries_commuter,
00264     AirportFTAClass::ALL | AirportFTAClass::SHORT_STRIP,
00265     _airport_fta_commuter,
00266     0
00267   );
00268 
00269   _heli_depot = new AirportFTAClass(
00270     _airport_moving_data_helidepot,
00271     NULL,
00272     _airport_helipad_helidepot,
00273     _airport_entries_helidepot,
00274     AirportFTAClass::HELICOPTERS,
00275     _airport_fta_helidepot,
00276     0
00277   );
00278 
00279   _heli_station = new AirportFTAClass(
00280     _airport_moving_data_helistation,
00281     NULL,
00282     _airport_helipad_helistation,
00283     _airport_entries_helistation,
00284     AirportFTAClass::HELICOPTERS,
00285     _airport_fta_helistation,
00286     0
00287   );
00288 }
00289 
00290 void UnInitializeAirports()
00291 {
00292   delete _dummy_airport;
00293   delete _country_airport;
00294   delete _city_airport;
00295   delete _heliport;
00296   delete _metropolitan_airport;
00297   delete _international_airport;
00298   delete _commuter_airport;
00299   delete _heli_depot;
00300   delete _intercontinental_airport;
00301   delete _heli_station;
00302 }
00303 
00304 
00305 static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA);
00306 static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA);
00307 static byte AirportGetTerminalCount(const byte *terminals, byte *groups);
00308 static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals);
00309 
00310 #ifdef DEBUG_AIRPORT
00311 static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report);
00312 #endif
00313 
00314 
00315 AirportFTAClass::AirportFTAClass(
00316   const AirportMovingData *moving_data_,
00317   const byte *terminals_,
00318   const byte *helipads_,
00319   const byte *entry_points_,
00320   Flags flags_,
00321   const AirportFTAbuildup *apFA,
00322   byte delta_z_
00323 ) :
00324   moving_data(moving_data_),
00325   terminals(terminals_),
00326   helipads(helipads_),
00327   flags(flags_),
00328   nofelements(AirportGetNofElements(apFA)),
00329   entry_points(entry_points_),
00330   delta_z(delta_z_)
00331 {
00332   byte nofterminalgroups, nofhelipadgroups;
00333 
00334   /* Set up the terminal and helipad count for an airport.
00335    * TODO: If there are more than 10 terminals or 4 helipads, internal variables
00336    * need to be changed, so don't allow that for now */
00337   uint nofterminals = AirportGetTerminalCount(terminals, &nofterminalgroups);
00338   if (nofterminals > MAX_TERMINALS) {
00339     DEBUG(misc, 0, "[Ap] only a maximum of %d terminals are supported (requested %d)", MAX_TERMINALS, nofterminals);
00340     assert(nofterminals <= MAX_TERMINALS);
00341   }
00342 
00343   uint nofhelipads = AirportGetTerminalCount(helipads, &nofhelipadgroups);
00344   if (nofhelipads > MAX_HELIPADS) {
00345     DEBUG(misc, 0, "[Ap] only a maximum of %d helipads are supported (requested %d)", MAX_HELIPADS, nofhelipads);
00346     assert(nofhelipads <= MAX_HELIPADS);
00347   }
00348 
00349   /* Get the number of elements from the source table. We also double check this
00350    * with the entry point which must be within bounds and use this information
00351    * later on to build and validate the state machine */
00352   for (DiagDirection i = DIAGDIR_BEGIN; i < DIAGDIR_END; i++) {
00353     if (entry_points[i] >= nofelements) {
00354       DEBUG(misc, 0, "[Ap] entry (%d) must be within the airport (maximum %d)", entry_points[i], nofelements);
00355       assert(entry_points[i] < nofelements);
00356     }
00357   }
00358 
00359   /* Build the state machine itself */
00360   layout = AirportBuildAutomata(nofelements, apFA);
00361   DEBUG(misc, 6, "[Ap] #count %3d; #term %2d (%dgrp); #helipad %2d (%dgrp); entries %3d, %3d, %3d, %3d",
00362     nofelements, nofterminals, nofterminalgroups, nofhelipads, nofhelipadgroups,
00363     entry_points[DIAGDIR_NE], entry_points[DIAGDIR_SE], entry_points[DIAGDIR_SW], entry_points[DIAGDIR_NW]);
00364 
00365   /* Test if everything went allright. This is only a rude static test checking
00366    * the symantic correctness. By no means does passing the test mean that the
00367    * airport is working correctly or will not deadlock for example */
00368   uint ret = AirportTestFTA(nofelements, layout, terminals);
00369   if (ret != MAX_ELEMENTS) DEBUG(misc, 0, "[Ap] problem with element: %d", ret - 1);
00370   assert(ret == MAX_ELEMENTS);
00371 
00372 #ifdef DEBUG_AIRPORT
00373   AirportPrintOut(nofelements, layout, DEBUG_AIRPORT);
00374 #endif
00375 }
00376 
00377 AirportFTAClass::~AirportFTAClass()
00378 {
00379   for (uint i = 0; i < nofelements; i++) {
00380     AirportFTA *current = layout[i].next;
00381     while (current != NULL) {
00382       AirportFTA *next = current->next;
00383       free(current);
00384       current = next;
00385     };
00386   }
00387   free(layout);
00388 }
00389 
00390 bool AirportSpec::IsAvailable() const
00391 {
00392   if (_cur_year < this->min_year) return false;
00393   if (_settings_game.station.never_expire_airports) return true;
00394   return _cur_year <= this->max_year;
00395 }
00396 
00400 static uint16 AirportGetNofElements(const AirportFTAbuildup *apFA)
00401 {
00402   uint16 nofelements = 0;
00403   int temp = apFA[0].position;
00404 
00405   for (uint i = 0; i < MAX_ELEMENTS; i++) {
00406     if (temp != apFA[i].position) {
00407       nofelements++;
00408       temp = apFA[i].position;
00409     }
00410     if (apFA[i].position == MAX_ELEMENTS) break;
00411   }
00412   return nofelements;
00413 }
00414 
00418 static byte AirportGetTerminalCount(const byte *terminals, byte *groups)
00419 {
00420   byte nof_terminals = 0;
00421   *groups = 0;
00422 
00423   if (terminals != NULL) {
00424     uint i = terminals[0];
00425     *groups = i;
00426     while (i-- > 0) {
00427       terminals++;
00428       assert(*terminals != 0); // no empty groups please
00429       nof_terminals += *terminals;
00430     }
00431   }
00432   return nof_terminals;
00433 }
00434 
00435 
00436 static AirportFTA *AirportBuildAutomata(uint nofelements, const AirportFTAbuildup *apFA)
00437 {
00438   AirportFTA *FAutomata = MallocT<AirportFTA>(nofelements);
00439   uint16 internalcounter = 0;
00440 
00441   for (uint i = 0; i < nofelements; i++) {
00442     AirportFTA *current = &FAutomata[i];
00443     current->position      = apFA[internalcounter].position;
00444     current->heading       = apFA[internalcounter].heading;
00445     current->block         = apFA[internalcounter].block;
00446     current->next_position = apFA[internalcounter].next;
00447 
00448     /* outgoing nodes from the same position, create linked list */
00449     while (current->position == apFA[internalcounter + 1].position) {
00450       AirportFTA *newNode = MallocT<AirportFTA>(1);
00451 
00452       newNode->position      = apFA[internalcounter + 1].position;
00453       newNode->heading       = apFA[internalcounter + 1].heading;
00454       newNode->block         = apFA[internalcounter + 1].block;
00455       newNode->next_position = apFA[internalcounter + 1].next;
00456       /* create link */
00457       current->next = newNode;
00458       current = current->next;
00459       internalcounter++;
00460     }
00461     current->next = NULL;
00462     internalcounter++;
00463   }
00464   return FAutomata;
00465 }
00466 
00467 
00468 static byte AirportTestFTA(uint nofelements, const AirportFTA *layout, const byte *terminals)
00469 {
00470   uint next_position = 0;
00471 
00472   for (uint i = 0; i < nofelements; i++) {
00473     uint position = layout[i].position;
00474     if (position != next_position) return i;
00475     const AirportFTA *first = &layout[i];
00476 
00477     for (const AirportFTA *current = first; current != NULL; current = current->next) {
00478       /* A heading must always be valid. The only exceptions are
00479        * - multiple choices as start, identified by a special value of 255
00480        * - terminal group which is identified by a special value of 255 */
00481       if (current->heading > MAX_HEADINGS) {
00482         if (current->heading != 255) return i;
00483         if (current == first && current->next == NULL) return i;
00484         if (current != first && current->next_position > terminals[0]) return i;
00485       }
00486 
00487       /* If there is only one choice, it must be at the end */
00488       if (current->heading == 0 && current->next != NULL) return i;
00489       /* Obviously the elements of the linked list must have the same identifier */
00490       if (position != current->position) return i;
00491       /* A next position must be within bounds */
00492       if (current->next_position >= nofelements) return i;
00493     }
00494     next_position++;
00495   }
00496   return MAX_ELEMENTS;
00497 }
00498 
00499 #ifdef DEBUG_AIRPORT
00500 static const char * const _airport_heading_strings[] = {
00501   "TO_ALL",
00502   "HANGAR",
00503   "TERM1",
00504   "TERM2",
00505   "TERM3",
00506   "TERM4",
00507   "TERM5",
00508   "TERM6",
00509   "HELIPAD1",
00510   "HELIPAD2",
00511   "TAKEOFF",
00512   "STARTTAKEOFF",
00513   "ENDTAKEOFF",
00514   "HELITAKEOFF",
00515   "FLYING",
00516   "LANDING",
00517   "ENDLANDING",
00518   "HELILANDING",
00519   "HELIENDLANDING",
00520   "TERM7",
00521   "TERM8",
00522   "HELIPAD3",
00523   "HELIPAD4",
00524   "DUMMY" // extra heading for 255
00525 };
00526 
00527 static void AirportPrintOut(uint nofelements, const AirportFTA *layout, bool full_report)
00528 {
00529   if (!full_report) printf("(P = Current Position; NP = Next Position)\n");
00530 
00531   for (uint i = 0; i < nofelements; i++) {
00532     for (const AirportFTA *current = &layout[i]; current != NULL; current = current->next) {
00533       if (full_report) {
00534         byte heading = (current->heading == 255) ? MAX_HEADINGS + 1 : current->heading;
00535         printf("\tPos:%2d NPos:%2d Heading:%15s Block:%2d\n", current->position,
00536               current->next_position, _airport_heading_strings[heading],
00537               FindLastBit(current->block));
00538       } else {
00539         printf("P:%2d NP:%2d", current->position, current->next_position);
00540       }
00541     }
00542     printf("\n");
00543   }
00544 }
00545 #endif
00546 
00547 const AirportFTAClass *GetAirport(const byte airport_type)
00548 {
00549   /* FIXME -- AircraftNextAirportPos_and_Order -> Needs something nicer, don't like this code
00550    * needs constant change if more airports are added */
00551   switch (airport_type) {
00552     default:               NOT_REACHED();
00553     case AT_SMALL:         return _country_airport;
00554     case AT_LARGE:         return _city_airport;
00555     case AT_METROPOLITAN:  return _metropolitan_airport;
00556     case AT_HELIPORT:      return _heliport;
00557     case AT_OILRIG:        return _oilrig;
00558     case AT_INTERNATIONAL: return _international_airport;
00559     case AT_COMMUTER:      return _commuter_airport;
00560     case AT_HELIDEPOT:     return _heli_depot;
00561     case AT_INTERCON:      return _intercontinental_airport;
00562     case AT_HELISTATION:   return _heli_station;
00563     case AT_DUMMY:         return _dummy_airport;
00564   }
00565 }

Generated on Wed Jan 20 23:38:34 2010 for OpenTTD by  doxygen 1.5.6