airport.cpp

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

Generated on Wed Feb 17 23:06:44 2010 for OpenTTD by  doxygen 1.6.1