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