2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 /** @file script_station.cpp Implementation of ScriptStation. */
10 #include "../../stdafx.h"
11 #include "script_station.hpp"
12 #include "script_map.hpp"
13 #include "script_town.hpp"
14 #include "script_cargo.hpp"
15 #include "../../station_base.h"
16 #include "../../roadstop_base.h"
17 #include "../../town.h"
18 #include "../../station_cmd.h"
20 #include "../../safeguards.h"
22 /* static */ bool ScriptStation::IsValidStation(StationID station_id
)
24 EnforceDeityOrCompanyModeValid(false);
25 const Station
*st
= ::Station::GetIfValid(station_id
);
26 return st
!= nullptr && (st
->owner
== ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st
->owner
== OWNER_NONE
);
29 /* static */ ScriptCompany::CompanyID
ScriptStation::GetOwner(StationID station_id
)
31 if (!IsValidStation(station_id
)) return ScriptCompany::COMPANY_INVALID
;
33 return static_cast<ScriptCompany::CompanyID
>((int)::Station::Get(station_id
)->owner
);
36 /* static */ StationID
ScriptStation::GetStationID(TileIndex tile
)
38 if (!::IsValidTile(tile
) || !::IsTileType(tile
, MP_STATION
)) return INVALID_STATION
;
39 return ::GetStationIndex(tile
);
42 template <bool Tfrom
, bool Tvia
>
43 /* static */ bool ScriptStation::IsCargoRequestValid(StationID station_id
,
44 StationID from_station_id
, StationID via_station_id
, CargoID cargo_id
)
46 if (!IsValidStation(station_id
)) return false;
47 if (Tfrom
&& !IsValidStation(from_station_id
) && from_station_id
!= STATION_INVALID
) return false;
48 if (Tvia
&& !IsValidStation(via_station_id
) && via_station_id
!= STATION_INVALID
) return false;
49 if (!ScriptCargo::IsValidCargo(cargo_id
)) return false;
53 template <bool Tfrom
, bool Tvia
>
54 /* static */ SQInteger
ScriptStation::CountCargoWaiting(StationID station_id
,
55 StationID from_station_id
, StationID via_station_id
, CargoID cargo_id
)
57 if (!ScriptStation::IsCargoRequestValid
<Tfrom
, Tvia
>(station_id
, from_station_id
,
58 via_station_id
, cargo_id
)) {
62 const ::GoodsEntry
&goods
= ::Station::Get(station_id
)->goods
[cargo_id
];
63 if (!goods
.HasData()) return 0;
65 const StationCargoList
&cargo_list
= goods
.GetData().cargo
;
66 if (!Tfrom
&& !Tvia
) return cargo_list
.TotalCount();
68 uint16_t cargo_count
= 0;
69 std::pair
<StationCargoList::ConstIterator
, StationCargoList::ConstIterator
> range
= Tvia
?
70 cargo_list
.Packets()->equal_range(via_station_id
) :
71 std::make_pair(StationCargoList::ConstIterator(cargo_list
.Packets()->begin()),
72 StationCargoList::ConstIterator(cargo_list
.Packets()->end()));
73 for (StationCargoList::ConstIterator it
= range
.first
; it
!= range
.second
; it
++) {
74 const CargoPacket
*cp
= *it
;
75 if (!Tfrom
|| cp
->GetFirstStation() == from_station_id
) cargo_count
+= cp
->Count();
81 /* static */ SQInteger
ScriptStation::GetCargoWaiting(StationID station_id
, CargoID cargo_id
)
83 return CountCargoWaiting
<false, false>(station_id
, STATION_INVALID
, STATION_INVALID
, cargo_id
);
86 /* static */ SQInteger
ScriptStation::GetCargoWaitingFrom(StationID station_id
,
87 StationID from_station_id
, CargoID cargo_id
)
89 return CountCargoWaiting
<true, false>(station_id
, from_station_id
, STATION_INVALID
, cargo_id
);
92 /* static */ SQInteger
ScriptStation::GetCargoWaitingVia(StationID station_id
,
93 StationID via_station_id
, CargoID cargo_id
)
95 return CountCargoWaiting
<false, true>(station_id
, STATION_INVALID
, via_station_id
, cargo_id
);
98 /* static */ SQInteger
ScriptStation::GetCargoWaitingFromVia(StationID station_id
,
99 StationID from_station_id
, StationID via_station_id
, CargoID cargo_id
)
101 return CountCargoWaiting
<true, true>(station_id
, from_station_id
, via_station_id
, cargo_id
);
104 template <bool Tfrom
, bool Tvia
>
105 /* static */ SQInteger
ScriptStation::CountCargoPlanned(StationID station_id
,
106 StationID from_station_id
, StationID via_station_id
, CargoID cargo_id
)
108 if (!ScriptStation::IsCargoRequestValid
<Tfrom
, Tvia
>(station_id
, from_station_id
,
109 via_station_id
, cargo_id
)) {
113 const ::GoodsEntry
&goods
= ::Station::Get(station_id
)->goods
[cargo_id
];
114 if (!goods
.HasData()) return 0;
116 const FlowStatMap
&flows
= goods
.GetData().flows
;
118 return Tvia
? flows
.GetFlowFromVia(from_station_id
, via_station_id
) :
119 flows
.GetFlowFrom(from_station_id
);
121 return Tvia
? flows
.GetFlowVia(via_station_id
) : flows
.GetFlow();
125 /* static */ SQInteger
ScriptStation::GetCargoPlanned(StationID station_id
, CargoID cargo_id
)
127 return CountCargoPlanned
<false, false>(station_id
, STATION_INVALID
, STATION_INVALID
, cargo_id
);
130 /* static */ SQInteger
ScriptStation::GetCargoPlannedFrom(StationID station_id
,
131 StationID from_station_id
, CargoID cargo_id
)
133 return CountCargoPlanned
<true, false>(station_id
, from_station_id
, STATION_INVALID
, cargo_id
);
136 /* static */ SQInteger
ScriptStation::GetCargoPlannedVia(StationID station_id
,
137 StationID via_station_id
, CargoID cargo_id
)
139 return CountCargoPlanned
<false, true>(station_id
, STATION_INVALID
, via_station_id
, cargo_id
);
142 /* static */ SQInteger
ScriptStation::GetCargoPlannedFromVia(StationID station_id
,
143 StationID from_station_id
, StationID via_station_id
, CargoID cargo_id
)
145 return CountCargoPlanned
<true, true>(station_id
, from_station_id
, via_station_id
, cargo_id
);
148 /* static */ bool ScriptStation::HasCargoRating(StationID station_id
, CargoID cargo_id
)
150 if (!IsValidStation(station_id
)) return false;
151 if (!ScriptCargo::IsValidCargo(cargo_id
)) return false;
153 return ::Station::Get(station_id
)->goods
[cargo_id
].HasRating();
156 /* static */ SQInteger
ScriptStation::GetCargoRating(StationID station_id
, CargoID cargo_id
)
158 if (!ScriptStation::HasCargoRating(station_id
, cargo_id
)) return -1;
160 return ::ToPercent8(::Station::Get(station_id
)->goods
[cargo_id
].rating
);
163 /* static */ SQInteger
ScriptStation::GetCoverageRadius(ScriptStation::StationType station_type
)
165 if (station_type
== STATION_AIRPORT
) return -1;
166 if (!HasExactlyOneBit(station_type
)) return -1;
168 if (!_settings_game
.station
.modified_catchment
) return CA_UNMODIFIED
;
170 switch (station_type
) {
171 case STATION_TRAIN
: return CA_TRAIN
;
172 case STATION_TRUCK_STOP
: return CA_TRUCK
;
173 case STATION_BUS_STOP
: return CA_BUS
;
174 case STATION_DOCK
: return CA_DOCK
;
175 default: return CA_NONE
;
179 /* static */ SQInteger
ScriptStation::GetStationCoverageRadius(StationID station_id
)
181 if (!IsValidStation(station_id
)) return -1;
183 return Station::Get(station_id
)->GetCatchmentRadius();
186 /* static */ SQInteger
ScriptStation::GetDistanceManhattanToTile(StationID station_id
, TileIndex tile
)
188 if (!IsValidStation(station_id
)) return -1;
190 return ScriptMap::DistanceManhattan(tile
, GetLocation(station_id
));
193 /* static */ SQInteger
ScriptStation::GetDistanceSquareToTile(StationID station_id
, TileIndex tile
)
195 if (!IsValidStation(station_id
)) return -1;
197 return ScriptMap::DistanceSquare(tile
, GetLocation(station_id
));
200 /* static */ bool ScriptStation::IsWithinTownInfluence(StationID station_id
, TownID town_id
)
202 if (!IsValidStation(station_id
)) return false;
204 return ScriptTown::IsWithinTownInfluence(town_id
, GetLocation(station_id
));
207 /* static */ bool ScriptStation::HasStationType(StationID station_id
, StationType station_type
)
209 if (!IsValidStation(station_id
)) return false;
210 if (!HasExactlyOneBit(station_type
)) return false;
212 return (::Station::Get(station_id
)->facilities
& static_cast<StationFacility
>(station_type
)) != 0;
215 /* static */ bool ScriptStation::HasRoadType(StationID station_id
, ScriptRoad::RoadType road_type
)
217 if (!IsValidStation(station_id
)) return false;
218 if (!ScriptRoad::IsRoadTypeAvailable(road_type
)) return false;
220 for (const RoadStop
*rs
= ::Station::Get(station_id
)->GetPrimaryRoadStop(ROADSTOP_BUS
); rs
!= nullptr; rs
= rs
->next
) {
221 if (HasBit(::GetPresentRoadTypes(rs
->xy
), (::RoadType
)road_type
)) return true;
223 for (const RoadStop
*rs
= ::Station::Get(station_id
)->GetPrimaryRoadStop(ROADSTOP_TRUCK
); rs
!= nullptr; rs
= rs
->next
) {
224 if (HasBit(::GetPresentRoadTypes(rs
->xy
), (::RoadType
)road_type
)) return true;
230 /* static */ TownID
ScriptStation::GetNearestTown(StationID station_id
)
232 if (!IsValidStation(station_id
)) return INVALID_TOWN
;
234 return ::Station::Get(station_id
)->town
->index
;
237 /* static */ bool ScriptStation::IsAirportClosed(StationID station_id
)
239 EnforcePrecondition(false, IsValidStation(station_id
));
240 EnforcePrecondition(false, HasStationType(station_id
, STATION_AIRPORT
));
242 return (::Station::Get(station_id
)->airport
.flags
& AIRPORT_CLOSED_block
) != 0;
245 /* static */ bool ScriptStation::OpenCloseAirport(StationID station_id
)
247 EnforceCompanyModeValid(false);
248 EnforcePrecondition(false, IsValidStation(station_id
));
249 EnforcePrecondition(false, HasStationType(station_id
, STATION_AIRPORT
));
251 return ScriptObject::Command
<CMD_OPEN_CLOSE_AIRPORT
>::Do(station_id
);