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