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