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