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) 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 
00336   inline StationID GetVia(StationID source, StationID excluded = INVALID_STATION) const
00337   {
00338     FlowStatMap::const_iterator flow_it(this->flows.find(source));
00339     return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded) : INVALID_STATION;
00340   }
00341 };
00342 
00344 struct Airport : public TileArea {
00345   Airport() : TileArea(INVALID_TILE, 0, 0) {}
00346 
00347   uint64 flags;       
00348   byte type;          
00349   byte layout;        
00350   Direction rotation; 
00351 
00352   PersistentStorage *psa; 
00353 
00359   const AirportSpec *GetSpec() const
00360   {
00361     if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00362     return AirportSpec::Get(this->type);
00363   }
00364 
00371   const AirportFTAClass *GetFTA() const
00372   {
00373     return this->GetSpec()->fsm;
00374   }
00375 
00377   inline bool HasHangar() const
00378   {
00379     return this->GetSpec()->nof_depots > 0;
00380   }
00381 
00390   inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00391   {
00392     const AirportSpec *as = this->GetSpec();
00393     switch (this->rotation) {
00394       case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00395 
00396       case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00397 
00398       case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00399 
00400       case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00401 
00402       default: NOT_REACHED();
00403     }
00404   }
00405 
00412   inline TileIndex GetHangarTile(uint hangar_num) const
00413   {
00414     const AirportSpec *as = this->GetSpec();
00415     for (uint i = 0; i < as->nof_depots; i++) {
00416       if (as->depot_table[i].hangar_num == hangar_num) {
00417         return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00418       }
00419     }
00420     NOT_REACHED();
00421   }
00422 
00429   inline Direction GetHangarExitDirection(TileIndex tile) const
00430   {
00431     const AirportSpec *as = this->GetSpec();
00432     const HangarTileTable *htt = GetHangarDataByTile(tile);
00433     return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00434   }
00435 
00442   inline uint GetHangarNum(TileIndex tile) const
00443   {
00444     const HangarTileTable *htt = GetHangarDataByTile(tile);
00445     return htt->hangar_num;
00446   }
00447 
00449   inline uint GetNumHangars() const
00450   {
00451     uint num = 0;
00452     uint counted = 0;
00453     const AirportSpec *as = this->GetSpec();
00454     for (uint i = 0; i < as->nof_depots; i++) {
00455       if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00456         num++;
00457         SetBit(counted, as->depot_table[i].hangar_num);
00458       }
00459     }
00460     return num;
00461   }
00462 
00463 private:
00470   inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00471   {
00472     const AirportSpec *as = this->GetSpec();
00473     for (uint i = 0; i < as->nof_depots; i++) {
00474       if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00475         return as->depot_table + i;
00476       }
00477     }
00478     NOT_REACHED();
00479   }
00480 };
00481 
00482 typedef SmallVector<Industry *, 2> IndustryVector;
00483 
00485 struct Station FINAL : SpecializedStation<Station, false> {
00486 public:
00487   RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00488   {
00489     return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00490   }
00491 
00492   RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00493 
00494   RoadStop *bus_stops;    
00495   TileArea bus_station;   
00496   RoadStop *truck_stops;  
00497   TileArea truck_station; 
00498 
00499   Airport airport;        
00500   TileIndex dock_tile;    
00501 
00502   IndustryType indtype;   
00503 
00504   StationHadVehicleOfTypeByte had_vehicle_of_type;
00505 
00506   byte time_since_load;
00507   byte time_since_unload;
00508 
00509   byte last_vehicle_type;
00510   std::list<Vehicle *> loading_vehicles;
00511   GoodsEntry goods[NUM_CARGO];  
00512   uint32 always_accepted;       
00513 
00514   IndustryVector industries_near; 
00515 
00516   Station(TileIndex tile = INVALID_TILE);
00517   ~Station();
00518 
00519   void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00520 
00521   void MarkTilesDirty(bool cargo_change) const;
00522 
00523   void UpdateVirtCoord();
00524 
00525   /* virtual */ uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00526   /* virtual */ uint GetPlatformLength(TileIndex tile) const;
00527   void RecomputeIndustriesNear();
00528   static void RecomputeIndustriesNearForAll();
00529 
00530   uint GetCatchmentRadius() const;
00531   Rect GetCatchmentRect() const;
00532 
00533   /* virtual */ inline bool TileBelongsToRailStation(TileIndex tile) const
00534   {
00535     return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00536   }
00537 
00538   inline bool TileBelongsToAirport(TileIndex tile) const
00539   {
00540     return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00541   }
00542 
00543   /* virtual */ uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00544 
00545   /* virtual */ void GetTileArea(TileArea *ta, StationType type) const;
00546 
00547   void RunAverages();
00548 };
00549 
00550 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00551 
00553 class AirportTileIterator : public OrthogonalTileIterator {
00554 private:
00555   const Station *st; 
00556 
00557 public:
00562   AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00563   {
00564     if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00565   }
00566 
00567   inline TileIterator& operator ++()
00568   {
00569     (*this).OrthogonalTileIterator::operator++();
00570     while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00571       (*this).OrthogonalTileIterator::operator++();
00572     }
00573     return *this;
00574   }
00575 
00576   virtual TileIterator *Clone() const
00577   {
00578     return new AirportTileIterator(*this);
00579   }
00580 };
00581 
00582 #endif /* STATION_BASE_H */