4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file station_sl.cpp Code handling saving and loading of stations. */
12 #include "../stdafx.h"
13 #include "../station_base.h"
14 #include "../waypoint_base.h"
15 #include "../roadstop_base.h"
16 #include "../vehicle_base.h"
17 #include "../newgrf_station.h"
20 #include "table/strings.h"
22 #include "../safeguards.h"
25 * Update the buoy orders to be waypoint orders.
26 * @param o the order 'list' to check.
28 static void UpdateWaypointOrder(Order
*o
)
30 if (!o
->IsType(OT_GOTO_STATION
)) return;
32 const Station
*st
= Station::Get(o
->GetDestination());
33 if ((st
->had_vehicle_of_type
& HVOT_WAYPOINT
) == 0) return;
35 o
->MakeGoToWaypoint(o
->GetDestination());
39 * Perform all steps to upgrade from the old station buoys to the new version
40 * that uses waypoints. This includes some old saveload mechanics.
42 void MoveBuoysToWaypoints()
44 /* Buoy orders become waypoint orders */
46 FOR_ALL_ORDER_LISTS(ol
) {
47 VehicleType vt
= ol
->GetFirstSharedVehicle()->type
;
48 if (vt
!= VEH_SHIP
&& vt
!= VEH_TRAIN
) continue;
50 for (Order
*o
= ol
->GetFirstOrder(); o
!= NULL
; o
= o
->next
) UpdateWaypointOrder(o
);
55 VehicleType vt
= v
->type
;
56 if (vt
!= VEH_SHIP
&& vt
!= VEH_TRAIN
) continue;
58 UpdateWaypointOrder(&v
->current_order
);
61 /* Now make the stations waypoints */
63 FOR_ALL_STATIONS(st
) {
64 if ((st
->had_vehicle_of_type
& HVOT_WAYPOINT
) == 0) continue;
66 StationID index
= st
->index
;
67 TileIndex xy
= st
->xy
;
68 Town
*town
= st
->town
;
69 StringID string_id
= st
->string_id
;
70 char *name
= st
->name
;
72 Date build_date
= st
->build_date
;
73 /* TTDPatch could use "buoys with rail station" for rail waypoints */
74 bool train
= st
->train_station
.tile
!= INVALID_TILE
;
75 TileArea train_st
= st
->train_station
;
77 /* Delete the station, so we can make it a real waypoint. */
80 /* Stations and waypoints are in the same pool, so if a station
81 * is deleted there must be place for a Waypoint. */
82 assert(Waypoint::CanAllocateItem());
83 Waypoint
*wp
= new (index
) Waypoint(xy
);
85 wp
->string_id
= train
? STR_SV_STNAME_WAYPOINT
: STR_SV_STNAME_BUOY
;
87 wp
->delete_ctr
= 0; // Just reset delete counter for once.
88 wp
->build_date
= build_date
;
89 wp
->owner
= train
? GetTileOwner(xy
) : OWNER_NONE
;
91 if (IsInsideBS(string_id
, STR_SV_STNAME_BUOY
, 9)) wp
->town_cn
= string_id
- STR_SV_STNAME_BUOY
;
94 /* When we make a rail waypoint of the station, convert the map as well. */
95 TILE_AREA_LOOP(t
, train_st
) {
96 if (!IsTileType(t
, MP_STATION
) || GetStationIndex(t
) != index
) continue;
98 SB(_me
[t
].m6
, 3, 3, STATION_WAYPOINT
);
99 wp
->rect
.BeforeAddTile(t
, StationRect::ADD_FORCE
);
102 wp
->train_station
= train_st
;
103 wp
->facilities
|= FACIL_TRAIN
;
104 } else if (IsBuoyTile(xy
) && GetStationIndex(xy
) == index
) {
105 wp
->rect
.BeforeAddTile(xy
, StationRect::ADD_FORCE
);
106 wp
->facilities
|= FACIL_DOCK
;
111 void AfterLoadStations()
113 /* Update the speclists of all stations to point to the currently loaded custom stations. */
115 FOR_ALL_BASE_STATIONS(st
) {
116 for (uint i
= 0; i
< st
->num_specs
; i
++) {
117 if (st
->speclist
[i
].grfid
== 0) continue;
119 st
->speclist
[i
].spec
= StationClass::GetByGrf(st
->speclist
[i
].grfid
, st
->speclist
[i
].localidx
, NULL
);
122 if (Station::IsExpected(st
)) {
123 Station
*sta
= Station::From(st
);
124 for (const RoadStop
*rs
= sta
->bus_stops
; rs
!= NULL
; rs
= rs
->next
) sta
->bus_station
.Add(rs
->xy
);
125 for (const RoadStop
*rs
= sta
->truck_stops
; rs
!= NULL
; rs
= rs
->next
) sta
->truck_station
.Add(rs
->xy
);
128 StationUpdateCachedTriggers(st
);
133 * (Re)building of road stop caches after loading a savegame.
135 void AfterLoadRoadStops()
137 /* First construct the drive through entries */
139 FOR_ALL_ROADSTOPS(rs
) {
140 if (IsDriveThroughStopTile(rs
->xy
)) rs
->MakeDriveThrough();
142 /* And then rebuild the data in those entries */
143 FOR_ALL_ROADSTOPS(rs
) {
144 if (!HasBit(rs
->status
, RoadStop::RSSFB_BASE_ENTRY
)) continue;
146 rs
->GetEntry(DIAGDIR_NE
)->Rebuild(rs
);
147 rs
->GetEntry(DIAGDIR_NW
)->Rebuild(rs
);
151 static const SaveLoad _roadstop_desc
[] = {
152 SLE_VAR(RoadStop
, xy
, SLE_UINT32
),
153 SLE_CONDNULL(1, 0, 44),
154 SLE_VAR(RoadStop
, status
, SLE_UINT8
),
155 /* Index was saved in some versions, but this is not needed */
156 SLE_CONDNULL(4, 0, 8),
157 SLE_CONDNULL(2, 0, 44),
158 SLE_CONDNULL(1, 0, 25),
160 SLE_REF(RoadStop
, next
, REF_ROADSTOPS
),
161 SLE_CONDNULL(2, 0, 44),
163 SLE_CONDNULL(4, 0, 24),
164 SLE_CONDNULL(1, 25, 25),
169 static const SaveLoad _old_station_desc
[] = {
170 SLE_CONDVAR(Station
, xy
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
171 SLE_CONDVAR(Station
, xy
, SLE_UINT32
, 6, SL_MAX_VERSION
),
172 SLE_CONDNULL(4, 0, 5), ///< bus/lorry tile
173 SLE_CONDVAR(Station
, train_station
.tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
174 SLE_CONDVAR(Station
, train_station
.tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
175 SLE_CONDVAR(Station
, airport
.tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
176 SLE_CONDVAR(Station
, airport
.tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
177 SLE_CONDVAR(Station
, dock_tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
178 SLE_CONDVAR(Station
, dock_tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
179 SLE_REF(Station
, town
, REF_TOWN
),
180 SLE_VAR(Station
, train_station
.w
, SLE_FILE_U8
| SLE_VAR_U16
),
181 SLE_CONDVAR(Station
, train_station
.h
, SLE_FILE_U8
| SLE_VAR_U16
, 2, SL_MAX_VERSION
),
183 SLE_CONDNULL(1, 0, 3), ///< alpha_order
185 SLE_VAR(Station
, string_id
, SLE_STRINGID
),
186 SLE_CONDSTR(Station
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, 0, 84, SL_MAX_VERSION
),
187 SLE_CONDVAR(Station
, indtype
, SLE_UINT8
, 103, SL_MAX_VERSION
),
188 SLE_CONDVAR(Station
, had_vehicle_of_type
, SLE_FILE_U16
| SLE_VAR_U8
, 0, 121),
189 SLE_CONDVAR(Station
, had_vehicle_of_type
, SLE_UINT8
, 122, SL_MAX_VERSION
),
191 SLE_VAR(Station
, time_since_load
, SLE_UINT8
),
192 SLE_VAR(Station
, time_since_unload
, SLE_UINT8
),
193 SLE_VAR(Station
, delete_ctr
, SLE_UINT8
),
194 SLE_VAR(Station
, owner
, SLE_UINT8
),
195 SLE_VAR(Station
, facilities
, SLE_UINT8
),
196 SLE_VAR(Station
, airport
.type
, SLE_UINT8
),
198 SLE_CONDNULL(2, 0, 5), ///< Truck/bus stop status
199 SLE_CONDNULL(1, 0, 4), ///< Blocked months
201 SLE_CONDVAR(Station
, airport
.flags
, SLE_VAR_U64
| SLE_FILE_U16
, 0, 2),
202 SLE_CONDVAR(Station
, airport
.flags
, SLE_VAR_U64
| SLE_FILE_U32
, 3, 45),
203 SLE_CONDVAR(Station
, airport
.flags
, SLE_UINT64
, 46, SL_MAX_VERSION
),
205 SLE_CONDNULL(2, 0, 25), ///< last-vehicle
206 SLE_CONDVAR(Station
, last_vehicle_type
, SLE_UINT8
, 26, SL_MAX_VERSION
),
208 SLE_CONDNULL(2, 3, 25), ///< custom station class and id
209 SLE_CONDVAR(Station
, build_date
, SLE_FILE_U16
| SLE_VAR_I32
, 3, 30),
210 SLE_CONDVAR(Station
, build_date
, SLE_INT32
, 31, SL_MAX_VERSION
),
212 SLE_CONDREF(Station
, bus_stops
, REF_ROADSTOPS
, 6, SL_MAX_VERSION
),
213 SLE_CONDREF(Station
, truck_stops
, REF_ROADSTOPS
, 6, SL_MAX_VERSION
),
215 /* Used by newstations for graphic variations */
216 SLE_CONDVAR(Station
, random_bits
, SLE_UINT16
, 27, SL_MAX_VERSION
),
217 SLE_CONDVAR(Station
, waiting_triggers
, SLE_UINT8
, 27, SL_MAX_VERSION
),
218 SLE_CONDVAR(Station
, num_specs
, SLE_UINT8
, 27, SL_MAX_VERSION
),
220 SLE_CONDLST(Station
, loading_vehicles
, REF_VEHICLE
, 57, SL_MAX_VERSION
),
222 /* reserve extra space in savegame here. (currently 32 bytes) */
223 SLE_CONDNULL(32, 2, SL_MAX_VERSION
),
228 static uint16 _waiting_acceptance
;
229 static uint32 _num_flows
;
230 static uint16 _cargo_source
;
231 static uint32 _cargo_source_xy
;
232 static uint8 _cargo_days
;
233 static Money _cargo_feeder_share
;
235 static const SaveLoad _station_speclist_desc
[] = {
236 SLE_CONDVAR(StationSpecList
, grfid
, SLE_UINT32
, 27, SL_MAX_VERSION
),
237 SLE_CONDVAR(StationSpecList
, localidx
, SLE_UINT8
, 27, SL_MAX_VERSION
),
242 std::list
<CargoPacket
*> _packets
;
245 struct FlowSaveLoad
{
246 FlowSaveLoad() : source(0), via(0), share(0), restricted(false) {}
253 static const SaveLoad _flow_desc
[] = {
254 SLE_VAR(FlowSaveLoad
, source
, SLE_UINT16
),
255 SLE_VAR(FlowSaveLoad
, via
, SLE_UINT16
),
256 SLE_VAR(FlowSaveLoad
, share
, SLE_UINT32
),
257 SLE_CONDVAR(FlowSaveLoad
, restricted
, SLE_BOOL
, 187, SL_MAX_VERSION
),
262 * Wrapper function to get the GoodsEntry's internal structure while
263 * some of the variables itself are private.
264 * @return the saveload description for GoodsEntry.
266 const SaveLoad
*GetGoodsDesc()
268 static const SaveLoad goods_desc
[] = {
269 SLEG_CONDVAR( _waiting_acceptance
, SLE_UINT16
, 0, 67),
270 SLE_CONDVAR(GoodsEntry
, status
, SLE_UINT8
, 68, SL_MAX_VERSION
),
271 SLE_CONDNULL(2, 51, 67),
272 SLE_VAR(GoodsEntry
, time_since_pickup
, SLE_UINT8
),
273 SLE_VAR(GoodsEntry
, rating
, SLE_UINT8
),
274 SLEG_CONDVAR( _cargo_source
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 6),
275 SLEG_CONDVAR( _cargo_source
, SLE_UINT16
, 7, 67),
276 SLEG_CONDVAR( _cargo_source_xy
, SLE_UINT32
, 44, 67),
277 SLEG_CONDVAR( _cargo_days
, SLE_UINT8
, 0, 67),
278 SLE_VAR(GoodsEntry
, last_speed
, SLE_UINT8
),
279 SLE_VAR(GoodsEntry
, last_age
, SLE_UINT8
),
280 SLEG_CONDVAR( _cargo_feeder_share
, SLE_FILE_U32
| SLE_VAR_I64
, 14, 64),
281 SLEG_CONDVAR( _cargo_feeder_share
, SLE_INT64
, 65, 67),
282 SLE_CONDVAR(GoodsEntry
, amount_fract
, SLE_UINT8
, 150, SL_MAX_VERSION
),
283 SLEG_CONDLST( _packets
, REF_CARGO_PACKET
, 68, 182),
284 SLEG_CONDVAR( _num_dests
, SLE_UINT32
, 183, SL_MAX_VERSION
),
285 SLE_CONDVAR(GoodsEntry
, cargo
.reserved_count
, SLE_UINT
, 181, SL_MAX_VERSION
),
286 SLE_CONDVAR(GoodsEntry
, link_graph
, SLE_UINT16
, 183, SL_MAX_VERSION
),
287 SLE_CONDVAR(GoodsEntry
, node
, SLE_UINT16
, 183, SL_MAX_VERSION
),
288 SLEG_CONDVAR( _num_flows
, SLE_UINT32
, 183, SL_MAX_VERSION
),
289 SLE_CONDVAR(GoodsEntry
, max_waiting_cargo
, SLE_UINT32
, 183, SL_MAX_VERSION
),
296 typedef std::pair
<const StationID
, std::list
<CargoPacket
*> > StationCargoPair
;
298 static const SaveLoad _cargo_list_desc
[] = {
299 SLE_VAR(StationCargoPair
, first
, SLE_UINT16
),
300 SLE_LST(StationCargoPair
, second
, REF_CARGO_PACKET
),
305 * Swap the temporary packets with the packets without specific destination in
306 * the given goods entry. Assert that at least one of those is empty.
307 * @param ge Goods entry to swap with.
309 static void SwapPackets(GoodsEntry
*ge
)
311 StationCargoPacketMap
&ge_packets
= const_cast<StationCargoPacketMap
&>(*ge
->cargo
.Packets());
313 if (_packets
.empty()) {
314 std::map
<StationID
, std::list
<CargoPacket
*> >::iterator
it(ge_packets
.find(INVALID_STATION
));
315 if (it
== ge_packets
.end()) {
318 it
->second
.swap(_packets
);
321 assert(ge_packets
[INVALID_STATION
].empty());
322 ge_packets
[INVALID_STATION
].swap(_packets
);
326 static void Load_STNS()
328 _cargo_source_xy
= 0;
330 _cargo_feeder_share
= 0;
333 while ((index
= SlIterateArray()) != -1) {
334 Station
*st
= new (index
) Station();
336 SlObject(st
, _old_station_desc
);
338 _waiting_acceptance
= 0;
340 uint num_cargo
= IsSavegameVersionBefore(55) ? 12 : NUM_CARGO
;
341 for (CargoID i
= 0; i
< num_cargo
; i
++) {
342 GoodsEntry
*ge
= &st
->goods
[i
];
343 SlObject(ge
, GetGoodsDesc());
345 if (IsSavegameVersionBefore(68)) {
346 SB(ge
->status
, GoodsEntry::GES_ACCEPTANCE
, 1, HasBit(_waiting_acceptance
, 15));
347 if (GB(_waiting_acceptance
, 0, 12) != 0) {
348 /* In old versions, enroute_from used 0xFF as INVALID_STATION */
349 StationID source
= (IsSavegameVersionBefore(7) && _cargo_source
== 0xFF) ? INVALID_STATION
: _cargo_source
;
351 /* Make sure we can allocate the CargoPacket. This is safe
352 * as there can only be ~64k stations and 32 cargoes in these
353 * savegame versions. As the CargoPacketPool has more than
354 * 16 million entries; it fits by an order of magnitude. */
355 assert(CargoPacket::CanAllocateItem());
357 /* Don't construct the packet with station here, because that'll fail with old savegames */
358 CargoPacket
*cp
= new CargoPacket(GB(_waiting_acceptance
, 0, 12), _cargo_days
, source
, _cargo_source_xy
, _cargo_source_xy
, _cargo_feeder_share
);
359 ge
->cargo
.Append(cp
, INVALID_STATION
);
360 SB(ge
->status
, GoodsEntry::GES_RATING
, 1, 1);
365 if (st
->num_specs
!= 0) {
366 /* Allocate speclist memory when loading a game */
367 st
->speclist
= CallocT
<StationSpecList
>(st
->num_specs
);
368 for (uint i
= 0; i
< st
->num_specs
; i
++) {
369 SlObject(&st
->speclist
[i
], _station_speclist_desc
);
375 static void Ptrs_STNS()
377 /* Don't run when savegame version is higher than or equal to 123. */
378 if (!IsSavegameVersionBefore(123)) return;
381 FOR_ALL_STATIONS(st
) {
382 if (!IsSavegameVersionBefore(68)) {
383 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
384 GoodsEntry
*ge
= &st
->goods
[i
];
386 SlObject(ge
, GetGoodsDesc());
390 SlObject(st
, _old_station_desc
);
395 static const SaveLoad _base_station_desc
[] = {
396 SLE_VAR(BaseStation
, xy
, SLE_UINT32
),
397 SLE_REF(BaseStation
, town
, REF_TOWN
),
398 SLE_VAR(BaseStation
, string_id
, SLE_STRINGID
),
399 SLE_STR(BaseStation
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, 0),
400 SLE_VAR(BaseStation
, delete_ctr
, SLE_UINT8
),
401 SLE_VAR(BaseStation
, owner
, SLE_UINT8
),
402 SLE_VAR(BaseStation
, facilities
, SLE_UINT8
),
403 SLE_VAR(BaseStation
, build_date
, SLE_INT32
),
405 /* Used by newstations for graphic variations */
406 SLE_VAR(BaseStation
, random_bits
, SLE_UINT16
),
407 SLE_VAR(BaseStation
, waiting_triggers
, SLE_UINT8
),
408 SLE_VAR(BaseStation
, num_specs
, SLE_UINT8
),
413 static OldPersistentStorage _old_st_persistent_storage
;
415 static const SaveLoad _station_desc
[] = {
416 SLE_WRITEBYTE(Station
, facilities
, FACIL_NONE
),
419 SLE_VAR(Station
, train_station
.tile
, SLE_UINT32
),
420 SLE_VAR(Station
, train_station
.w
, SLE_FILE_U8
| SLE_VAR_U16
),
421 SLE_VAR(Station
, train_station
.h
, SLE_FILE_U8
| SLE_VAR_U16
),
423 SLE_REF(Station
, bus_stops
, REF_ROADSTOPS
),
424 SLE_REF(Station
, truck_stops
, REF_ROADSTOPS
),
425 SLE_VAR(Station
, dock_tile
, SLE_UINT32
),
426 SLE_VAR(Station
, airport
.tile
, SLE_UINT32
),
427 SLE_CONDVAR(Station
, airport
.w
, SLE_FILE_U8
| SLE_VAR_U16
, 140, SL_MAX_VERSION
),
428 SLE_CONDVAR(Station
, airport
.h
, SLE_FILE_U8
| SLE_VAR_U16
, 140, SL_MAX_VERSION
),
429 SLE_VAR(Station
, airport
.type
, SLE_UINT8
),
430 SLE_CONDVAR(Station
, airport
.layout
, SLE_UINT8
, 145, SL_MAX_VERSION
),
431 SLE_VAR(Station
, airport
.flags
, SLE_UINT64
),
432 SLE_CONDVAR(Station
, airport
.rotation
, SLE_UINT8
, 145, SL_MAX_VERSION
),
433 SLEG_CONDARR(_old_st_persistent_storage
.storage
, SLE_UINT32
, 16, 145, 160),
434 SLE_CONDREF(Station
, airport
.psa
, REF_STORAGE
, 161, SL_MAX_VERSION
),
436 SLE_VAR(Station
, indtype
, SLE_UINT8
),
438 SLE_VAR(Station
, time_since_load
, SLE_UINT8
),
439 SLE_VAR(Station
, time_since_unload
, SLE_UINT8
),
440 SLE_VAR(Station
, last_vehicle_type
, SLE_UINT8
),
441 SLE_VAR(Station
, had_vehicle_of_type
, SLE_UINT8
),
442 SLE_LST(Station
, loading_vehicles
, REF_VEHICLE
),
443 SLE_CONDVAR(Station
, always_accepted
, SLE_UINT32
, 127, SL_MAX_VERSION
),
448 static const SaveLoad _waypoint_desc
[] = {
449 SLE_WRITEBYTE(Waypoint
, facilities
, FACIL_WAYPOINT
),
452 SLE_VAR(Waypoint
, town_cn
, SLE_UINT16
),
454 SLE_CONDVAR(Waypoint
, train_station
.tile
, SLE_UINT32
, 124, SL_MAX_VERSION
),
455 SLE_CONDVAR(Waypoint
, train_station
.w
, SLE_FILE_U8
| SLE_VAR_U16
, 124, SL_MAX_VERSION
),
456 SLE_CONDVAR(Waypoint
, train_station
.h
, SLE_FILE_U8
| SLE_VAR_U16
, 124, SL_MAX_VERSION
),
462 * Get the base station description to be used for SL_ST_INCLUDE
463 * @return the base station description.
465 const SaveLoad
*GetBaseStationDescription()
467 return _base_station_desc
;
470 static void RealSave_STNN(BaseStation
*bst
)
472 bool waypoint
= (bst
->facilities
& FACIL_WAYPOINT
) != 0;
473 SlObject(bst
, waypoint
? _waypoint_desc
: _station_desc
);
476 Station
*st
= Station::From(bst
);
477 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
478 _num_dests
= (uint32
)st
->goods
[i
].cargo
.Packets()->MapSize();
480 for (FlowStatMap::const_iterator
it(st
->goods
[i
].flows
.begin()); it
!= st
->goods
[i
].flows
.end(); ++it
) {
481 _num_flows
+= (uint32
)it
->second
.GetShares()->size();
483 SlObject(&st
->goods
[i
], GetGoodsDesc());
484 for (FlowStatMap::const_iterator
outer_it(st
->goods
[i
].flows
.begin()); outer_it
!= st
->goods
[i
].flows
.end(); ++outer_it
) {
485 const FlowStat::SharesMap
*shares
= outer_it
->second
.GetShares();
486 uint32 sum_shares
= 0;
488 flow
.source
= outer_it
->first
;
489 for (FlowStat::SharesMap::const_iterator
inner_it(shares
->begin()); inner_it
!= shares
->end(); ++inner_it
) {
490 flow
.via
= inner_it
->second
;
491 flow
.share
= inner_it
->first
- sum_shares
;
492 flow
.restricted
= inner_it
->first
> outer_it
->second
.GetUnrestricted();
493 sum_shares
= inner_it
->first
;
494 assert(flow
.share
> 0);
495 SlObject(&flow
, _flow_desc
);
498 for (StationCargoPacketMap::ConstMapIterator
it(st
->goods
[i
].cargo
.Packets()->begin()); it
!= st
->goods
[i
].cargo
.Packets()->end(); ++it
) {
499 SlObject(const_cast<StationCargoPacketMap::value_type
*>(&(*it
)), _cargo_list_desc
);
504 for (uint i
= 0; i
< bst
->num_specs
; i
++) {
505 SlObject(&bst
->speclist
[i
], _station_speclist_desc
);
509 static void Save_STNN()
512 /* Write the stations */
513 FOR_ALL_BASE_STATIONS(st
) {
514 SlSetArrayIndex(st
->index
);
515 SlAutolength((AutolengthProc
*)RealSave_STNN
, st
);
519 static void Load_STNN()
524 while ((index
= SlIterateArray()) != -1) {
525 bool waypoint
= (SlReadByte() & FACIL_WAYPOINT
) != 0;
527 BaseStation
*bst
= waypoint
? (BaseStation
*)new (index
) Waypoint() : new (index
) Station();
528 SlObject(bst
, waypoint
? _waypoint_desc
: _station_desc
);
531 Station
*st
= Station::From(bst
);
533 /* Before savegame version 161, persistent storages were not stored in a pool. */
534 if (IsSavegameVersionBefore(161) && !IsSavegameVersionBefore(145) && st
->facilities
& FACIL_AIRPORT
) {
535 /* Store the old persistent storage. The GRFID will be added later. */
536 assert(PersistentStorage::CanAllocateItem());
537 st
->airport
.psa
= new PersistentStorage(0, 0, 0);
538 memcpy(st
->airport
.psa
->storage
, _old_st_persistent_storage
.storage
, sizeof(st
->airport
.psa
->storage
));
541 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
542 SlObject(&st
->goods
[i
], GetGoodsDesc());
545 StationID prev_source
= INVALID_STATION
;
546 for (uint32 j
= 0; j
< _num_flows
; ++j
) {
547 SlObject(&flow
, _flow_desc
);
548 if (fs
== NULL
|| prev_source
!= flow
.source
) {
549 fs
= &(st
->goods
[i
].flows
.insert(std::make_pair(flow
.source
, FlowStat(flow
.via
, flow
.share
, flow
.restricted
))).first
->second
);
551 fs
->AppendShare(flow
.via
, flow
.share
, flow
.restricted
);
553 prev_source
= flow
.source
;
555 if (IsSavegameVersionBefore(183)) {
556 SwapPackets(&st
->goods
[i
]);
558 StationCargoPair pair
;
559 for (uint j
= 0; j
< _num_dests
; ++j
) {
560 SlObject(&pair
, _cargo_list_desc
);
561 const_cast<StationCargoPacketMap
&>(*(st
->goods
[i
].cargo
.Packets()))[pair
.first
].swap(pair
.second
);
562 assert(pair
.second
.empty());
568 if (bst
->num_specs
!= 0) {
569 /* Allocate speclist memory when loading a game */
570 bst
->speclist
= CallocT
<StationSpecList
>(bst
->num_specs
);
571 for (uint i
= 0; i
< bst
->num_specs
; i
++) {
572 SlObject(&bst
->speclist
[i
], _station_speclist_desc
);
578 static void Ptrs_STNN()
580 /* Don't run when savegame version lower than 123. */
581 if (IsSavegameVersionBefore(123)) return;
584 FOR_ALL_STATIONS(st
) {
585 for (CargoID i
= 0; i
< NUM_CARGO
; i
++) {
586 GoodsEntry
*ge
= &st
->goods
[i
];
587 if (IsSavegameVersionBefore(183)) {
589 SlObject(ge
, GetGoodsDesc());
592 SlObject(ge
, GetGoodsDesc());
593 for (StationCargoPacketMap::ConstMapIterator it
= ge
->cargo
.Packets()->begin(); it
!= ge
->cargo
.Packets()->end(); ++it
) {
594 SlObject(const_cast<StationCargoPair
*>(&(*it
)), _cargo_list_desc
);
598 SlObject(st
, _station_desc
);
602 FOR_ALL_WAYPOINTS(wp
) {
603 SlObject(wp
, _waypoint_desc
);
607 static void Save_ROADSTOP()
611 FOR_ALL_ROADSTOPS(rs
) {
612 SlSetArrayIndex(rs
->index
);
613 SlObject(rs
, _roadstop_desc
);
617 static void Load_ROADSTOP()
621 while ((index
= SlIterateArray()) != -1) {
622 RoadStop
*rs
= new (index
) RoadStop(INVALID_TILE
);
624 SlObject(rs
, _roadstop_desc
);
628 static void Ptrs_ROADSTOP()
631 FOR_ALL_ROADSTOPS(rs
) {
632 SlObject(rs
, _roadstop_desc
);
636 extern const ChunkHandler _station_chunk_handlers
[] = {
637 { 'STNS', NULL
, Load_STNS
, Ptrs_STNS
, NULL
, CH_ARRAY
},
638 { 'STNN', Save_STNN
, Load_STNN
, Ptrs_STNN
, NULL
, CH_ARRAY
},
639 { 'ROAD', Save_ROADSTOP
, Load_ROADSTOP
, Ptrs_ROADSTOP
, NULL
, CH_ARRAY
| CH_LAST
},