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 <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 uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00538 uint GetPlatformLength(TileIndex tile) const;
00539 void RecomputeIndustriesNear();
00540 static void RecomputeIndustriesNearForAll();
00541
00542 uint GetCatchmentRadius() const;
00543 Rect GetCatchmentRect() const;
00544
00545 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 uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00556
00557 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