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 "moving_average.h"
00023 #include <map>
00024 
00025 typedef Pool<BaseStation, StationID, 32, 64000> StationPool;
00026 extern StationPool _station_pool;
00027 
00028 static const byte INITIAL_STATION_RATING = 175;
00029 
00038 class LinkStat : private MovingAverage<uint> {
00039 private:
00044   uint capacity;
00045 
00049   uint timeout;
00050 
00055   uint usage;
00056 
00057 public:
00061   static const uint MIN_AVERAGE_LENGTH = 48;
00062 
00063   friend const SaveLoad *GetLinkStatDesc();
00064 
00068   LinkStat() : MovingAverage<uint>(0) {NOT_REACHED();}
00069 
00076   inline LinkStat(uint distance, uint capacity = 1, uint usage = 0) :
00077     MovingAverage<uint>(distance), capacity(capacity), timeout(distance), usage(usage)
00078   {
00079     assert(this->usage <= this->capacity);
00080   }
00081 
00085   inline void Clear()
00086   {
00087     this->capacity = 1;
00088     this->usage = 0;
00089     this->timeout = this->length;
00090   }
00091 
00095   inline void Decrease()
00096   {
00097     this->MovingAverage<uint>::Decrease(this->usage);
00098     this->timeout = this->timeout * MIN_AVERAGE_LENGTH / (MIN_AVERAGE_LENGTH + 1);
00099     this->capacity = max(this->MovingAverage<uint>::Decrease(this->capacity), (uint)1);
00100     assert(this->usage <= this->capacity);
00101   }
00102 
00107   inline uint Capacity() const
00108   {
00109     return this->MovingAverage<uint>::Monthly(this->capacity);
00110   }
00111 
00116   inline uint Usage() const
00117   {
00118     return this->MovingAverage<uint>::Monthly(this->usage);
00119   }
00120 
00126   inline void Increase(uint capacity, uint usage)
00127   {
00128     this->timeout = this->length;
00129     this->capacity += capacity;
00130     this->usage += usage;
00131     assert(this->usage <= this->capacity);
00132   }
00133 
00137   inline void Refresh(uint min_capacity)
00138   {
00139     this->capacity = max(this->capacity, min_capacity);
00140     this->timeout = this->length;
00141   }
00142 
00147   inline bool IsValid() const
00148   {
00149     return this->timeout > 0;
00150   }
00151 };
00152 
00160 class FlowStat {
00161 public:
00162   typedef std::map<uint32, StationID> SharesMap;
00163 
00164   inline FlowStat() {NOT_REACHED();}
00165   
00166   inline FlowStat(StationID st, uint flow)
00167   {
00168     assert(flow > 0);
00169     this->shares[flow] = st;
00170   }
00171 
00177   inline void AddShare(StationID st, uint flow)
00178   {
00179     assert(flow > 0);
00180     this->shares[(--this->shares.end())->first + flow] = st;
00181   }
00182   
00183   uint GetShare(StationID st) const;
00184   
00185   void EraseShare(StationID st);
00186   
00187   inline const SharesMap *GetShares() const {return &this->shares;}
00188 
00196   inline StationID GetVia() const
00197   {
00198     assert(!this->shares.empty());
00199     return this->shares.upper_bound(RandomRange((--this->shares.end())->first - 1))->second;
00200   }
00201 
00202   StationID GetVia(StationID excluded) const;
00203 
00204 private:
00205   SharesMap shares;  
00206 };
00207 
00208 typedef std::map<StationID, LinkStat> LinkStatMap;
00209 typedef std::map<StationID, FlowStat> FlowStatMap; 
00210 
00211 uint GetMovingAverageLength(const Station *from, const Station *to);
00212 
00216 struct GoodsEntry {
00218   enum GoodsEntryStatus {
00219     GES_ACCEPTANCE,       
00220     GES_PICKUP,           
00221     GES_EVER_ACCEPTED,    
00222     GES_LAST_MONTH,       
00223     GES_CURRENT_MONTH,    
00224     GES_ACCEPTED_BIGTICK, 
00225   };
00226 
00227   GoodsEntry() :
00228     acceptance_pickup(0),
00229     days_since_pickup(255),
00230     rating(INITIAL_STATION_RATING),
00231     last_speed(0),
00232     last_age(255),
00233     supply(0),
00234     supply_new(0),
00235     last_component(INVALID_LINKGRAPH_COMPONENT),
00236     max_waiting_cargo(0)
00237   {}
00238 
00239   byte acceptance_pickup; 
00240   byte days_since_pickup; 
00241   byte rating;            
00242   byte last_speed;        
00243   byte last_age;          
00244   byte amount_fract;      
00245   StationCargoList cargo; 
00246   uint supply;            
00247   uint supply_new;        
00248   FlowStatMap flows;      
00249   LinkStatMap link_stats; 
00250   LinkGraphComponentID last_component; 
00251   uint max_waiting_cargo;              
00252 
00253   uint GetSumFlowVia(StationID via) const;
00254 
00255   inline StationID GetVia(StationID source, StationID excluded = INVALID_STATION) const
00256   {
00257     FlowStatMap::const_iterator flow_it(this->flows.find(source));
00258     return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded) : INVALID_STATION;
00259   }
00260 };
00261 
00263 struct Airport : public TileArea {
00264   Airport() : TileArea(INVALID_TILE, 0, 0) {}
00265 
00266   uint64 flags;       
00267   byte type;          
00268   byte layout;        
00269   Direction rotation; 
00270 
00271   PersistentStorage *psa; 
00272 
00278   const AirportSpec *GetSpec() const
00279   {
00280     if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00281     return AirportSpec::Get(this->type);
00282   }
00283 
00290   const AirportFTAClass *GetFTA() const
00291   {
00292     return this->GetSpec()->fsm;
00293   }
00294 
00296   inline bool HasHangar() const
00297   {
00298     return this->GetSpec()->nof_depots > 0;
00299   }
00300 
00309   inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00310   {
00311     const AirportSpec *as = this->GetSpec();
00312     switch (this->rotation) {
00313       case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00314 
00315       case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00316 
00317       case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00318 
00319       case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00320 
00321       default: NOT_REACHED();
00322     }
00323   }
00324 
00331   inline TileIndex GetHangarTile(uint hangar_num) const
00332   {
00333     const AirportSpec *as = this->GetSpec();
00334     for (uint i = 0; i < as->nof_depots; i++) {
00335       if (as->depot_table[i].hangar_num == hangar_num) {
00336         return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00337       }
00338     }
00339     NOT_REACHED();
00340   }
00341 
00348   inline Direction GetHangarExitDirection(TileIndex tile) const
00349   {
00350     const AirportSpec *as = this->GetSpec();
00351     const HangarTileTable *htt = GetHangarDataByTile(tile);
00352     return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00353   }
00354 
00361   inline uint GetHangarNum(TileIndex tile) const
00362   {
00363     const HangarTileTable *htt = GetHangarDataByTile(tile);
00364     return htt->hangar_num;
00365   }
00366 
00368   inline uint GetNumHangars() const
00369   {
00370     uint num = 0;
00371     uint counted = 0;
00372     const AirportSpec *as = this->GetSpec();
00373     for (uint i = 0; i < as->nof_depots; i++) {
00374       if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00375         num++;
00376         SetBit(counted, as->depot_table[i].hangar_num);
00377       }
00378     }
00379     return num;
00380   }
00381 
00382 private:
00389   inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00390   {
00391     const AirportSpec *as = this->GetSpec();
00392     for (uint i = 0; i < as->nof_depots; i++) {
00393       if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00394         return as->depot_table + i;
00395       }
00396     }
00397     NOT_REACHED();
00398   }
00399 };
00400 
00401 typedef SmallVector<Industry *, 2> IndustryVector;
00402 
00404 struct Station FINAL : SpecializedStation<Station, false> {
00405 public:
00406   RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00407   {
00408     return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00409   }
00410 
00411   RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00412 
00413   RoadStop *bus_stops;    
00414   TileArea bus_station;   
00415   RoadStop *truck_stops;  
00416   TileArea truck_station; 
00417 
00418   Airport airport;        
00419   TileIndex dock_tile;    
00420 
00421   IndustryType indtype;   
00422 
00423   StationHadVehicleOfTypeByte had_vehicle_of_type;
00424 
00425   byte time_since_load;
00426   byte time_since_unload;
00427 
00428   byte last_vehicle_type;
00429   std::list<Vehicle *> loading_vehicles;
00430   GoodsEntry goods[NUM_CARGO];  
00431   uint32 always_accepted;       
00432 
00433   IndustryVector industries_near; 
00434 
00435   Station(TileIndex tile = INVALID_TILE);
00436   ~Station();
00437 
00438   void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00439 
00440   void MarkTilesDirty(bool cargo_change) const;
00441 
00442   void UpdateVirtCoord();
00443 
00444   /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00445   /* virtual */ uint GetPlatformLength(TileIndex tile) const;
00446   void RecomputeIndustriesNear();
00447   static void RecomputeIndustriesNearForAll();
00448 
00449   uint GetCatchmentRadius() const;
00450   Rect GetCatchmentRect() const;
00451 
00452   /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const
00453   {
00454     return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00455   }
00456 
00457   inline bool TileBelongsToAirport(TileIndex tile) const
00458   {
00459     return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00460   }
00461 
00462   /* virtual */ uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00463 
00464   /* virtual */ void GetTileArea(TileArea *ta, StationType type) const;
00465 
00466   void RunAverages();
00467 };
00468 
00469 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00470 
00472 class AirportTileIterator : public OrthogonalTileIterator {
00473 private:
00474   const Station *st; 
00475 
00476 public:
00481   AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00482   {
00483     if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00484   }
00485 
00486   inline TileIterator& operator ++()
00487   {
00488     (*this).OrthogonalTileIterator::operator++();
00489     while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00490       (*this).OrthogonalTileIterator::operator++();
00491     }
00492     return *this;
00493   }
00494 
00495   virtual TileIterator *Clone() const
00496   {
00497     return new AirportTileIterator(*this);
00498   }
00499 };
00500 
00501 #endif /* STATION_BASE_H */