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), (uint)1);
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 {
00229 GES_ACCEPTANCE,
00230 GES_PICKUP,
00231 GES_EVER_ACCEPTED,
00232 GES_LAST_MONTH,
00233 GES_CURRENT_MONTH,
00234 GES_ACCEPTED_BIGTICK,
00235 };
00236
00237 GoodsEntry() :
00238 acceptance_pickup(0),
00239 days_since_pickup(255),
00240 rating(INITIAL_STATION_RATING),
00241 last_speed(0),
00242 last_age(255),
00243 supply(0),
00244 supply_new(0),
00245 last_component(INVALID_LINKGRAPH_COMPONENT),
00246 max_waiting_cargo(0)
00247 {}
00248
00249 byte acceptance_pickup;
00250 byte days_since_pickup;
00251 byte rating;
00252 byte last_speed;
00253 byte last_age;
00254 byte amount_fract;
00255 StationCargoList cargo;
00256 uint supply;
00257 uint supply_new;
00258 FlowStatMap flows;
00259 LinkStatMap link_stats;
00260 LinkGraphComponentID last_component;
00261 uint max_waiting_cargo;
00262
00263 uint GetSumFlowVia(StationID via) const;
00264
00265 inline StationID GetVia(StationID source, StationID excluded = INVALID_STATION) const
00266 {
00267 FlowStatMap::const_iterator flow_it(this->flows.find(source));
00268 return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded) : INVALID_STATION;
00269 }
00270 };
00271
00273 struct Airport : public TileArea {
00274 Airport() : TileArea(INVALID_TILE, 0, 0) {}
00275
00276 uint64 flags;
00277 byte type;
00278 byte layout;
00279 Direction rotation;
00280
00281 PersistentStorage *psa;
00282
00288 const AirportSpec *GetSpec() const
00289 {
00290 if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00291 return AirportSpec::Get(this->type);
00292 }
00293
00300 const AirportFTAClass *GetFTA() const
00301 {
00302 return this->GetSpec()->fsm;
00303 }
00304
00306 inline bool HasHangar() const
00307 {
00308 return this->GetSpec()->nof_depots > 0;
00309 }
00310
00319 inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00320 {
00321 const AirportSpec *as = this->GetSpec();
00322 switch (this->rotation) {
00323 case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00324
00325 case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00326
00327 case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00328
00329 case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00330
00331 default: NOT_REACHED();
00332 }
00333 }
00334
00341 inline TileIndex GetHangarTile(uint hangar_num) const
00342 {
00343 const AirportSpec *as = this->GetSpec();
00344 for (uint i = 0; i < as->nof_depots; i++) {
00345 if (as->depot_table[i].hangar_num == hangar_num) {
00346 return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00347 }
00348 }
00349 NOT_REACHED();
00350 }
00351
00358 inline Direction GetHangarExitDirection(TileIndex tile) const
00359 {
00360 const AirportSpec *as = this->GetSpec();
00361 const HangarTileTable *htt = GetHangarDataByTile(tile);
00362 return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00363 }
00364
00371 inline uint GetHangarNum(TileIndex tile) const
00372 {
00373 const HangarTileTable *htt = GetHangarDataByTile(tile);
00374 return htt->hangar_num;
00375 }
00376
00378 inline uint GetNumHangars() const
00379 {
00380 uint num = 0;
00381 uint counted = 0;
00382 const AirportSpec *as = this->GetSpec();
00383 for (uint i = 0; i < as->nof_depots; i++) {
00384 if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00385 num++;
00386 SetBit(counted, as->depot_table[i].hangar_num);
00387 }
00388 }
00389 return num;
00390 }
00391
00392 private:
00399 inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00400 {
00401 const AirportSpec *as = this->GetSpec();
00402 for (uint i = 0; i < as->nof_depots; i++) {
00403 if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00404 return as->depot_table + i;
00405 }
00406 }
00407 NOT_REACHED();
00408 }
00409 };
00410
00411 typedef SmallVector<Industry *, 2> IndustryVector;
00412
00414 struct Station FINAL : SpecializedStation<Station, false> {
00415 public:
00416 RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00417 {
00418 return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00419 }
00420
00421 RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00422
00423 RoadStop *bus_stops;
00424 TileArea bus_station;
00425 RoadStop *truck_stops;
00426 TileArea truck_station;
00427
00428 Airport airport;
00429 TileIndex dock_tile;
00430
00431 IndustryType indtype;
00432
00433 StationHadVehicleOfTypeByte had_vehicle_of_type;
00434
00435 byte time_since_load;
00436 byte time_since_unload;
00437
00438 byte last_vehicle_type;
00439 std::list<Vehicle *> loading_vehicles;
00440 GoodsEntry goods[NUM_CARGO];
00441 uint32 always_accepted;
00442
00443 IndustryVector industries_near;
00444
00445 Station(TileIndex tile = INVALID_TILE);
00446 ~Station();
00447
00448 void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00449
00450 void MarkTilesDirty(bool cargo_change) const;
00451
00452 void UpdateVirtCoord();
00453
00454 uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00455 uint GetPlatformLength(TileIndex tile) const;
00456 void RecomputeIndustriesNear();
00457 static void RecomputeIndustriesNearForAll();
00458
00459 uint GetCatchmentRadius() const;
00460 Rect GetCatchmentRect() const;
00461
00462 inline bool TileBelongsToRailStation(TileIndex tile) const
00463 {
00464 return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00465 }
00466
00467 inline bool TileBelongsToAirport(TileIndex tile) const
00468 {
00469 return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00470 }
00471
00472 uint32 GetNewGRFVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) const;
00473
00474 void GetTileArea(TileArea *ta, StationType type) const;
00475
00476 void RunAverages();
00477 };
00478
00479 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00480
00482 class AirportTileIterator : public OrthogonalTileIterator {
00483 private:
00484 const Station *st;
00485
00486 public:
00491 AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00492 {
00493 if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00494 }
00495
00496 inline TileIterator& operator ++()
00497 {
00498 (*this).OrthogonalTileIterator::operator++();
00499 while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00500 (*this).OrthogonalTileIterator::operator++();
00501 }
00502 return *this;
00503 }
00504
00505 virtual TileIterator *Clone() const
00506 {
00507 return new AirportTileIterator(*this);
00508 }
00509 };
00510
00511 #endif