station_base.h

Go to the documentation of this file.
00001 /* $Id$ */
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 #ifndef STATION_BASE_H
00013 #define STATION_BASE_H
00014 
00015 #include "core/random_func.hpp"
00016 #include "base_station_base.h"
00017 #include "newgrf_airport.h"
00018 #include "cargopacket.h"
00019 #include "industry_type.h"
00020 #include "linkgraph/linkgraph_type.h"
00021 #include "newgrf_storage.h"
00022 #include <map>
00023 
00024 typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
00025 extern StationPool _station_pool;
00026 
00027 static const byte INITIAL_STATION_RATING = 175;
00028 
00044 class LinkStat {
00045 private:
00049   uint distance;
00050 
00055   uint capacity;
00056 
00060   uint timeout;
00061 
00066   uint usage;
00067 
00068 public:
00069   static const uint MIN_DISTANCE = 48;          
00070   static const uint MOVING_AVERAGE_LENGTH = 30; 
00071 
00072   friend const SaveLoad *GetLinkStatDesc();
00073 
00077   LinkStat() {NOT_REACHED();}
00078 
00085   inline LinkStat(uint distance, uint capacity = 1, uint usage = 0) :
00086     distance(distance), capacity(capacity), timeout(distance), usage(usage)
00087   {
00088     assert(this->distance > 0);
00089     assert(this->usage <= this->capacity);
00090   }
00091 
00095   inline void Clear()
00096   {
00097     this->capacity = 1;
00098     this->usage = 0;
00099     this->timeout = this->distance;
00100   }
00101 
00105   inline void Decrease()
00106   {
00107     this->usage = this->usage * this->distance / (this->distance + 1);
00108     this->timeout = this->timeout * MIN_DISTANCE / (MIN_DISTANCE + 1);
00109     this->capacity = max(this->capacity * this->distance / (this->distance + 1), (uint)1);
00110     assert(this->usage <= this->capacity);
00111   }
00112 
00117   inline uint Capacity() const
00118   {
00119     return this->capacity * LinkStat::MOVING_AVERAGE_LENGTH / this->distance;
00120   }
00121 
00126   inline uint Usage() const
00127   {
00128     return this->usage * LinkStat::MOVING_AVERAGE_LENGTH / this->distance;
00129   }
00130 
00136   inline void Increase(uint capacity, uint usage)
00137   {
00138     this->timeout = this->distance;
00139     this->capacity += capacity;
00140     this->usage += usage;
00141     assert(this->usage <= this->capacity);
00142   }
00143 
00147   inline void Refresh(uint min_capacity)
00148   {
00149     this->capacity = max(this->capacity, min_capacity);
00150     this->timeout = this->distance;
00151   }
00152 
00157   inline bool IsValid() const
00158   {
00159     return this->timeout > 0;
00160   }
00161 };
00162 
00170 class FlowStat {
00171 public:
00172   typedef std::map<uint32, StationID> SharesMap;
00173 
00174   inline FlowStat() {NOT_REACHED();}
00175 
00176   inline FlowStat(StationID st, uint flow)
00177   {
00178     assert(flow > 0);
00179     this->shares[flow] = st;
00180   }
00181 
00187   inline void AddShare(StationID st, uint flow)
00188   {
00189     assert(flow > 0);
00190     this->shares[(--this->shares.end())->first + flow] = st;
00191   }
00192 
00193   uint GetShare(StationID st) const;
00194 
00195   void EraseShare(StationID st);
00196 
00197   inline const SharesMap *GetShares() const {return &this->shares;}
00198 
00206   inline StationID GetVia() const
00207   {
00208     assert(!this->shares.empty());
00209     return this->shares.upper_bound(RandomRange((--this->shares.end())->first - 1))->second;
00210   }
00211 
00212   StationID GetVia(StationID excluded) const;
00213 
00214 private:
00215   SharesMap shares;  
00216 };
00217 
00218 typedef std::map<StationID, LinkStat> LinkStatMap;
00219 typedef std::map<StationID, FlowStat> FlowStatMap; 
00220 
00221 uint GetMovingAverageLength(const Station *from, const Station *to);
00222 
00226 struct GoodsEntry {
00228   enum GoodsEntryStatus {
00229     GES_ACCEPTANCE,       
00230     GES_PICKUP,           
00231     GES_EVER_ACCEPTED,    
00232     GES_LAST_MONTH,       
00233     GES_CURRENT_MONTH,    
00234     GES_ACCEPTED_BIGTICK, 
00235   };
00236 
00237   GoodsEntry() :
00238     acceptance_pickup(0),
00239     days_since_pickup(255),
00240     rating(INITIAL_STATION_RATING),
00241     last_speed(0),
00242     last_age(255),
00243     supply(0),
00244     supply_new(0),
00245     last_component(INVALID_LINKGRAPH_COMPONENT),
00246     max_waiting_cargo(0)
00247   {}
00248 
00249   byte acceptance_pickup; 
00250   byte days_since_pickup; 
00251   byte rating;            
00252   byte last_speed;        
00253   byte last_age;          
00254   byte amount_fract;      
00255   StationCargoList cargo; 
00256   uint supply;            
00257   uint supply_new;        
00258   FlowStatMap flows;      
00259   LinkStatMap link_stats; 
00260   LinkGraphComponentID last_component; 
00261   uint max_waiting_cargo;              
00262 
00263   uint GetSumFlowVia(StationID via) const;
00264 
00265   inline StationID GetVia(StationID source, StationID excluded = INVALID_STATION) const
00266   {
00267     FlowStatMap::const_iterator flow_it(this->flows.find(source));
00268     return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded) : INVALID_STATION;
00269   }
00270 };
00271 
00273 struct Airport : public TileArea {
00274   Airport() : TileArea(INVALID_TILE, 0, 0) {}
00275 
00276   uint64 flags;       
00277   byte type;          
00278   byte layout;        
00279   Direction rotation; 
00280 
00281   PersistentStorage *psa; 
00282 
00288   const AirportSpec *GetSpec() const
00289   {
00290     if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00291     return AirportSpec::Get(this->type);
00292   }
00293 
00300   const AirportFTAClass *GetFTA() const
00301   {
00302     return this->GetSpec()->fsm;
00303   }
00304 
00306   inline bool HasHangar() const
00307   {
00308     return this->GetSpec()->nof_depots > 0;
00309   }
00310 
00319   inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00320   {
00321     const AirportSpec *as = this->GetSpec();
00322     switch (this->rotation) {
00323       case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00324 
00325       case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00326 
00327       case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00328 
00329       case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00330 
00331       default: NOT_REACHED();
00332     }
00333   }
00334 
00341   inline TileIndex GetHangarTile(uint hangar_num) const
00342   {
00343     const AirportSpec *as = this->GetSpec();
00344     for (uint i = 0; i < as->nof_depots; i++) {
00345       if (as->depot_table[i].hangar_num == hangar_num) {
00346         return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00347       }
00348     }
00349     NOT_REACHED();
00350   }
00351 
00358   inline Direction GetHangarExitDirection(TileIndex tile) const
00359   {
00360     const AirportSpec *as = this->GetSpec();
00361     const HangarTileTable *htt = GetHangarDataByTile(tile);
00362     return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00363   }
00364 
00371   inline uint GetHangarNum(TileIndex tile) const
00372   {
00373     const HangarTileTable *htt = GetHangarDataByTile(tile);
00374     return htt->hangar_num;
00375   }
00376 
00378   inline uint GetNumHangars() const
00379   {
00380     uint num = 0;
00381     uint counted = 0;
00382     const AirportSpec *as = this->GetSpec();
00383     for (uint i = 0; i < as->nof_depots; i++) {
00384       if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00385         num++;
00386         SetBit(counted, as->depot_table[i].hangar_num);
00387       }
00388     }
00389     return num;
00390   }
00391 
00392 private:
00399   inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00400   {
00401     const AirportSpec *as = this->GetSpec();
00402     for (uint i = 0; i < as->nof_depots; i++) {
00403       if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00404         return as->depot_table + i;
00405       }
00406     }
00407     NOT_REACHED();
00408   }
00409 };
00410 
00411 typedef SmallVector<Industry *, 2> IndustryVector;
00412 
00414 struct Station FINAL : SpecializedStation<Station, false> {
00415 public:
00416   RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00417   {
00418     return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00419   }
00420 
00421   RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00422 
00423   RoadStop *bus_stops;    
00424   TileArea bus_station;   
00425   RoadStop *truck_stops;  
00426   TileArea truck_station; 
00427 
00428   Airport airport;        
00429   TileIndex dock_tile;    
00430 
00431   IndustryType indtype;   
00432 
00433   StationHadVehicleOfTypeByte had_vehicle_of_type;
00434 
00435   byte time_since_load;
00436   byte time_since_unload;
00437 
00438   byte last_vehicle_type;
00439   std::list<Vehicle *> loading_vehicles;
00440   GoodsEntry goods[NUM_CARGO];  
00441   uint32 always_accepted;       
00442 
00443   IndustryVector industries_near; 
00444 
00445   Station(TileIndex tile = INVALID_TILE);
00446   ~Station();
00447 
00448   void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00449 
00450   void MarkTilesDirty(bool cargo_change) const;
00451 
00452   void UpdateVirtCoord();
00453 
00454   /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00455   /* virtual */ uint GetPlatformLength(TileIndex tile) const;
00456   void RecomputeIndustriesNear();
00457   static void RecomputeIndustriesNearForAll();
00458 
00459   uint GetCatchmentRadius() const;
00460   Rect GetCatchmentRect() const;
00461 
00462   /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const
00463   {
00464     return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00465   }
00466 
00467   inline bool TileBelongsToAirport(TileIndex tile) const
00468   {
00469     return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00470   }
00471 
00472   /* virtual */ uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00473 
00474   /* virtual */ void GetTileArea(TileArea *ta, StationType type) const;
00475 
00476   void RunAverages();
00477 };
00478 
00479 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00480 
00482 class AirportTileIterator : public OrthogonalTileIterator {
00483 private:
00484   const Station *st; 
00485 
00486 public:
00491   AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00492   {
00493     if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00494   }
00495 
00496   inline TileIterator& operator ++()
00497   {
00498     (*this).OrthogonalTileIterator::operator++();
00499     while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00500       (*this).OrthogonalTileIterator::operator++();
00501     }
00502     return *this;
00503   }
00504 
00505   virtual TileIterator *Clone() const
00506   {
00507     return new AirportTileIterator(*this);
00508   }
00509 };
00510 
00511 #endif /* STATION_BASE_H */