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), 1U);
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, StationID excluded2 = INVALID_STATION) 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 {
00233     GES_ACCEPTANCE,
00234 
00242     GES_PICKUP,
00243 
00248     GES_EVER_ACCEPTED,
00249 
00254     GES_LAST_MONTH,
00255 
00260     GES_CURRENT_MONTH,
00261 
00266     GES_ACCEPTED_BIGTICK,
00267   };
00268 
00269   GoodsEntry() :
00270     acceptance_pickup(0),
00271     time_since_pickup(255),
00272     rating(INITIAL_STATION_RATING),
00273     last_speed(0),
00274     last_age(255),
00275     supply(0),
00276     supply_new(0),
00277     last_component(INVALID_LINKGRAPH_COMPONENT),
00278     max_waiting_cargo(0)
00279   {}
00280 
00281   byte acceptance_pickup; 
00282 
00288   byte time_since_pickup;
00289 
00290   byte rating;            
00291 
00301   byte last_speed;
00302 
00307   byte last_age;
00308 
00309   byte amount_fract;      
00310   StationCargoList cargo; 
00311 
00312   uint supply;            
00313   uint supply_new;        
00314   FlowStatMap flows;      
00315   LinkStatMap link_stats; 
00316 
00317   LinkGraphComponentID last_component; 
00318   uint max_waiting_cargo;              
00319 
00325   bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; }
00326   uint GetSumFlowVia(StationID via) const;
00327 
00334   inline StationID GetVia(StationID source) const
00335   {
00336     FlowStatMap::const_iterator flow_it(this->flows.find(source));
00337     return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION;
00338   }
00339 
00348   inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const
00349   {
00350     FlowStatMap::const_iterator flow_it(this->flows.find(source));
00351     return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION;
00352   }
00353 };
00354 
00356 struct Airport : public TileArea {
00357   Airport() : TileArea(INVALID_TILE, 0, 0) {}
00358 
00359   uint64 flags;       
00360   byte type;          
00361   byte layout;        
00362   Direction rotation; 
00363 
00364   PersistentStorage *psa; 
00365 
00371   const AirportSpec *GetSpec() const
00372   {
00373     if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00374     return AirportSpec::Get(this->type);
00375   }
00376 
00383   const AirportFTAClass *GetFTA() const
00384   {
00385     return this->GetSpec()->fsm;
00386   }
00387 
00389   inline bool HasHangar() const
00390   {
00391     return this->GetSpec()->nof_depots > 0;
00392   }
00393 
00402   inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00403   {
00404     const AirportSpec *as = this->GetSpec();
00405     switch (this->rotation) {
00406       case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00407 
00408       case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00409 
00410       case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00411 
00412       case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00413 
00414       default: NOT_REACHED();
00415     }
00416   }
00417 
00424   inline TileIndex GetHangarTile(uint hangar_num) const
00425   {
00426     const AirportSpec *as = this->GetSpec();
00427     for (uint i = 0; i < as->nof_depots; i++) {
00428       if (as->depot_table[i].hangar_num == hangar_num) {
00429         return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00430       }
00431     }
00432     NOT_REACHED();
00433   }
00434 
00441   inline Direction GetHangarExitDirection(TileIndex tile) const
00442   {
00443     const AirportSpec *as = this->GetSpec();
00444     const HangarTileTable *htt = GetHangarDataByTile(tile);
00445     return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00446   }
00447 
00454   inline uint GetHangarNum(TileIndex tile) const
00455   {
00456     const HangarTileTable *htt = GetHangarDataByTile(tile);
00457     return htt->hangar_num;
00458   }
00459 
00461   inline uint GetNumHangars() const
00462   {
00463     uint num = 0;
00464     uint counted = 0;
00465     const AirportSpec *as = this->GetSpec();
00466     for (uint i = 0; i < as->nof_depots; i++) {
00467       if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00468         num++;
00469         SetBit(counted, as->depot_table[i].hangar_num);
00470       }
00471     }
00472     return num;
00473   }
00474 
00475 private:
00482   inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00483   {
00484     const AirportSpec *as = this->GetSpec();
00485     for (uint i = 0; i < as->nof_depots; i++) {
00486       if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00487         return as->depot_table + i;
00488       }
00489     }
00490     NOT_REACHED();
00491   }
00492 };
00493 
00494 typedef SmallVector<Industry *, 2> IndustryVector;
00495 
00497 struct Station FINAL : SpecializedStation<Station, false> {
00498 public:
00499   RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00500   {
00501     return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00502   }
00503 
00504   RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00505 
00506   RoadStop *bus_stops;    
00507   TileArea bus_station;   
00508   RoadStop *truck_stops;  
00509   TileArea truck_station; 
00510 
00511   Airport airport;        
00512   TileIndex dock_tile;    
00513 
00514   IndustryType indtype;   
00515 
00516   StationHadVehicleOfTypeByte had_vehicle_of_type;
00517 
00518   byte time_since_load;
00519   byte time_since_unload;
00520 
00521   byte last_vehicle_type;
00522   std::list<Vehicle *> loading_vehicles;
00523   GoodsEntry goods[NUM_CARGO];  
00524   uint32 always_accepted;       
00525 
00526   IndustryVector industries_near; 
00527 
00528   Station(TileIndex tile = INVALID_TILE);
00529   ~Station();
00530 
00531   void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00532 
00533   void MarkTilesDirty(bool cargo_change) const;
00534 
00535   void UpdateVirtCoord();
00536 
00537   /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00538   /* virtual */ uint GetPlatformLength(TileIndex tile) const;
00539   void RecomputeIndustriesNear();
00540   static void RecomputeIndustriesNearForAll();
00541 
00542   uint GetCatchmentRadius() const;
00543   Rect GetCatchmentRect() const;
00544 
00545   /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const
00546   {
00547     return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00548   }
00549 
00550   inline bool TileBelongsToAirport(TileIndex tile) const
00551   {
00552     return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00553   }
00554 
00555   /* virtual */ uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00556 
00557   /* virtual */ void GetTileArea(TileArea *ta, StationType type) const;
00558 
00559   void RunAverages();
00560 };
00561 
00562 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00563 
00565 class AirportTileIterator : public OrthogonalTileIterator {
00566 private:
00567   const Station *st; 
00568 
00569 public:
00574   AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00575   {
00576     if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00577   }
00578 
00579   inline TileIterator& operator ++()
00580   {
00581     (*this).OrthogonalTileIterator::operator++();
00582     while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00583       (*this).OrthogonalTileIterator::operator++();
00584     }
00585     return *this;
00586   }
00587 
00588   virtual TileIterator *Clone() const
00589   {
00590     return new AirportTileIterator(*this);
00591   }
00592 };
00593 
00594 #endif /* STATION_BASE_H */