1 /*
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/>.
6 */
7
8 /** @file script_stationlist.cpp Implementation of ScriptStationList and friends. */
9
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"
16
17 #include "../../safeguards.h"
18
ScriptStationList(ScriptStation::StationType station_type)19 ScriptStationList::ScriptStationList(ScriptStation::StationType station_type)
20 {
21 for (Station *st : Station::Iterate()) {
22 if ((st->owner == ScriptObject::GetCompany() || ScriptObject::GetCompany() == OWNER_DEITY) && (st->facilities & station_type) != 0) this->AddItem(st->index);
23 }
24 }
25
ScriptStationList_Vehicle(VehicleID vehicle_id)26 ScriptStationList_Vehicle::ScriptStationList_Vehicle(VehicleID vehicle_id)
27 {
28 if (!ScriptVehicle::IsValidVehicle(vehicle_id)) return;
29
30 Vehicle *v = ::Vehicle::Get(vehicle_id);
31
32 for (Order *o = v->GetFirstOrder(); o != nullptr; o = o->next) {
33 if (o->IsType(OT_GOTO_STATION)) this->AddItem(o->GetDestination());
34 }
35 }
36
ScriptStationList_Cargo(ScriptStationList_Cargo::CargoMode mode,ScriptStationList_Cargo::CargoSelector selector,StationID station_id,CargoID cargo,StationID other_station)37 ScriptStationList_Cargo::ScriptStationList_Cargo(ScriptStationList_Cargo::CargoMode mode,
38 ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo,
39 StationID other_station)
40 {
41 switch (mode) {
42 case CM_WAITING:
43 ScriptStationList_CargoWaiting(selector, station_id, cargo, other_station).SwapList(this);
44 break;
45 case CM_PLANNED:
46 ScriptStationList_CargoPlanned(selector, station_id, cargo, other_station).SwapList(this);
47 break;
48 default:
49 NOT_REACHED();
50 }
51 }
52
ScriptStationList_CargoWaiting(ScriptStationList_Cargo::CargoSelector selector,StationID station_id,CargoID cargo,StationID other_station)53 ScriptStationList_CargoWaiting::ScriptStationList_CargoWaiting(
54 ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo,
55 StationID other_station)
56 {
57 switch (selector) {
58 case CS_BY_FROM:
59 ScriptStationList_CargoWaitingByFrom(station_id, cargo).SwapList(this);
60 break;
61 case CS_VIA_BY_FROM:
62 ScriptStationList_CargoWaitingViaByFrom(station_id, cargo, other_station).SwapList(this);
63 break;
64 case CS_BY_VIA:
65 ScriptStationList_CargoWaitingByVia(station_id, cargo).SwapList(this);
66 break;
67 case CS_FROM_BY_VIA:
68 ScriptStationList_CargoWaitingFromByVia(station_id, cargo, other_station).SwapList(this);
69 break;
70 default:
71 NOT_REACHED();
72 }
73 }
74
ScriptStationList_CargoPlanned(ScriptStationList_Cargo::CargoSelector selector,StationID station_id,CargoID cargo,StationID other_station)75 ScriptStationList_CargoPlanned::ScriptStationList_CargoPlanned(
76 ScriptStationList_Cargo::CargoSelector selector, StationID station_id, CargoID cargo,
77 StationID other_station)
78 {
79 switch (selector) {
80 case CS_BY_FROM:
81 ScriptStationList_CargoPlannedByFrom(station_id, cargo).SwapList(this);
82 break;
83 case CS_VIA_BY_FROM:
84 ScriptStationList_CargoPlannedViaByFrom(station_id, cargo, other_station).SwapList(this);
85 break;
86 case CS_BY_VIA:
87 ScriptStationList_CargoPlannedByVia(station_id, cargo).SwapList(this);
88 break;
89 case CS_FROM_BY_VIA:
90 ScriptStationList_CargoPlannedFromByVia(station_id, cargo, other_station).SwapList(this);
91 break;
92 default:
93 NOT_REACHED();
94 }
95 }
96
97 class CargoCollector {
98 public:
99 CargoCollector(ScriptStationList_Cargo *parent, StationID station_id, CargoID cargo,
100 StationID other);
101 ~CargoCollector() ;
102
103 template<ScriptStationList_Cargo::CargoSelector Tselector>
104 void Update(StationID from, StationID via, uint amount);
GE() const105 const GoodsEntry *GE() const { return ge; }
106
107 private:
108 void SetValue();
109
110 ScriptStationList_Cargo *list;
111 const GoodsEntry *ge;
112 StationID other_station;
113
114 StationID last_key;
115 uint amount;
116 };
117
CargoCollector(ScriptStationList_Cargo * parent,StationID station_id,CargoID cargo,StationID other)118 CargoCollector::CargoCollector(ScriptStationList_Cargo *parent,
119 StationID station_id, CargoID cargo, StationID other) :
120 list(parent), ge(nullptr), other_station(other), last_key(INVALID_STATION), amount(0)
121 {
122 if (!ScriptStation::IsValidStation(station_id)) return;
123 if (!ScriptCargo::IsValidCargo(cargo)) return;
124 this->ge = &(Station::Get(station_id)->goods[cargo]);
125 }
126
~CargoCollector()127 CargoCollector::~CargoCollector()
128 {
129 this->SetValue();
130 }
131
SetValue()132 void CargoCollector::SetValue()
133 {
134 if (this->amount > 0) {
135 if (this->list->HasItem(this->last_key)) {
136 this->list->SetValue(this->last_key,
137 this->list->GetValue(this->last_key) + this->amount);
138 } else {
139 this->list->AddItem(this->last_key, this->amount);
140 }
141 }
142 }
143
144 template<ScriptStationList_Cargo::CargoSelector Tselector>
Update(StationID from,StationID via,uint amount)145 void CargoCollector::Update(StationID from, StationID via, uint amount)
146 {
147 StationID key = INVALID_STATION;
148 switch (Tselector) {
149 case ScriptStationList_Cargo::CS_VIA_BY_FROM:
150 if (via != this->other_station) return;
151 FALLTHROUGH;
152 case ScriptStationList_Cargo::CS_BY_FROM:
153 key = from;
154 break;
155 case ScriptStationList_Cargo::CS_FROM_BY_VIA:
156 if (from != this->other_station) return;
157 FALLTHROUGH;
158 case ScriptStationList_Cargo::CS_BY_VIA:
159 key = via;
160 break;
161 }
162 if (key == this->last_key) {
163 this->amount += amount;
164 } else {
165 this->SetValue();
166 this->amount = amount;
167 this->last_key = key;
168 }
169 }
170
171
172 template<ScriptStationList_Cargo::CargoSelector Tselector>
Add(StationID station_id,CargoID cargo,StationID other_station)173 void ScriptStationList_CargoWaiting::Add(StationID station_id, CargoID cargo, StationID other_station)
174 {
175 CargoCollector collector(this, station_id, cargo, other_station);
176 if (collector.GE() == nullptr) return;
177
178 StationCargoList::ConstIterator iter = collector.GE()->cargo.Packets()->begin();
179 StationCargoList::ConstIterator end = collector.GE()->cargo.Packets()->end();
180 for (; iter != end; ++iter) {
181 collector.Update<Tselector>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
182 }
183 }
184
185
186 template<ScriptStationList_Cargo::CargoSelector Tselector>
Add(StationID station_id,CargoID cargo,StationID other_station)187 void ScriptStationList_CargoPlanned::Add(StationID station_id, CargoID cargo, StationID other_station)
188 {
189 CargoCollector collector(this, station_id, cargo, other_station);
190 if (collector.GE() == nullptr) return;
191
192 FlowStatMap::const_iterator iter = collector.GE()->flows.begin();
193 FlowStatMap::const_iterator end = collector.GE()->flows.end();
194 for (; iter != end; ++iter) {
195 const FlowStat::SharesMap *shares = iter->second.GetShares();
196 uint prev = 0;
197 for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin();
198 flow_iter != shares->end(); ++flow_iter) {
199 collector.Update<Tselector>(iter->first, flow_iter->second, flow_iter->first - prev);
200 prev = flow_iter->first;
201 }
202 }
203 }
204
ScriptStationList_CargoWaitingByFrom(StationID station_id,CargoID cargo)205 ScriptStationList_CargoWaitingByFrom::ScriptStationList_CargoWaitingByFrom(StationID station_id,
206 CargoID cargo)
207 {
208 this->Add<CS_BY_FROM>(station_id, cargo);
209 }
210
ScriptStationList_CargoWaitingViaByFrom(StationID station_id,CargoID cargo,StationID via)211 ScriptStationList_CargoWaitingViaByFrom::ScriptStationList_CargoWaitingViaByFrom(
212 StationID station_id, CargoID cargo, StationID via)
213 {
214 CargoCollector collector(this, station_id, cargo, via);
215 if (collector.GE() == nullptr) return;
216
217 std::pair<StationCargoList::ConstIterator, StationCargoList::ConstIterator> range =
218 collector.GE()->cargo.Packets()->equal_range(via);
219 for (StationCargoList::ConstIterator iter = range.first; iter != range.second; ++iter) {
220 collector.Update<CS_VIA_BY_FROM>((*iter)->SourceStation(), iter.GetKey(), (*iter)->Count());
221 }
222 }
223
224
ScriptStationList_CargoWaitingByVia(StationID station_id,CargoID cargo)225 ScriptStationList_CargoWaitingByVia::ScriptStationList_CargoWaitingByVia(StationID station_id,
226 CargoID cargo)
227 {
228 this->Add<CS_BY_VIA>(station_id, cargo);
229 }
230
ScriptStationList_CargoWaitingFromByVia(StationID station_id,CargoID cargo,StationID from)231 ScriptStationList_CargoWaitingFromByVia::ScriptStationList_CargoWaitingFromByVia(
232 StationID station_id, CargoID cargo, StationID from)
233 {
234 this->Add<CS_FROM_BY_VIA>(station_id, cargo, from);
235 }
236
ScriptStationList_CargoPlannedByFrom(StationID station_id,CargoID cargo)237 ScriptStationList_CargoPlannedByFrom::ScriptStationList_CargoPlannedByFrom(StationID station_id,
238 CargoID cargo)
239 {
240 this->Add<CS_BY_FROM>(station_id, cargo);
241 }
242
ScriptStationList_CargoPlannedViaByFrom(StationID station_id,CargoID cargo,StationID via)243 ScriptStationList_CargoPlannedViaByFrom::ScriptStationList_CargoPlannedViaByFrom(
244 StationID station_id, CargoID cargo, StationID via)
245 {
246 this->Add<CS_VIA_BY_FROM>(station_id, cargo, via);
247 }
248
249
ScriptStationList_CargoPlannedByVia(StationID station_id,CargoID cargo)250 ScriptStationList_CargoPlannedByVia::ScriptStationList_CargoPlannedByVia(StationID station_id,
251 CargoID cargo)
252 {
253 this->Add<CS_BY_VIA>(station_id, cargo);
254 }
255
256
ScriptStationList_CargoPlannedFromByVia(StationID station_id,CargoID cargo,StationID from)257 ScriptStationList_CargoPlannedFromByVia::ScriptStationList_CargoPlannedFromByVia(
258 StationID station_id, CargoID cargo, StationID from)
259 {
260 CargoCollector collector(this, station_id, cargo, from);
261 if (collector.GE() == nullptr) return;
262
263 FlowStatMap::const_iterator iter = collector.GE()->flows.find(from);
264 if (iter == collector.GE()->flows.end()) return;
265 const FlowStat::SharesMap *shares = iter->second.GetShares();
266 uint prev = 0;
267 for (FlowStat::SharesMap::const_iterator flow_iter = shares->begin();
268 flow_iter != shares->end(); ++flow_iter) {
269 collector.Update<CS_FROM_BY_VIA>(iter->first, flow_iter->second, flow_iter->first - prev);
270 prev = flow_iter->first;
271 }
272 }
273