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
00036 class FlowStat {
00037 public:
00038 typedef std::map<uint32, StationID> SharesMap;
00039
00045 inline FlowStat() {NOT_REACHED();}
00046
00053 inline FlowStat(StationID st, uint flow, bool restricted = false)
00054 {
00055 assert(flow > 0);
00056 this->shares[flow] = st;
00057 this->unrestricted = restricted ? 0 : flow;
00058 }
00059
00068 inline void AppendShare(StationID st, uint flow, bool restricted = false)
00069 {
00070 assert(flow > 0);
00071 this->shares[(--this->shares.end())->first + flow] = st;
00072 if (!restricted) this->unrestricted += flow;
00073 }
00074
00075 uint GetShare(StationID st) const;
00076
00077 void ChangeShare(StationID st, int flow);
00078
00079 void RestrictShare(StationID st);
00080
00081 void ReleaseShare(StationID st);
00082
00083 void ScaleToMonthly(uint runtime);
00084
00090 inline const SharesMap *GetShares() const { return &this->shares; }
00091
00096 inline uint GetUnrestricted() const { return this->unrestricted; }
00097
00103 inline void SwapShares(FlowStat &other)
00104 {
00105 this->shares.swap(other.shares);
00106 Swap(this->unrestricted, other.unrestricted);
00107 }
00108
00117 inline StationID GetViaWithRestricted(bool &is_restricted) const
00118 {
00119 assert(!this->shares.empty());
00120 uint rand = RandomRange((--this->shares.end())->first);
00121 is_restricted = rand >= this->unrestricted;
00122 return this->shares.upper_bound(rand)->second;
00123 }
00124
00132 inline StationID GetVia() const
00133 {
00134 assert(!this->shares.empty());
00135 return this->unrestricted > 0 ?
00136 this->shares.upper_bound(RandomRange(this->unrestricted))->second :
00137 INVALID_STATION;
00138 }
00139
00140 StationID GetVia(StationID excluded, StationID excluded2 = INVALID_STATION) const;
00141
00142 void Invalidate();
00143
00144 private:
00145 SharesMap shares;
00146 uint unrestricted;
00147 };
00148
00150 class FlowStatMap : public std::map<StationID, FlowStat> {
00151 public:
00152 void AddFlow(StationID origin, StationID via, uint amount);
00153 void PassOnFlow(StationID origin, StationID via, uint amount);
00154 StationIDStack DeleteFlows(StationID via);
00155 void RestrictFlows(StationID via);
00156 void ReleaseFlows(StationID via);
00157 void FinalizeLocalConsumption(StationID self);
00158 };
00159
00163 struct GoodsEntry {
00165 enum GoodsEntryStatus {
00170 GES_ACCEPTANCE,
00171
00179 GES_RATING,
00180
00185 GES_EVER_ACCEPTED,
00186
00191 GES_LAST_MONTH,
00192
00197 GES_CURRENT_MONTH,
00198
00203 GES_ACCEPTED_BIGTICK,
00204 };
00205
00206 GoodsEntry() :
00207 status(0),
00208 time_since_pickup(255),
00209 rating(INITIAL_STATION_RATING),
00210 last_speed(0),
00211 last_age(255),
00212 amount_fract(0),
00213 link_graph(INVALID_LINK_GRAPH),
00214 node(INVALID_NODE),
00215 max_waiting_cargo(0)
00216 {}
00217
00218 byte status;
00219
00225 byte time_since_pickup;
00226
00227 byte rating;
00228
00238 byte last_speed;
00239
00244 byte last_age;
00245
00246 byte amount_fract;
00247 StationCargoList cargo;
00248
00249 LinkGraphID link_graph;
00250 NodeID node;
00251 FlowStatMap flows;
00252 uint max_waiting_cargo;
00253
00259 bool HasVehicleEverTriedLoading() const { return this->last_speed != 0; }
00260
00265 inline bool HasRating() const
00266 {
00267 return HasBit(this->status, GES_RATING);
00268 }
00269
00270 uint GetSumFlowVia(StationID via) const;
00271
00277 inline StationID GetVia(StationID source) const
00278 {
00279 FlowStatMap::const_iterator flow_it(this->flows.find(source));
00280 return flow_it != this->flows.end() ? flow_it->second.GetVia() : INVALID_STATION;
00281 }
00282
00291 inline StationID GetVia(StationID source, StationID excluded, StationID excluded2 = INVALID_STATION) const
00292 {
00293 FlowStatMap::const_iterator flow_it(this->flows.find(source));
00294 return flow_it != this->flows.end() ? flow_it->second.GetVia(excluded, excluded2) : INVALID_STATION;
00295 }
00296 };
00297
00299 struct Airport : public TileArea {
00300 Airport() : TileArea(INVALID_TILE, 0, 0) {}
00301
00302 uint64 flags;
00303 byte type;
00304 byte layout;
00305 DirectionByte rotation;
00306
00307 PersistentStorage *psa;
00308
00314 const AirportSpec *GetSpec() const
00315 {
00316 if (this->tile == INVALID_TILE) return &AirportSpec::dummy;
00317 return AirportSpec::Get(this->type);
00318 }
00319
00326 const AirportFTAClass *GetFTA() const
00327 {
00328 return this->GetSpec()->fsm;
00329 }
00330
00332 inline bool HasHangar() const
00333 {
00334 return this->GetSpec()->nof_depots > 0;
00335 }
00336
00345 inline TileIndex GetRotatedTileFromOffset(TileIndexDiffC tidc) const
00346 {
00347 const AirportSpec *as = this->GetSpec();
00348 switch (this->rotation) {
00349 case DIR_N: return this->tile + ToTileIndexDiff(tidc);
00350
00351 case DIR_E: return this->tile + TileDiffXY(tidc.y, as->size_x - 1 - tidc.x);
00352
00353 case DIR_S: return this->tile + TileDiffXY(as->size_x - 1 - tidc.x, as->size_y - 1 - tidc.y);
00354
00355 case DIR_W: return this->tile + TileDiffXY(as->size_y - 1 - tidc.y, tidc.x);
00356
00357 default: NOT_REACHED();
00358 }
00359 }
00360
00367 inline TileIndex GetHangarTile(uint hangar_num) const
00368 {
00369 const AirportSpec *as = this->GetSpec();
00370 for (uint i = 0; i < as->nof_depots; i++) {
00371 if (as->depot_table[i].hangar_num == hangar_num) {
00372 return this->GetRotatedTileFromOffset(as->depot_table[i].ti);
00373 }
00374 }
00375 NOT_REACHED();
00376 }
00377
00384 inline Direction GetHangarExitDirection(TileIndex tile) const
00385 {
00386 const AirportSpec *as = this->GetSpec();
00387 const HangarTileTable *htt = GetHangarDataByTile(tile);
00388 return ChangeDir(htt->dir, DirDifference(this->rotation, as->rotation[0]));
00389 }
00390
00397 inline uint GetHangarNum(TileIndex tile) const
00398 {
00399 const HangarTileTable *htt = GetHangarDataByTile(tile);
00400 return htt->hangar_num;
00401 }
00402
00404 inline uint GetNumHangars() const
00405 {
00406 uint num = 0;
00407 uint counted = 0;
00408 const AirportSpec *as = this->GetSpec();
00409 for (uint i = 0; i < as->nof_depots; i++) {
00410 if (!HasBit(counted, as->depot_table[i].hangar_num)) {
00411 num++;
00412 SetBit(counted, as->depot_table[i].hangar_num);
00413 }
00414 }
00415 return num;
00416 }
00417
00418 private:
00425 inline const HangarTileTable *GetHangarDataByTile(TileIndex tile) const
00426 {
00427 const AirportSpec *as = this->GetSpec();
00428 for (uint i = 0; i < as->nof_depots; i++) {
00429 if (this->GetRotatedTileFromOffset(as->depot_table[i].ti) == tile) {
00430 return as->depot_table + i;
00431 }
00432 }
00433 NOT_REACHED();
00434 }
00435 };
00436
00437 typedef SmallVector<Industry *, 2> IndustryVector;
00438
00440 struct Station FINAL : SpecializedStation<Station, false> {
00441 public:
00442 RoadStop *GetPrimaryRoadStop(RoadStopType type) const
00443 {
00444 return type == ROADSTOP_BUS ? bus_stops : truck_stops;
00445 }
00446
00447 RoadStop *GetPrimaryRoadStop(const struct RoadVehicle *v) const;
00448
00449 RoadStop *bus_stops;
00450 TileArea bus_station;
00451 RoadStop *truck_stops;
00452 TileArea truck_station;
00453
00454 Airport airport;
00455 TileIndex dock_tile;
00456
00457 IndustryType indtype;
00458
00459 StationHadVehicleOfTypeByte had_vehicle_of_type;
00460
00461 byte time_since_load;
00462 byte time_since_unload;
00463
00464 byte last_vehicle_type;
00465 std::list<Vehicle *> loading_vehicles;
00466 GoodsEntry goods[NUM_CARGO];
00467 uint32 always_accepted;
00468
00469 IndustryVector industries_near;
00470
00471 Station(TileIndex tile = INVALID_TILE);
00472 ~Station();
00473
00474 void AddFacility(StationFacility new_facility_bit, TileIndex facil_xy);
00475
00476 void MarkTilesDirty(bool cargo_change) const;
00477
00478 void UpdateVirtCoord();
00479
00480 uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
00481 uint GetPlatformLength(TileIndex tile) const;
00482 void RecomputeIndustriesNear();
00483 static void RecomputeIndustriesNearForAll();
00484
00485 uint GetCatchmentRadius() const;
00486 Rect GetCatchmentRect() const;
00487
00488 inline bool TileBelongsToRailStation(TileIndex tile) const
00489 {
00490 return IsRailStationTile(tile) && GetStationIndex(tile) == this->index;
00491 }
00492
00493 inline bool TileBelongsToAirport(TileIndex tile) const
00494 {
00495 return IsAirportTile(tile) && GetStationIndex(tile) == this->index;
00496 }
00497
00498 uint32 GetNewGRFVariable(const ResolverObject &object, byte variable, byte parameter, bool *available) const;
00499
00500 void GetTileArea(TileArea *ta, StationType type) const;
00501 };
00502
00503 #define FOR_ALL_STATIONS(var) FOR_ALL_BASE_STATIONS_OF_TYPE(Station, var)
00504
00506 class AirportTileIterator : public OrthogonalTileIterator {
00507 private:
00508 const Station *st;
00509
00510 public:
00515 AirportTileIterator(const Station *st) : OrthogonalTileIterator(st->airport), st(st)
00516 {
00517 if (!st->TileBelongsToAirport(this->tile)) ++(*this);
00518 }
00519
00520 inline TileIterator& operator ++()
00521 {
00522 (*this).OrthogonalTileIterator::operator++();
00523 while (this->tile != INVALID_TILE && !st->TileBelongsToAirport(this->tile)) {
00524 (*this).OrthogonalTileIterator::operator++();
00525 }
00526 return *this;
00527 }
00528
00529 virtual TileIterator *Clone() const
00530 {
00531 return new AirportTileIterator(*this);
00532 }
00533 };
00534
00535 #endif