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