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 "base_station_base.h"
00016 #include "newgrf_airport.h"
00017 #include "cargopacket.h"
00018 #include "industry_type.h"
00019 #include "linkgraph/linkgraph_type.h"
00020 #include "newgrf_storage.h"
00021 #include "moving_average.h"
00022 #include "town.h"
00023 #include <map>
00024 #include <set>
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 
00157 class FlowStat : private MovingAverage<uint> {
00158 private:
00159   uint planned;  
00160   uint sent;     
00161   StationID via; 
00162 
00163 public:
00164   friend const SaveLoad *GetFlowStatDesc();
00165 
00173   FORCEINLINE FlowStat(uint distance = 1, StationID st = INVALID_STATION, uint planned = 0, uint sent = 0) :
00174     MovingAverage<uint>(distance), planned(planned), sent(sent), via(st) {}
00175 
00181   FORCEINLINE FlowStat(const FlowStat &prev, uint new_plan) :
00182     MovingAverage<uint>(prev.length), planned(new_plan), sent(prev.sent), via(prev.via) {}
00183 
00187   FORCEINLINE FlowStat GetDecreasedCopy() const
00188   {
00189     FlowStat ret(this->length, this->via, this->planned, this->sent);
00190     this->MovingAverage<uint>::Decrease(ret.sent);
00191     return ret;
00192   }
00193 
00198   FORCEINLINE void Increase(uint sent)
00199   {
00200     this->sent += sent;
00201   }
00202 
00207   FORCEINLINE uint Sent() const
00208   {
00209     return this->MovingAverage<uint>::Monthly(sent);
00210   }
00211 
00216   FORCEINLINE uint Planned() const
00217   {
00218     return this->planned;
00219   }
00220 
00225   FORCEINLINE StationID Via() const
00226   {
00227     return this->via;
00228   }
00229 
00234   struct Comparator {
00242     bool operator()(const FlowStat &x, const FlowStat &y) const
00243     {
00244       int diff_x = (int)x.Planned() - (int)x.Sent();
00245       int diff_y = (int)y.Planned() - (int)y.Sent();
00246       if (diff_x != diff_y) {
00247         return diff_x > diff_y;
00248       } else {
00249         return x.Via() > y.Via();
00250       }
00251     }
00252   };
00253 
00259   FORCEINLINE FlowStat &operator+=(const FlowStat &other)
00260   {
00261     assert(this->via == INVALID_STATION || other.via == INVALID_STATION || this->via == other.via);
00262     if (other.via != INVALID_STATION) this->via = other.via;
00263     this->planned += other.planned;
00264     uint sent = this->sent + other.sent;
00265     if (sent > 0) {
00266       this->length = (this->length * this->sent + other.length * other.sent) / sent;
00267       assert(this->length > 0);
00268     }
00269     this->sent = sent;
00270     return *this;
00271   }
00272 
00276   FORCEINLINE void Clear()
00277   {
00278     this->planned = 0;
00279     this->sent = 0;
00280     this->via = INVALID_STATION;
00281   }
00282 };
00283 
00284 typedef std::set<FlowStat, FlowStat::Comparator> FlowStatSet; 
00285 
00286 typedef std::map<StationID, LinkStat> LinkStatMap;
00287 typedef std::map<StationID, FlowStatSet> FlowStatMap; 
00288 
00289 uint GetMovingAverageLength(const Station *from, const Station *to);
00290 
00294 struct GoodsEntry {
00296   enum GoodsEntryStatus {
00297     GES_ACCEPTANCE,       
00298     GES_PICKUP,           
00299     GES_EVER_ACCEPTED,    
00300     GES_LAST_MONTH,       
00301     GES_CURRENT_MONTH,    
00302     GES_ACCEPTED_BIGTICK, 
00303   };
00304 
00305   GoodsEntry() :
00306     acceptance_pickup(0),
00307     days_since_pickup(255),
00308     rating(INITIAL_STATION_RATING),
00309     last_speed(0),
00310     last_age(255),
00311     supply(0),
00312     supply_new(0),
00313     last_component(INVALID_LINKGRAPH_COMPONENT),
00314     max_waiting_cargo(0)
00315   {}
00316 
00317   byte acceptance_pickup; 
00318   byte days_since_pickup; 
00319   byte rating;            
00320   byte last_speed;        
00321   byte last_age;          
00322   byte amount_fract;      
00323   StationCargoList cargo; 
00324   uint supply;            
00325   uint supply_new;        
00326   FlowStatMap flows;      
00327   LinkStatMap link_stats; 
00328   LinkGraphComponentID last_component; 
00329   uint max_waiting_cargo;              
00330   FlowStat GetSumFlowVia(StationID via) const;
00331 
00332   void UpdateFlowStats(StationID source, uint count, StationID next);
00333   void UpdateFlowStats(FlowStatSet &flow_stats, uint count, StationID next);
00334   void UpdateFlowStats(FlowStatSet &flow_stats, FlowStatSet::iterator flow_it, uint count);
00335 
00336   StationID UpdateFlowStatsTransfer(StationID source, uint count, StationID curr);
00337 };
00338 
00340 struct Airport : public TileArea {
00341   Airport() : TileArea(INVALID_TILE, 0, 0) {}
00342 
00343   uint64 flags;       
00344   byte type;          
00345   byte layout;        
00346   Direction rotation; 
00347 
00348   PersistentStorage *psa; 
00349 
00355   const AirportSpec *GetSpec() const
00356   {
00357     if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00358     return AirportSpec::Get(this->type);
00359   }
00360 
00367   const AirportFTAClass *GetFTA() const
00368   {
00369     return this->GetSpec()->fsm;
00370   }
00371 
00373   FORCEINLINE bool HasHangar() const
00374   {
00375     return this->GetSpec()->nof_depots > 0;
00376   }
00377 
00386   FORCEINLINE TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00387   {
00388     const AirportSpec *as = this->GetSpec();
00389     switch (this->rotation) {
00390       case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00391 
00392       case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00393 
00394       case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00395 
00396       case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00397 
00398       default: NOT_REACHED();
00399     }
00400   }
00401 
00408   FORCEINLINE TileIndex GetHangarTile(uint hangar_num) const
00409   {
00410     const AirportSpec *as = this->GetSpec();
00411     for (uint i = 0; i < as->nof_depots; i++) {
00412       if (as->depot_table[i].hangar_num == hangar_num) {
00413         return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00414       }
00415     }
00416     NOT_REACHED();
00417   }
00418 
00425   FORCEINLINE Direction GetHangarExitDirection(TileIndex tile) const
00426   {
00427     const AirportSpec *as = this->GetSpec();
00428     const HangarTileTable *htt = GetHangarDataByTile(tile);
00429     return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00430   }
00431 
00438   FORCEINLINE uint GetHangarNum(TileIndex tile) const
00439   {
00440     const HangarTileTable *htt = GetHangarDataByTile(tile);
00441     return htt->hangar_num;
00442   }
00443 
00445   FORCEINLINE uint GetNumHangars() const
00446   {
00447     uint num = 0;
00448     uint counted = 0;
00449     const AirportSpec *as = this->GetSpec();
00450     for (uint i = 0; i < as->nof_depots; i++) {
00451       if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00452         num++;
00453         SetBit(counted, as->depot_table[i].hangar_num);
00454       }
00455     }
00456     return num;
00457   }
00458 
00459 private:
00466   FORCEINLINE const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00467   {
00468     const AirportSpec *as = this->GetSpec();
00469     for (uint i = 0; i < as->nof_depots; i++) {
00470       if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00471         return as->depot_table + i;
00472       }
00473     }
00474     NOT_REACHED();
00475   }
00476 };
00477 
00478 typedef SmallVector<Industry *, 2> IndustryVector;
00479 
00481 struct Station : SpecializedStation<Station, false> {
00482 public:
00483   RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00484   {
00485     return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00486   }
00487 
00488   RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00489 
00490   RoadStop *bus_stops;    
00491   TileArea bus_station;   
00492   RoadStop *truck_stops;  
00493   TileArea truck_station; 
00494 
00495   Airport airport;        
00496   TileIndex dock_tile;    
00497 
00498   IndustryType indtype;   
00499 
00500   StationHadVehicleOfTypeByte had_vehicle_of_type;
00501 
00502   byte time_since_load;
00503   byte time_since_unload;
00504 
00505   byte last_vehicle_type;
00506   std::list<Vehicle *> loading_vehicles;
00507   GoodsEntry goods[NUM_CARGO];  
00508   uint32 always_accepted;       
00509 
00510   IndustryVector industries_near; 
00511 
00512   Station(TileIndex tile = INVALID_TILE);
00513   ~Station();
00514 
00515   void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00516 
00517   void MarkTilesDirty(bool cargo_change) const;
00518 
00519   void UpdateVirtCoord();
00520 
00521   /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00522   /* virtual */ uint GetPlatformLength(TileIndex tile) const;
00523   void RecomputeIndustriesNear();
00524   static void RecomputeIndustriesNearForAll();
00525 
00526   uint GetCatchmentRadius() const;
00527   Rect GetCatchmentRect() const;
00528 
00529   /* virtual */ FORCEINLINE bool TileBelongsToRailStation(TileIndex tile) const
00530   {
00531     return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00532   }
00533 
00534   FORCEINLINE bool TileBelongsToAirport(TileIndex tile) const
00535   {
00536     return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00537   }
00538 
00539   /* virtual */ uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00540 
00541   /* virtual */ void GetTileArea(TileArea *ta, StationType type) const;
00542 
00543   void RunAverages();
00544 };
00545 
00546 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00547 
00549 class AirportTileIterator : public OrthogonalTileIterator {
00550 private:
00551   const Station *st; 
00552 
00553 public:
00558   AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00559   {
00560     if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00561   }
00562 
00563   FORCEINLINE TileIterator& operator ++()
00564   {
00565     (*this).OrthogonalTileIterator::operator++();
00566     while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00567       (*this).OrthogonalTileIterator::operator++();
00568     }
00569     return *this;
00570   }
00571 
00572   virtual TileIterator *Clone() const
00573   {
00574     return new AirportTileIterator(*this);
00575   }
00576 };
00577 
00578 #endif /* STATION_BASE_H */