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_stationlist.cpp Implementation of ScriptStationList and friends. */
10 #include "../../stdafx.h"
11 #include "script_stationlist.hpp"
12 #include "script_vehicle.hpp"
13 #include "script_cargo.hpp"
14 #include "../../station_base.h"
15 #include "../../vehicle_base.h"
17 #include "../../safeguards.h"
19 ScriptStationList::ScriptStationList(ScriptStation::StationType station_type
)
21 EnforceDeityOrCompanyModeValid_Void();
22 bool is_deity
= ScriptCompanyMode::IsDeity();
23 CompanyID owner
= ScriptObject::GetCompany();
24 ScriptList::FillList
<Station
>(this,
25 [is_deity
, owner
, station_type
](const Station
*st
) {
26 return (is_deity
|| st
->owner
== owner
) && (st
->facilities
& static_cast<StationFacility
>(station_type
)) != 0;
31 ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id
)
33 if (!ScriptVehicle::IsPrimaryVehicle(vehicle_id
)) return;
35 const Vehicle
*v
= ::Vehicle::Get(vehicle_id
);
37 for (Order
*o
= v
->GetFirstOrder(); o
!= nullptr; o
= o
->next
) {
38 if (o
->IsType(OT_GOTO_STATION
)) this->AddItem(o
->GetDestination());
42 ScriptStationList_Cargo::ScriptStationList_Cargo(ScriptStationList_Cargo::CargoMode mode
,
43 ScriptStationList_Cargo::CargoSelector selector
, StationID station_id
, CargoID cargo
,
44 StationID other_station
)
48 ScriptStationList_CargoWaiting(selector
, station_id
, cargo
, other_station
).SwapList(this);
51 ScriptStationList_CargoPlanned(selector
, station_id
, cargo
, other_station
).SwapList(this);
58 ScriptStationList_CargoWaiting::ScriptStationList_CargoWaiting(
59 ScriptStationList_Cargo::CargoSelector selector
, StationID station_id
, CargoID cargo
,
60 StationID other_station
)
64 ScriptStationList_CargoWaitingByFrom(station_id
, cargo
).SwapList(this);
67 ScriptStationList_CargoWaitingViaByFrom(station_id
, cargo
, other_station
).SwapList(this);
70 ScriptStationList_CargoWaitingByVia(station_id
, cargo
).SwapList(this);
73 ScriptStationList_CargoWaitingFromByVia(station_id
, cargo
, other_station
).SwapList(this);
80 ScriptStationList_CargoPlanned::ScriptStationList_CargoPlanned(
81 ScriptStationList_Cargo::CargoSelector selector
, StationID station_id
, CargoID cargo
,
82 StationID other_station
)
86 ScriptStationList_CargoPlannedByFrom(station_id
, cargo
).SwapList(this);
89 ScriptStationList_CargoPlannedViaByFrom(station_id
, cargo
, other_station
).SwapList(this);
92 ScriptStationList_CargoPlannedByVia(station_id
, cargo
).SwapList(this);
95 ScriptStationList_CargoPlannedFromByVia(station_id
, cargo
, other_station
).SwapList(this);
102 class CargoCollector
{
104 CargoCollector(ScriptStationList_Cargo
*parent
, StationID station_id
, CargoID cargo
,
108 template<ScriptStationList_Cargo::CargoSelector Tselector
>
109 void Update(StationID from
, StationID via
, uint amount
);
110 const GoodsEntry
*GE() const { return ge
; }
115 ScriptStationList_Cargo
*list
;
116 const GoodsEntry
*ge
;
117 StationID other_station
;
123 CargoCollector::CargoCollector(ScriptStationList_Cargo
*parent
,
124 StationID station_id
, CargoID cargo
, StationID other
) :
125 list(parent
), ge(nullptr), other_station(other
), last_key(INVALID_STATION
), amount(0)
127 if (!ScriptStation::IsValidStation(station_id
)) return;
128 if (!ScriptCargo::IsValidCargo(cargo
)) return;
129 this->ge
= &(Station::Get(station_id
)->goods
[cargo
]);
132 CargoCollector::~CargoCollector()
137 void CargoCollector::SetValue()
139 if (this->amount
> 0) {
140 if (this->list
->HasItem(this->last_key
)) {
141 this->list
->SetValue(this->last_key
,
142 this->list
->GetValue(this->last_key
) + this->amount
);
144 this->list
->AddItem(this->last_key
, this->amount
);
149 template<ScriptStationList_Cargo::CargoSelector Tselector
>
150 void CargoCollector::Update(StationID from
, StationID via
, uint amount
)
152 StationID key
= INVALID_STATION
;
154 case ScriptStationList_Cargo::CS_VIA_BY_FROM
:
155 if (via
!= this->other_station
) return;
157 case ScriptStationList_Cargo::CS_BY_FROM
:
160 case ScriptStationList_Cargo::CS_FROM_BY_VIA
:
161 if (from
!= this->other_station
) return;
163 case ScriptStationList_Cargo::CS_BY_VIA
:
167 if (key
== this->last_key
) {
168 this->amount
+= amount
;
171 this->amount
= amount
;
172 this->last_key
= key
;
177 template<ScriptStationList_Cargo::CargoSelector Tselector
>
178 void ScriptStationList_CargoWaiting::Add(StationID station_id
, CargoID cargo
, StationID other_station
)
180 CargoCollector
collector(this, station_id
, cargo
, other_station
);
181 if (collector
.GE() == nullptr) return;
183 StationCargoList::ConstIterator iter
= collector
.GE()->cargo
.Packets()->begin();
184 StationCargoList::ConstIterator end
= collector
.GE()->cargo
.Packets()->end();
185 for (; iter
!= end
; ++iter
) {
186 collector
.Update
<Tselector
>((*iter
)->GetFirstStation(), iter
.GetKey(), (*iter
)->Count());
191 template<ScriptStationList_Cargo::CargoSelector Tselector
>
192 void ScriptStationList_CargoPlanned::Add(StationID station_id
, CargoID cargo
, StationID other_station
)
194 CargoCollector
collector(this, station_id
, cargo
, other_station
);
195 if (collector
.GE() == nullptr) return;
197 FlowStatMap::const_iterator iter
= collector
.GE()->flows
.begin();
198 FlowStatMap::const_iterator end
= collector
.GE()->flows
.end();
199 for (; iter
!= end
; ++iter
) {
200 const FlowStat::SharesMap
*shares
= iter
->second
.GetShares();
202 for (FlowStat::SharesMap::const_iterator flow_iter
= shares
->begin();
203 flow_iter
!= shares
->end(); ++flow_iter
) {
204 collector
.Update
<Tselector
>(iter
->first
, flow_iter
->second
, flow_iter
->first
- prev
);
205 prev
= flow_iter
->first
;
210 ScriptStationList_CargoWaitingByFrom::ScriptStationList_CargoWaitingByFrom(StationID station_id
,
213 this->Add
<CS_BY_FROM
>(station_id
, cargo
);
216 ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom(
217 StationID station_id
, CargoID cargo
, StationID via
)
219 CargoCollector
collector(this, station_id
, cargo
, via
);
220 if (collector
.GE() == nullptr) return;
222 std::pair
<StationCargoList::ConstIterator
, StationCargoList::ConstIterator
> range
=
223 collector
.GE()->cargo
.Packets()->equal_range(via
);
224 for (StationCargoList::ConstIterator iter
= range
.first
; iter
!= range
.second
; ++iter
) {
225 collector
.Update
<CS_VIA_BY_FROM
>((*iter
)->GetFirstStation(), iter
.GetKey(), (*iter
)->Count());
230 ScriptStationList_CargoWaitingByVia::ScriptStationList_CargoWaitingByVia(StationID station_id
,
233 this->Add
<CS_BY_VIA
>(station_id
, cargo
);
236 ScriptStationList_CargoWaitingFromByVia::ScriptStationList_CargoWaitingFromByVia(
237 StationID station_id
, CargoID cargo
, StationID from
)
239 this->Add
<CS_FROM_BY_VIA
>(station_id
, cargo
, from
);
242 ScriptStationList_CargoPlannedByFrom::ScriptStationList_CargoPlannedByFrom(StationID station_id
,
245 this->Add
<CS_BY_FROM
>(station_id
, cargo
);
248 ScriptStationList_CargoPlannedViaByFrom::ScriptStationList_CargoPlannedViaByFrom(
249 StationID station_id
, CargoID cargo
, StationID via
)
251 this->Add
<CS_VIA_BY_FROM
>(station_id
, cargo
, via
);
255 ScriptStationList_CargoPlannedByVia::ScriptStationList_CargoPlannedByVia(StationID station_id
,
258 this->Add
<CS_BY_VIA
>(station_id
, cargo
);
262 ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia(
263 StationID station_id
, CargoID cargo
, StationID from
)
265 CargoCollector
collector(this, station_id
, cargo
, from
);
266 if (collector
.GE() == nullptr) return;
268 FlowStatMap::const_iterator iter
= collector
.GE()->flows
.find(from
);
269 if (iter
== collector
.GE()->flows
.end()) return;
270 const FlowStat::SharesMap
*shares
= iter
->second
.GetShares();
272 for (FlowStat::SharesMap::const_iterator flow_iter
= shares
->begin();
273 flow_iter
!= shares
->end(); ++flow_iter
) {
274 collector
.Update
<CS_FROM_BY_VIA
>(iter
->first
, flow_iter
->second
, flow_iter
->first
- prev
);
275 prev
= flow_iter
->first
;