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 vehicle_sl.cpp Code handling saving and loading of vehicles */
10 #include "../stdafx.h"
13 #include "compat/vehicle_sl_compat.h"
15 #include "../vehicle_func.h"
17 #include "../roadveh.h"
19 #include "../aircraft.h"
20 #include "../station_base.h"
21 #include "../effectvehicle_base.h"
22 #include "../company_base.h"
23 #include "../company_func.h"
24 #include "../disaster_vehicle.h"
28 #include "../safeguards.h"
31 * Link front and rear multiheaded engines to each other
32 * This is done when loading a savegame
34 void ConnectMultiheadedTrains()
36 for (Train
*v
: Train::Iterate()) {
37 v
->other_multiheaded_part
= nullptr;
40 for (Train
*v
: Train::Iterate()) {
41 if (v
->IsFrontEngine() || v
->IsFreeWagon()) {
42 /* Two ways to associate multiheaded parts to each other:
43 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
44 * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
46 * Note: Old savegames might contain chains which do not comply with these rules, e.g.
47 * - the front and read parts have invalid orders
48 * - different engine types might be combined
49 * - there might be different amounts of front and rear parts.
51 * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
52 * This is why two matching strategies are needed.
55 bool sequential_matching
= v
->IsFrontEngine();
57 for (Train
*u
= v
; u
!= nullptr; u
= u
->GetNextVehicle()) {
58 if (u
->other_multiheaded_part
!= nullptr) continue; // we already linked this one
60 if (u
->IsMultiheaded()) {
62 /* we got a rear car without a front car. We will convert it to a front one */
67 /* Find a matching back part */
68 EngineID eid
= u
->engine_type
;
70 if (sequential_matching
) {
71 for (w
= u
->GetNextVehicle(); w
!= nullptr; w
= w
->GetNextVehicle()) {
72 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= nullptr || !w
->IsMultiheaded()) continue;
74 /* we found a car to partner with this engine. Now we will make sure it face the right way */
83 for (w
= u
->GetNextVehicle(); w
!= nullptr; w
= w
->GetNextVehicle()) {
84 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= nullptr || !w
->IsMultiheaded()) continue;
89 if (stack_pos
== 0) break;
96 w
->other_multiheaded_part
= u
;
97 u
->other_multiheaded_part
= w
;
99 /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
100 u
->ClearMultiheaded();
109 * Converts all trains to the new subtype format introduced in savegame 16.2
110 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
112 void ConvertOldMultiheadToNew()
114 for (Train
*t
: Train::Iterate()) SetBit(t
->subtype
, 7); // indicates that it's the old format and needs to be converted in the next loop
116 for (Train
*t
: Train::Iterate()) {
117 if (HasBit(t
->subtype
, 7) && ((t
->subtype
& ~0x80) == 0 || (t
->subtype
& ~0x80) == 4)) {
118 for (Train
*u
= t
; u
!= nullptr; u
= u
->Next()) {
119 const RailVehicleInfo
*rvi
= RailVehInfo(u
->engine_type
);
121 ClrBit(u
->subtype
, 7);
122 switch (u
->subtype
) {
123 case 0: // TS_Front_Engine
124 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
) u
->SetMultiheaded();
129 case 1: // TS_Artic_Part
131 u
->SetArticulatedPart();
134 case 2: // TS_Not_First
136 if (rvi
->railveh_type
== RAILVEH_WAGON
) {
141 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
&& rvi
->image_index
== u
->spritenum
- 1) {
142 /* rear end of a multiheaded engine */
146 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
) u
->SetMultiheaded();
150 case 4: // TS_Free_Car
155 default: SlErrorCorrupt("Invalid train subtype");
163 /** need to be called to load aircraft from old version */
164 void UpdateOldAircraft()
166 /* set airport_flags to 0 for all airports just to be sure */
167 for (Station
*st
: Station::Iterate()) {
168 st
->airport
.flags
= 0; // reset airport
171 for (Aircraft
*a
: Aircraft::Iterate()) {
172 /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
174 if (a
->IsNormalAircraft()) {
175 /* airplane in terminal stopped doesn't hurt anyone, so goto next */
176 if ((a
->vehstatus
& VS_STOPPED
) && a
->state
== 0) {
181 AircraftLeaveHangar(a
, a
->direction
); // make airplane visible if it was in a depot for example
182 a
->vehstatus
&= ~VS_STOPPED
; // make airplane moving
183 UpdateAircraftCache(a
);
184 a
->cur_speed
= a
->vcache
.cached_max_speed
; // so aircraft don't have zero speed while in air
185 if (!a
->current_order
.IsType(OT_GOTO_STATION
) && !a
->current_order
.IsType(OT_GOTO_DEPOT
)) {
186 /* reset current order so aircraft doesn't have invalid "station-only" order */
187 a
->current_order
.MakeDummy();
190 AircraftNextAirportPos_and_Order(a
); // move it to the entry point of the airport
191 GetNewVehiclePosResult gp
= GetNewVehiclePos(a
);
192 a
->tile
= 0; // aircraft in air is tile=0
194 /* correct speed of helicopter-rotors */
195 if (a
->subtype
== AIR_HELICOPTER
) a
->Next()->Next()->cur_speed
= 32;
197 /* set new position x,y,z */
198 GetAircraftFlightLevelBounds(a
, &a
->z_pos
, nullptr);
199 SetAircraftPosition(a
, gp
.x
, gp
.y
, GetAircraftFlightLevel(a
));
205 * Check all vehicles to ensure their engine type is valid
206 * for the currently loaded NewGRFs (that includes none...)
207 * This only makes a difference if NewGRFs are missing, otherwise
208 * all vehicles will be valid. This does not make such a game
209 * playable, it only prevents crash.
211 static void CheckValidVehicles()
213 size_t total_engines
= Engine::GetPoolSize();
214 EngineID first_engine
[4] = { INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
};
216 for (const Engine
*e
: Engine::IterateType(VEH_TRAIN
)) { first_engine
[VEH_TRAIN
] = e
->index
; break; }
217 for (const Engine
*e
: Engine::IterateType(VEH_ROAD
)) { first_engine
[VEH_ROAD
] = e
->index
; break; }
218 for (const Engine
*e
: Engine::IterateType(VEH_SHIP
)) { first_engine
[VEH_SHIP
] = e
->index
; break; }
219 for (const Engine
*e
: Engine::IterateType(VEH_AIRCRAFT
)) { first_engine
[VEH_AIRCRAFT
] = e
->index
; break; }
221 for (Vehicle
*v
: Vehicle::Iterate()) {
222 /* Test if engine types match */
228 if (v
->engine_type
>= total_engines
|| v
->type
!= v
->GetEngine()->type
) {
229 v
->engine_type
= first_engine
[v
->type
];
239 extern byte _age_cargo_skip_counter
; // From misc_sl.cpp
241 /** Called after load to update coordinates */
242 void AfterLoadVehicles(bool part_of_load
)
244 for (Vehicle
*v
: Vehicle::Iterate()) {
245 /* Reinstate the previous pointer */
246 if (v
->Next() != nullptr) v
->Next()->previous
= v
;
247 if (v
->NextShared() != nullptr) v
->NextShared()->previous_shared
= v
;
249 if (part_of_load
) v
->fill_percent_te_id
= INVALID_TE_ID
;
251 if (v
->IsGroundVehicle()) v
->GetGroundVehicleCache()->first_engine
= INVALID_ENGINE
;
254 /* AfterLoadVehicles may also be called in case of NewGRF reload, in this
255 * case we may not convert orders again. */
257 /* Create shared vehicle chain for very old games (pre 5,2) and create
258 * OrderList from shared vehicle chains. For this to work correctly, the
259 * following conditions must be fulfilled:
260 * a) both next_shared and previous_shared are not set for pre 5,2 games
261 * b) both next_shared and previous_shared are set for later games
263 std::map
<Order
*, OrderList
*> mapping
;
265 for (Vehicle
*v
: Vehicle::Iterate()) {
266 if (v
->old_orders
!= nullptr) {
267 if (IsSavegameVersionBefore(SLV_105
)) { // Pre-105 didn't save an OrderList
268 if (mapping
[v
->old_orders
] == nullptr) {
269 /* This adds the whole shared vehicle chain for case b */
271 /* Creating an OrderList here is safe because the number of vehicles
272 * allowed in these savegames matches the number of OrderLists. As
273 * such each vehicle can get an OrderList and it will (still) fit. */
274 assert(OrderList::CanAllocateItem());
275 v
->orders
= mapping
[v
->old_orders
] = new OrderList(v
->old_orders
, v
);
277 v
->orders
= mapping
[v
->old_orders
];
278 /* For old games (case a) we must create the shared vehicle chain */
279 if (IsSavegameVersionBefore(SLV_5
, 2)) {
280 v
->AddToShared(v
->orders
->GetFirstSharedVehicle());
283 } else { // OrderList was saved as such, only recalculate not saved values
284 if (v
->PreviousShared() == nullptr) {
285 v
->orders
->Initialize(v
->orders
->first
, v
);
292 for (Vehicle
*v
: Vehicle::Iterate()) {
293 /* Fill the first pointers */
294 if (v
->Previous() == nullptr) {
295 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
302 if (IsSavegameVersionBefore(SLV_105
)) {
303 /* Before 105 there was no order for shared orders, thus it messed up horribly */
304 for (Vehicle
*v
: Vehicle::Iterate()) {
305 if (v
->First() != v
|| v
->orders
!= nullptr || v
->previous_shared
!= nullptr || v
->next_shared
== nullptr) continue;
307 /* As above, allocating OrderList here is safe. */
308 assert(OrderList::CanAllocateItem());
309 v
->orders
= new OrderList(nullptr, v
);
310 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->next_shared
) {
311 u
->orders
= v
->orders
;
316 if (IsSavegameVersionBefore(SLV_157
)) {
317 /* The road vehicle subtype was converted to a flag. */
318 for (RoadVehicle
*rv
: RoadVehicle::Iterate()) {
319 if (rv
->subtype
== 0) {
320 /* The road vehicle is at the front. */
321 rv
->SetFrontEngine();
322 } else if (rv
->subtype
== 1) {
323 /* The road vehicle is an articulated part. */
325 rv
->SetArticulatedPart();
327 SlErrorCorrupt("Invalid road vehicle subtype");
332 if (IsSavegameVersionBefore(SLV_160
)) {
333 /* In some old savegames there might be some "crap" stored. */
334 for (Vehicle
*v
: Vehicle::Iterate()) {
335 if (!v
->IsPrimaryVehicle() && v
->type
!= VEH_DISASTER
) {
336 v
->current_order
.Free();
342 if (IsSavegameVersionBefore(SLV_162
)) {
343 /* Set the vehicle-local cargo age counter from the old global counter. */
344 for (Vehicle
*v
: Vehicle::Iterate()) {
345 v
->cargo_age_counter
= _age_cargo_skip_counter
;
349 if (IsSavegameVersionBefore(SLV_180
)) {
350 /* Set service interval flags */
351 for (Vehicle
*v
: Vehicle::Iterate()) {
352 if (!v
->IsPrimaryVehicle()) continue;
354 const Company
*c
= Company::Get(v
->owner
);
355 int interval
= CompanyServiceInterval(c
, v
->type
);
357 v
->SetServiceIntervalIsCustom(v
->GetServiceInterval() != interval
);
358 v
->SetServiceIntervalIsPercent(c
->settings
.vehicle
.servint_ispercent
);
362 if (IsSavegameVersionBefore(SLV_SHIP_ROTATION
)) {
363 /* Ship rotation added */
364 for (Ship
*s
: Ship::Iterate()) {
365 s
->rotation
= s
->direction
;
368 for (Ship
*s
: Ship::Iterate()) {
369 if (s
->rotation
== s
->direction
) continue;
370 /* In case we are rotating on gameload, set the rotation position to
371 * the current position, otherwise the applied workaround offset would
372 * be with respect to 0,0.
374 s
->rotation_x_pos
= s
->x_pos
;
375 s
->rotation_y_pos
= s
->y_pos
;
380 CheckValidVehicles();
382 for (Vehicle
*v
: Vehicle::Iterate()) {
383 assert(v
->first
!= nullptr);
385 v
->trip_occupancy
= CalcPercentVehicleFilled(v
, nullptr);
389 Train
*t
= Train::From(v
);
390 if (t
->IsFrontEngine() || t
->IsFreeWagon()) {
391 t
->gcache
.last_speed
= t
->cur_speed
; // update displayed train speed
392 t
->ConsistChanged(CCF_SAVELOAD
);
398 RoadVehicle
*rv
= RoadVehicle::From(v
);
399 if (rv
->IsFrontEngine()) {
400 rv
->gcache
.last_speed
= rv
->cur_speed
; // update displayed road vehicle speed
402 rv
->roadtype
= Engine::Get(rv
->engine_type
)->u
.road
.roadtype
;
403 rv
->compatible_roadtypes
= GetRoadTypeInfo(rv
->roadtype
)->powered_roadtypes
;
404 for (RoadVehicle
*u
= rv
; u
!= nullptr; u
= u
->Next()) {
405 u
->roadtype
= rv
->roadtype
;
406 u
->compatible_roadtypes
= rv
->compatible_roadtypes
;
409 RoadVehUpdateCache(rv
);
410 if (_settings_game
.vehicle
.roadveh_acceleration_model
!= AM_ORIGINAL
) {
418 Ship::From(v
)->UpdateCache();
425 /* Stop non-front engines */
426 if (part_of_load
&& IsSavegameVersionBefore(SLV_112
)) {
427 for (Vehicle
*v
: Vehicle::Iterate()) {
428 if (v
->type
== VEH_TRAIN
) {
429 Train
*t
= Train::From(v
);
430 if (!t
->IsFrontEngine()) {
431 if (t
->IsEngine()) t
->vehstatus
|= VS_STOPPED
;
432 /* cur_speed is now relevant for non-front parts - nonzero breaks
433 * moving-wagons-inside-depot- and autoreplace- code */
437 /* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
438 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
439 if ((v
->vehstatus
& VS_STOPPED
) && (v
->type
!= VEH_TRAIN
|| IsSavegameVersionBefore(SLV_2
, 1))) {
445 for (Vehicle
*v
: Vehicle::Iterate()) {
450 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_cache
.sprite_seq
);
454 if (Aircraft::From(v
)->IsNormalAircraft()) {
455 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_cache
.sprite_seq
);
457 /* The plane's shadow will have the same image as the plane, but no colour */
458 Vehicle
*shadow
= v
->Next();
459 shadow
->sprite_cache
.sprite_seq
.CopyWithoutPalette(v
->sprite_cache
.sprite_seq
);
461 /* In the case of a helicopter we will update the rotor sprites */
462 if (v
->subtype
== AIR_HELICOPTER
) {
463 Vehicle
*rotor
= shadow
->Next();
464 GetRotorImage(Aircraft::From(v
), EIT_ON_MAP
, &rotor
->sprite_cache
.sprite_seq
);
467 UpdateAircraftCache(Aircraft::From(v
), true);
474 v
->coord
.left
= INVALID_COORD
;
475 v
->sprite_cache
.old_coord
.left
= INVALID_COORD
;
477 v
->UpdateViewport(false);
481 bool TrainController(Train
*v
, Vehicle
*nomove
, bool reverse
= true); // From train_cmd.cpp
482 void ReverseTrainDirection(Train
*v
);
483 void ReverseTrainSwapVeh(Train
*v
, int l
, int r
);
485 /** Fixup old train spacing. */
486 void FixupTrainLengths()
488 /* Vehicle center was moved from 4 units behind the front to half the length
489 * behind the front. Move vehicles so they end up on the same spot. */
490 for (Vehicle
*v
: Vehicle::Iterate()) {
491 if (v
->type
== VEH_TRAIN
&& v
->IsPrimaryVehicle()) {
492 /* The vehicle center is now more to the front depending on vehicle length,
493 * so we need to move all vehicles forward to cover the difference to the
494 * old center, otherwise wagon spacing in trains would be broken upon load. */
495 for (Train
*u
= Train::From(v
); u
!= nullptr; u
= u
->Next()) {
496 if (u
->track
== TRACK_BIT_DEPOT
|| (u
->vehstatus
& VS_CRASHED
)) continue;
498 Train
*next
= u
->Next();
500 /* Try to pull the vehicle half its length forward. */
501 int diff
= (VEHICLE_LENGTH
- u
->gcache
.cached_veh_length
) / 2;
503 for (done
= 0; done
< diff
; done
++) {
504 if (!TrainController(u
, next
, false)) break;
507 if (next
!= nullptr && done
< diff
&& u
->IsFrontEngine()) {
508 /* Pulling the front vehicle forwards failed, we either encountered a dead-end
509 * or a red signal. To fix this, we try to move the whole train the required
510 * space backwards and re-do the fix up of the front vehicle. */
512 /* Ignore any signals when backtracking. */
513 TrainForceProceeding old_tfp
= u
->force_proceed
;
514 u
->force_proceed
= TFP_SIGNAL
;
516 /* Swap start<>end, start+1<>end-1, ... */
517 int r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
519 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
521 /* We moved the first vehicle which is now the last. Move it back to the
522 * original position as we will fix up the last vehicle later in the loop. */
523 for (int i
= 0; i
< done
; i
++) TrainController(u
->Last(), nullptr);
525 /* Move the train backwards to get space for the first vehicle. As the stopping
526 * distance from a line end is rounded up, move the train one unit more to cater
527 * for front vehicles with odd lengths. */
529 for (moved
= 0; moved
< diff
+ 1; moved
++) {
530 if (!TrainController(u
, nullptr, false)) break;
533 /* Swap start<>end, start+1<>end-1, ... again. */
534 r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
536 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
538 u
->force_proceed
= old_tfp
;
540 /* Tracks are too short to fix the train length. The player has to fix the
541 * train in a depot. Bail out so we don't damage the vehicle chain any more. */
542 if (moved
< diff
+ 1) break;
544 /* Re-do the correction for the first vehicle. */
545 for (done
= 0; done
< diff
; done
++) TrainController(u
, next
, false);
547 /* We moved one unit more backwards than needed for even-length front vehicles,
548 * try to move that unit forward again. We don't care if this step fails. */
549 TrainController(u
, nullptr, false);
552 /* If the next wagon is still in a depot, check if it shouldn't be outside already. */
553 if (next
!= nullptr && next
->track
== TRACK_BIT_DEPOT
) {
554 int d
= TicksToLeaveDepot(u
);
556 /* Next vehicle should have left the depot already, show it and pull forward. */
557 next
->vehstatus
&= ~VS_HIDDEN
;
558 next
->track
= TrackToTrackBits(GetRailDepotTrack(next
->tile
));
559 for (int i
= 0; i
>= d
; i
--) TrainController(next
, nullptr);
564 /* Update all cached properties after moving the vehicle chain around. */
565 Train::From(v
)->ConsistChanged(CCF_TRACK
);
570 static uint8 _cargo_days
;
571 static uint16 _cargo_source
;
572 static uint32 _cargo_source_xy
;
573 static uint16 _cargo_count
;
574 static uint16 _cargo_paid_for
;
575 static Money _cargo_feeder_share
;
576 static uint32 _cargo_loaded_at_xy
;
578 class SlVehicleCommon
: public DefaultSaveLoadHandler
<SlVehicleCommon
, Vehicle
> {
580 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
581 /* This table access private members of other classes; they have this
582 * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for
583 * "inline static const", so we are forced to wrap the table in a
584 * function. CL 19.16 is the latest for VS2017. */
585 inline static const SaveLoad description
[] = {{}};
586 SaveLoadTable
GetDescription() const override
{
590 static const SaveLoad description
[] = {
591 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
593 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
594 SLE_CONDVAR(Vehicle
, name
, SLE_NAME
, SL_MIN_VERSION
, SLV_84
),
595 SLE_CONDSSTR(Vehicle
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, SLV_84
, SL_MAX_VERSION
),
596 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_8
),
597 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_UINT16
, SLV_8
, SL_MAX_VERSION
),
598 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
599 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
600 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
601 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
602 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
604 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
605 SLE_CONDVAR(Vehicle
, x_pos
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
606 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
607 SLE_CONDVAR(Vehicle
, y_pos
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
608 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
609 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
610 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
612 SLE_VAR(Vehicle
, spritenum
, SLE_UINT8
),
613 SLE_VAR(Vehicle
, engine_type
, SLE_UINT16
),
614 SLE_VAR(Vehicle
, cur_speed
, SLE_UINT16
),
615 SLE_VAR(Vehicle
, subspeed
, SLE_UINT8
),
616 SLE_VAR(Vehicle
, acceleration
, SLE_UINT8
),
617 SLE_CONDVAR(Vehicle
, motion_counter
, SLE_UINT32
, SLV_VEH_MOTION_COUNTER
, SL_MAX_VERSION
),
618 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
620 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
621 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
622 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
623 SLE_CONDVAR(Vehicle
, last_loading_station
, SLE_UINT16
, SLV_182
, SL_MAX_VERSION
),
625 SLE_VAR(Vehicle
, cargo_type
, SLE_UINT8
),
626 SLE_CONDVAR(Vehicle
, cargo_subtype
, SLE_UINT8
, SLV_35
, SL_MAX_VERSION
),
627 SLEG_CONDVAR("cargo_days", _cargo_days
, SLE_UINT8
, SL_MIN_VERSION
, SLV_68
),
628 SLEG_CONDVAR("cargo_source", _cargo_source
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_7
),
629 SLEG_CONDVAR("cargo_source", _cargo_source
, SLE_UINT16
, SLV_7
, SLV_68
),
630 SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy
, SLE_UINT32
, SLV_44
, SLV_68
),
631 SLE_VAR(Vehicle
, cargo_cap
, SLE_UINT16
),
632 SLE_CONDVAR(Vehicle
, refit_cap
, SLE_UINT16
, SLV_182
, SL_MAX_VERSION
),
633 SLEG_CONDVAR("cargo_count", _cargo_count
, SLE_UINT16
, SL_MIN_VERSION
, SLV_68
),
634 SLE_CONDREFLIST(Vehicle
, cargo
.packets
, REF_CARGO_PACKET
, SLV_68
, SL_MAX_VERSION
),
635 SLE_CONDARR(Vehicle
, cargo
.action_counts
, SLE_UINT
, VehicleCargoList::NUM_MOVE_TO_ACTION
, SLV_181
, SL_MAX_VERSION
),
636 SLE_CONDVAR(Vehicle
, cargo_age_counter
, SLE_UINT16
, SLV_162
, SL_MAX_VERSION
),
638 SLE_VAR(Vehicle
, day_counter
, SLE_UINT8
),
639 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
640 SLE_CONDVAR(Vehicle
, running_ticks
, SLE_UINT8
, SLV_88
, SL_MAX_VERSION
),
642 SLE_VAR(Vehicle
, cur_implicit_order_index
, SLE_UINT8
),
643 SLE_CONDVAR(Vehicle
, cur_real_order_index
, SLE_UINT8
, SLV_158
, SL_MAX_VERSION
),
645 /* This next line is for version 4 and prior compatibility.. it temporarily reads
646 type and flags (which were both 4 bits) into type. Later on this is
647 converted correctly */
648 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, SL_MIN_VERSION
, SLV_5
),
649 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
651 /* Orders for version 5 and on */
652 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, SLV_5
, SL_MAX_VERSION
),
653 SLE_CONDVAR(Vehicle
, current_order
.flags
, SLE_UINT8
, SLV_5
, SL_MAX_VERSION
),
654 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
656 /* Refit in current order */
657 SLE_CONDVAR(Vehicle
, current_order
.refit_cargo
, SLE_UINT8
, SLV_36
, SL_MAX_VERSION
),
659 /* Timetable in current order */
660 SLE_CONDVAR(Vehicle
, current_order
.wait_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
661 SLE_CONDVAR(Vehicle
, current_order
.travel_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
662 SLE_CONDVAR(Vehicle
, current_order
.max_speed
, SLE_UINT16
, SLV_174
, SL_MAX_VERSION
),
663 SLE_CONDVAR(Vehicle
, timetable_start
, SLE_INT32
, SLV_129
, SL_MAX_VERSION
),
665 SLE_CONDREF(Vehicle
, orders
, REF_ORDER
, SL_MIN_VERSION
, SLV_105
),
666 SLE_CONDREF(Vehicle
, orders
, REF_ORDERLIST
, SLV_105
, SL_MAX_VERSION
),
668 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
669 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
670 SLE_CONDVAR(Vehicle
, max_age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
671 SLE_CONDVAR(Vehicle
, max_age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
672 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
673 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
674 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, SL_MIN_VERSION
, SLV_31
),
675 SLE_CONDVAR(Vehicle
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, SLV_31
, SLV_180
),
676 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, SLV_180
, SL_MAX_VERSION
),
677 SLE_VAR(Vehicle
, reliability
, SLE_UINT16
),
678 SLE_VAR(Vehicle
, reliability_spd_dec
, SLE_UINT16
),
679 SLE_VAR(Vehicle
, breakdown_ctr
, SLE_UINT8
),
680 SLE_VAR(Vehicle
, breakdown_delay
, SLE_UINT8
),
681 SLE_VAR(Vehicle
, breakdowns_since_last_service
, SLE_UINT8
),
682 SLE_VAR(Vehicle
, breakdown_chance
, SLE_UINT8
),
683 SLE_CONDVAR(Vehicle
, build_year
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
684 SLE_CONDVAR(Vehicle
, build_year
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
686 SLE_VAR(Vehicle
, load_unload_ticks
, SLE_UINT16
),
687 SLEG_CONDVAR("cargo_paid_for", _cargo_paid_for
, SLE_UINT16
, SLV_45
, SL_MAX_VERSION
),
688 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_40
, SLV_180
),
689 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_UINT16
, SLV_180
, SL_MAX_VERSION
),
691 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
692 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
693 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
694 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
695 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share
, SLE_FILE_I32
| SLE_VAR_I64
, SLV_51
, SLV_65
),
696 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share
, SLE_INT64
, SLV_65
, SLV_68
),
697 SLEG_CONDVAR("cargo_loaded_at_xy", _cargo_loaded_at_xy
, SLE_UINT32
, SLV_51
, SLV_68
),
698 SLE_CONDVAR(Vehicle
, value
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
699 SLE_CONDVAR(Vehicle
, value
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
701 SLE_CONDVAR(Vehicle
, random_bits
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
702 SLE_CONDVAR(Vehicle
, waiting_triggers
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
704 SLE_CONDREF(Vehicle
, next_shared
, REF_VEHICLE
, SLV_2
, SL_MAX_VERSION
),
705 SLE_CONDVAR(Vehicle
, group_id
, SLE_UINT16
, SLV_60
, SL_MAX_VERSION
),
707 SLE_CONDVAR(Vehicle
, current_order_time
, SLE_UINT32
, SLV_67
, SL_MAX_VERSION
),
708 SLE_CONDVAR(Vehicle
, lateness_counter
, SLE_INT32
, SLV_67
, SL_MAX_VERSION
),
710 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
714 inline const static SaveLoadCompatTable compat_description
= _vehicle_common_sl_compat
;
716 void Save(Vehicle
*v
) const override
718 SlObject(v
, this->GetDescription());
721 void Load(Vehicle
*v
) const override
723 SlObject(v
, this->GetLoadDescription());
726 void FixPointers(Vehicle
*v
) const override
728 SlObject(v
, this->GetDescription());
732 class SlVehicleTrain
: public DefaultSaveLoadHandler
<SlVehicleTrain
, Vehicle
> {
734 inline static const SaveLoad description
[] = {
735 SLEG_STRUCT("common", SlVehicleCommon
),
736 SLE_VAR(Train
, crash_anim_pos
, SLE_UINT16
),
737 SLE_VAR(Train
, force_proceed
, SLE_UINT8
),
738 SLE_VAR(Train
, railtype
, SLE_UINT8
),
739 SLE_VAR(Train
, track
, SLE_UINT8
),
741 SLE_CONDVAR(Train
, flags
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_2
, SLV_100
),
742 SLE_CONDVAR(Train
, flags
, SLE_UINT16
, SLV_100
, SL_MAX_VERSION
),
743 SLE_CONDVAR(Train
, wait_counter
, SLE_UINT16
, SLV_136
, SL_MAX_VERSION
),
744 SLE_CONDVAR(Train
, gv_flags
, SLE_UINT16
, SLV_139
, SL_MAX_VERSION
),
746 inline const static SaveLoadCompatTable compat_description
= _vehicle_train_sl_compat
;
748 void Save(Vehicle
*v
) const override
750 if (v
->type
!= VEH_TRAIN
) return;
751 SlObject(v
, this->GetDescription());
754 void Load(Vehicle
*v
) const override
756 if (v
->type
!= VEH_TRAIN
) return;
757 SlObject(v
, this->GetLoadDescription());
760 void FixPointers(Vehicle
*v
) const override
762 if (v
->type
!= VEH_TRAIN
) return;
763 SlObject(v
, this->GetDescription());
767 class SlVehicleRoadVeh
: public DefaultSaveLoadHandler
<SlVehicleRoadVeh
, Vehicle
> {
769 inline static const SaveLoad description
[] = {
770 SLEG_STRUCT("common", SlVehicleCommon
),
771 SLE_VAR(RoadVehicle
, state
, SLE_UINT8
),
772 SLE_VAR(RoadVehicle
, frame
, SLE_UINT8
),
773 SLE_VAR(RoadVehicle
, blocked_ctr
, SLE_UINT16
),
774 SLE_VAR(RoadVehicle
, overtaking
, SLE_UINT8
),
775 SLE_VAR(RoadVehicle
, overtaking_ctr
, SLE_UINT8
),
776 SLE_VAR(RoadVehicle
, crashed_ctr
, SLE_UINT16
),
777 SLE_VAR(RoadVehicle
, reverse_ctr
, SLE_UINT8
),
778 SLE_CONDDEQUE(RoadVehicle
, path
.td
, SLE_UINT8
, SLV_ROADVEH_PATH_CACHE
, SL_MAX_VERSION
),
779 SLE_CONDDEQUE(RoadVehicle
, path
.tile
, SLE_UINT32
, SLV_ROADVEH_PATH_CACHE
, SL_MAX_VERSION
),
780 SLE_CONDVAR(RoadVehicle
, gv_flags
, SLE_UINT16
, SLV_139
, SL_MAX_VERSION
),
782 inline const static SaveLoadCompatTable compat_description
= _vehicle_roadveh_sl_compat
;
784 void Save(Vehicle
*v
) const override
786 if (v
->type
!= VEH_ROAD
) return;
787 SlObject(v
, this->GetDescription());
790 void Load(Vehicle
*v
) const override
792 if (v
->type
!= VEH_ROAD
) return;
793 SlObject(v
, this->GetLoadDescription());
796 void FixPointers(Vehicle
*v
) const override
798 if (v
->type
!= VEH_ROAD
) return;
799 SlObject(v
, this->GetDescription());
803 class SlVehicleShip
: public DefaultSaveLoadHandler
<SlVehicleShip
, Vehicle
> {
805 inline static const SaveLoad description
[] = {
806 SLEG_STRUCT("common", SlVehicleCommon
),
807 SLE_VAR(Ship
, state
, SLE_UINT8
),
808 SLE_CONDDEQUE(Ship
, path
, SLE_UINT8
, SLV_SHIP_PATH_CACHE
, SL_MAX_VERSION
),
809 SLE_CONDVAR(Ship
, rotation
, SLE_UINT8
, SLV_SHIP_ROTATION
, SL_MAX_VERSION
),
811 inline const static SaveLoadCompatTable compat_description
= _vehicle_ship_sl_compat
;
813 void Save(Vehicle
*v
) const override
815 if (v
->type
!= VEH_SHIP
) return;
816 SlObject(v
, this->GetDescription());
819 void Load(Vehicle
*v
) const override
821 if (v
->type
!= VEH_SHIP
) return;
822 SlObject(v
, this->GetLoadDescription());
825 void FixPointers(Vehicle
*v
) const override
827 if (v
->type
!= VEH_SHIP
) return;
828 SlObject(v
, this->GetDescription());
832 class SlVehicleAircraft
: public DefaultSaveLoadHandler
<SlVehicleAircraft
, Vehicle
> {
834 inline static const SaveLoad description
[] = {
835 SLEG_STRUCT("common", SlVehicleCommon
),
836 SLE_VAR(Aircraft
, crashed_counter
, SLE_UINT16
),
837 SLE_VAR(Aircraft
, pos
, SLE_UINT8
),
839 SLE_CONDVAR(Aircraft
, targetairport
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
840 SLE_CONDVAR(Aircraft
, targetairport
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
842 SLE_VAR(Aircraft
, state
, SLE_UINT8
),
844 SLE_CONDVAR(Aircraft
, previous_pos
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
845 SLE_CONDVAR(Aircraft
, last_direction
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
846 SLE_CONDVAR(Aircraft
, number_consecutive_turns
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
848 SLE_CONDVAR(Aircraft
, turn_counter
, SLE_UINT8
, SLV_136
, SL_MAX_VERSION
),
849 SLE_CONDVAR(Aircraft
, flags
, SLE_UINT8
, SLV_167
, SL_MAX_VERSION
),
851 inline const static SaveLoadCompatTable compat_description
= _vehicle_aircraft_sl_compat
;
853 void Save(Vehicle
*v
) const override
855 if (v
->type
!= VEH_AIRCRAFT
) return;
856 SlObject(v
, this->GetDescription());
859 void Load(Vehicle
*v
) const override
861 if (v
->type
!= VEH_AIRCRAFT
) return;
862 SlObject(v
, this->GetLoadDescription());
865 void FixPointers(Vehicle
*v
) const override
867 if (v
->type
!= VEH_AIRCRAFT
) return;
868 SlObject(v
, this->GetDescription());
872 class SlVehicleEffect
: public DefaultSaveLoadHandler
<SlVehicleEffect
, Vehicle
> {
874 inline static const SaveLoad description
[] = {
875 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
877 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
878 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
880 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
881 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
882 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
883 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
884 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
885 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
887 SLE_VAR(Vehicle
, sprite_cache
.sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
888 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
889 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
891 SLE_VAR(EffectVehicle
, animation_state
, SLE_UINT16
),
892 SLE_VAR(EffectVehicle
, animation_substate
, SLE_UINT8
),
894 SLE_CONDVAR(Vehicle
, spritenum
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
896 inline const static SaveLoadCompatTable compat_description
= _vehicle_effect_sl_compat
;
898 void Save(Vehicle
*v
) const override
900 if (v
->type
!= VEH_EFFECT
) return;
901 SlObject(v
, this->GetDescription());
904 void Load(Vehicle
*v
) const override
906 if (v
->type
!= VEH_EFFECT
) return;
907 SlObject(v
, this->GetLoadDescription());
910 void FixPointers(Vehicle
*v
) const override
912 if (v
->type
!= VEH_EFFECT
) return;
913 SlObject(v
, this->GetDescription());
917 class SlVehicleDisaster
: public DefaultSaveLoadHandler
<SlVehicleDisaster
, Vehicle
> {
919 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
920 /* This table access private members of other classes; they have this
921 * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for
922 * "inline static const", so we are forced to wrap the table in a
923 * function. CL 19.16 is the latest for VS2017. */
924 inline static const SaveLoad description
[] = {{}};
925 SaveLoadTable
GetDescription() const override
{
929 static const SaveLoad description
[] = {
930 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
932 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
933 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
934 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
935 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
936 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
938 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
939 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
940 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
941 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
942 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
943 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
944 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
946 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
947 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
948 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
949 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
951 SLE_VAR(Vehicle
, sprite_cache
.sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
952 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
953 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
954 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
956 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_191
),
957 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_UINT32
, SLV_191
, SL_MAX_VERSION
),
958 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_191
),
959 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_UINT32
, SLV_191
, SL_MAX_VERSION
),
960 SLE_CONDVAR(DisasterVehicle
, flags
, SLE_UINT8
, SLV_194
, SL_MAX_VERSION
),
962 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
966 inline const static SaveLoadCompatTable compat_description
= _vehicle_disaster_sl_compat
;
968 void Save(Vehicle
*v
) const override
970 if (v
->type
!= VEH_DISASTER
) return;
971 SlObject(v
, this->GetDescription());
974 void Load(Vehicle
*v
) const override
976 if (v
->type
!= VEH_DISASTER
) return;
977 SlObject(v
, this->GetLoadDescription());
980 void FixPointers(Vehicle
*v
) const override
982 if (v
->type
!= VEH_DISASTER
) return;
983 SlObject(v
, this->GetDescription());
987 const static SaveLoad _vehicle_desc
[] = {
988 SLE_SAVEBYTE(Vehicle
, type
),
989 SLEG_STRUCT("train", SlVehicleTrain
),
990 SLEG_STRUCT("roadveh", SlVehicleRoadVeh
),
991 SLEG_STRUCT("ship", SlVehicleShip
),
992 SLEG_STRUCT("aircraft", SlVehicleAircraft
),
993 SLEG_STRUCT("effect", SlVehicleEffect
),
994 SLEG_STRUCT("disaster", SlVehicleDisaster
),
997 struct VEHSChunkHandler
: ChunkHandler
{
998 VEHSChunkHandler() : ChunkHandler('VEHS', CH_SPARSE_TABLE
) {}
1000 void Save() const override
1002 SlTableHeader(_vehicle_desc
);
1004 /* Write the vehicles */
1005 for (Vehicle
*v
: Vehicle::Iterate()) {
1006 SlSetArrayIndex(v
->index
);
1007 SlObject(v
, _vehicle_desc
);
1011 void Load() const override
1013 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(_vehicle_desc
, _vehicle_sl_compat
);
1019 while ((index
= SlIterateArray()) != -1) {
1021 VehicleType vtype
= (VehicleType
)SlReadByte();
1024 case VEH_TRAIN
: v
= new (index
) Train(); break;
1025 case VEH_ROAD
: v
= new (index
) RoadVehicle(); break;
1026 case VEH_SHIP
: v
= new (index
) Ship(); break;
1027 case VEH_AIRCRAFT
: v
= new (index
) Aircraft(); break;
1028 case VEH_EFFECT
: v
= new (index
) EffectVehicle(); break;
1029 case VEH_DISASTER
: v
= new (index
) DisasterVehicle(); break;
1030 case VEH_INVALID
: // Savegame shouldn't contain invalid vehicles
1031 default: SlErrorCorrupt("Invalid vehicle type");
1036 if (_cargo_count
!= 0 && IsCompanyBuildableVehicleType(v
) && CargoPacket::CanAllocateItem()) {
1037 /* Don't construct the packet with station here, because that'll fail with old savegames */
1038 CargoPacket
*cp
= new CargoPacket(_cargo_count
, _cargo_days
, _cargo_source
, _cargo_source_xy
, _cargo_loaded_at_xy
, _cargo_feeder_share
);
1039 v
->cargo
.Append(cp
);
1042 /* Old savegames used 'last_station_visited = 0xFF' */
1043 if (IsSavegameVersionBefore(SLV_5
) && v
->last_station_visited
== 0xFF) {
1044 v
->last_station_visited
= INVALID_STATION
;
1047 if (IsSavegameVersionBefore(SLV_182
)) v
->last_loading_station
= INVALID_STATION
;
1049 if (IsSavegameVersionBefore(SLV_5
)) {
1050 /* Convert the current_order.type (which is a mix of type and flags, because
1051 * in those versions, they both were 4 bits big) to type and flags */
1052 v
->current_order
.flags
= GB(v
->current_order
.type
, 4, 4);
1053 v
->current_order
.type
&= 0x0F;
1056 /* Advanced vehicle lists got added */
1057 if (IsSavegameVersionBefore(SLV_60
)) v
->group_id
= DEFAULT_GROUP
;
1061 void FixPointers() const override
1063 for (Vehicle
*v
: Vehicle::Iterate()) {
1064 SlObject(v
, _vehicle_desc
);
1069 static const VEHSChunkHandler VEHS
;
1070 static const ChunkHandlerRef veh_chunk_handlers
[] = {
1074 extern const ChunkHandlerTable
_veh_chunk_handlers(veh_chunk_handlers
);