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 "../timetable.h"
21 #include "../station_base.h"
22 #include "../effectvehicle_base.h"
23 #include "../company_base.h"
24 #include "../company_func.h"
25 #include "../disaster_vehicle.h"
26 #include "../economy_base.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
));
203 /* Clear aircraft from loading vehicles, if we bumped them into the air. */
204 for (Station
*st
: Station::Iterate()) {
205 for (auto iter
= st
->loading_vehicles
.begin(); iter
!= st
->loading_vehicles
.end(); /* nothing */) {
207 if (v
->type
== VEH_AIRCRAFT
&& !v
->current_order
.IsType(OT_LOADING
)) {
208 iter
= st
->loading_vehicles
.erase(iter
);
209 delete v
->cargo_payment
;
218 * Check all vehicles to ensure their engine type is valid
219 * for the currently loaded NewGRFs (that includes none...)
220 * This only makes a difference if NewGRFs are missing, otherwise
221 * all vehicles will be valid. This does not make such a game
222 * playable, it only prevents crash.
224 static void CheckValidVehicles()
226 size_t total_engines
= Engine::GetPoolSize();
227 EngineID first_engine
[4] = { INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
};
229 for (const Engine
*e
: Engine::IterateType(VEH_TRAIN
)) { first_engine
[VEH_TRAIN
] = e
->index
; break; }
230 for (const Engine
*e
: Engine::IterateType(VEH_ROAD
)) { first_engine
[VEH_ROAD
] = e
->index
; break; }
231 for (const Engine
*e
: Engine::IterateType(VEH_SHIP
)) { first_engine
[VEH_SHIP
] = e
->index
; break; }
232 for (const Engine
*e
: Engine::IterateType(VEH_AIRCRAFT
)) { first_engine
[VEH_AIRCRAFT
] = e
->index
; break; }
234 for (Vehicle
*v
: Vehicle::Iterate()) {
235 /* Test if engine types match */
241 if (v
->engine_type
>= total_engines
|| v
->type
!= v
->GetEngine()->type
) {
242 v
->engine_type
= first_engine
[v
->type
];
252 extern uint8_t _age_cargo_skip_counter
; // From misc_sl.cpp
254 /** Called after load to update coordinates */
255 void AfterLoadVehicles(bool part_of_load
)
257 for (Vehicle
*v
: Vehicle::Iterate()) {
258 /* Reinstate the previous pointer */
259 if (v
->Next() != nullptr) v
->Next()->previous
= v
;
260 if (v
->NextShared() != nullptr) v
->NextShared()->previous_shared
= v
;
262 if (part_of_load
) v
->fill_percent_te_id
= INVALID_TE_ID
;
264 if (v
->IsGroundVehicle()) v
->GetGroundVehicleCache()->first_engine
= INVALID_ENGINE
;
267 /* AfterLoadVehicles may also be called in case of NewGRF reload, in this
268 * case we may not convert orders again. */
270 /* Create shared vehicle chain for very old games (pre 5,2) and create
271 * OrderList from shared vehicle chains. For this to work correctly, the
272 * following conditions must be fulfilled:
273 * a) both next_shared and previous_shared are not set for pre 5,2 games
274 * b) both next_shared and previous_shared are set for later games
276 std::map
<Order
*, OrderList
*> mapping
;
278 for (Vehicle
*v
: Vehicle::Iterate()) {
279 if (v
->old_orders
!= nullptr) {
280 if (IsSavegameVersionBefore(SLV_105
)) { // Pre-105 didn't save an OrderList
281 if (mapping
[v
->old_orders
] == nullptr) {
282 /* This adds the whole shared vehicle chain for case b */
284 /* Creating an OrderList here is safe because the number of vehicles
285 * allowed in these savegames matches the number of OrderLists. As
286 * such each vehicle can get an OrderList and it will (still) fit. */
287 assert(OrderList::CanAllocateItem());
288 v
->orders
= mapping
[v
->old_orders
] = new OrderList(v
->old_orders
, v
);
290 v
->orders
= mapping
[v
->old_orders
];
291 /* For old games (case a) we must create the shared vehicle chain */
292 if (IsSavegameVersionBefore(SLV_5
, 2)) {
293 v
->AddToShared(v
->orders
->GetFirstSharedVehicle());
296 } else { // OrderList was saved as such, only recalculate not saved values
297 if (v
->PreviousShared() == nullptr) {
298 v
->orders
->Initialize(v
->orders
->first
, v
);
305 for (Vehicle
*v
: Vehicle::Iterate()) {
306 /* Fill the first pointers */
307 if (v
->Previous() == nullptr) {
308 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
315 if (IsSavegameVersionBefore(SLV_105
)) {
316 /* Before 105 there was no order for shared orders, thus it messed up horribly */
317 for (Vehicle
*v
: Vehicle::Iterate()) {
318 if (v
->First() != v
|| v
->orders
!= nullptr || v
->previous_shared
!= nullptr || v
->next_shared
== nullptr) continue;
320 /* As above, allocating OrderList here is safe. */
321 assert(OrderList::CanAllocateItem());
322 v
->orders
= new OrderList(nullptr, v
);
323 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->next_shared
) {
324 u
->orders
= v
->orders
;
329 if (IsSavegameVersionBefore(SLV_157
)) {
330 /* The road vehicle subtype was converted to a flag. */
331 for (RoadVehicle
*rv
: RoadVehicle::Iterate()) {
332 if (rv
->subtype
== 0) {
333 /* The road vehicle is at the front. */
334 rv
->SetFrontEngine();
335 } else if (rv
->subtype
== 1) {
336 /* The road vehicle is an articulated part. */
338 rv
->SetArticulatedPart();
340 SlErrorCorrupt("Invalid road vehicle subtype");
345 if (IsSavegameVersionBefore(SLV_160
)) {
346 /* In some old savegames there might be some "crap" stored. */
347 for (Vehicle
*v
: Vehicle::Iterate()) {
348 if (!v
->IsPrimaryVehicle() && v
->type
!= VEH_DISASTER
) {
349 v
->current_order
.Free();
355 if (IsSavegameVersionBefore(SLV_162
)) {
356 /* Set the vehicle-local cargo age counter from the old global counter. */
357 for (Vehicle
*v
: Vehicle::Iterate()) {
358 v
->cargo_age_counter
= _age_cargo_skip_counter
;
362 if (IsSavegameVersionBefore(SLV_180
)) {
363 /* Set service interval flags */
364 for (Vehicle
*v
: Vehicle::Iterate()) {
365 if (!v
->IsPrimaryVehicle()) continue;
367 const Company
*c
= Company::Get(v
->owner
);
368 int interval
= CompanyServiceInterval(c
, v
->type
);
370 v
->SetServiceIntervalIsCustom(v
->GetServiceInterval() != interval
);
371 v
->SetServiceIntervalIsPercent(c
->settings
.vehicle
.servint_ispercent
);
375 if (IsSavegameVersionBefore(SLV_SHIP_ROTATION
)) {
376 /* Ship rotation added */
377 for (Ship
*s
: Ship::Iterate()) {
378 s
->rotation
= s
->direction
;
381 for (Ship
*s
: Ship::Iterate()) {
382 if (s
->rotation
== s
->direction
) continue;
383 /* In case we are rotating on gameload, set the rotation position to
384 * the current position, otherwise the applied workaround offset would
385 * be with respect to 0,0.
387 s
->rotation_x_pos
= s
->x_pos
;
388 s
->rotation_y_pos
= s
->y_pos
;
392 if (IsSavegameVersionBefore(SLV_TIMETABLE_START_TICKS
)) {
393 /* Convert timetable start from a date to an absolute tick in TimerGameTick::counter. */
394 for (Vehicle
*v
: Vehicle::Iterate()) {
395 /* If the start date is 0, the vehicle is not waiting to start and can be ignored. */
396 if (v
->timetable_start
== 0) continue;
398 v
->timetable_start
= GetStartTickFromDate(v
->timetable_start
);
402 if (IsSavegameVersionBefore(SLV_VEHICLE_ECONOMY_AGE
)) {
403 /* Set vehicle economy age based on calendar age. */
404 for (Vehicle
*v
: Vehicle::Iterate()) {
405 v
->economy_age
= v
->age
.base();
410 CheckValidVehicles();
412 for (Vehicle
*v
: Vehicle::Iterate()) {
413 assert(v
->first
!= nullptr);
415 v
->trip_occupancy
= CalcPercentVehicleFilled(v
, nullptr);
419 Train
*t
= Train::From(v
);
420 if (t
->IsFrontEngine() || t
->IsFreeWagon()) {
421 t
->gcache
.last_speed
= t
->cur_speed
; // update displayed train speed
422 t
->ConsistChanged(CCF_SAVELOAD
);
428 RoadVehicle
*rv
= RoadVehicle::From(v
);
429 if (rv
->IsFrontEngine()) {
430 rv
->gcache
.last_speed
= rv
->cur_speed
; // update displayed road vehicle speed
432 rv
->roadtype
= Engine::Get(rv
->engine_type
)->u
.road
.roadtype
;
433 rv
->compatible_roadtypes
= GetRoadTypeInfo(rv
->roadtype
)->powered_roadtypes
;
434 RoadTramType rtt
= GetRoadTramType(rv
->roadtype
);
435 for (RoadVehicle
*u
= rv
; u
!= nullptr; u
= u
->Next()) {
436 u
->roadtype
= rv
->roadtype
;
437 u
->compatible_roadtypes
= rv
->compatible_roadtypes
;
438 if (GetRoadType(u
->tile
, rtt
) == INVALID_ROADTYPE
) SlErrorCorrupt("Road vehicle on invalid road type");
441 RoadVehUpdateCache(rv
);
442 if (_settings_game
.vehicle
.roadveh_acceleration_model
!= AM_ORIGINAL
) {
450 Ship::From(v
)->UpdateCache();
457 /* Stop non-front engines */
458 if (part_of_load
&& IsSavegameVersionBefore(SLV_112
)) {
459 for (Vehicle
*v
: Vehicle::Iterate()) {
460 if (v
->type
== VEH_TRAIN
) {
461 Train
*t
= Train::From(v
);
462 if (!t
->IsFrontEngine()) {
463 if (t
->IsEngine()) t
->vehstatus
|= VS_STOPPED
;
464 /* cur_speed is now relevant for non-front parts - nonzero breaks
465 * moving-wagons-inside-depot- and autoreplace- code */
469 /* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
470 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
471 if ((v
->vehstatus
& VS_STOPPED
) && (v
->type
!= VEH_TRAIN
|| IsSavegameVersionBefore(SLV_2
, 1))) {
477 for (Vehicle
*v
: Vehicle::Iterate()) {
482 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_cache
.sprite_seq
);
486 if (Aircraft::From(v
)->IsNormalAircraft()) {
487 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_cache
.sprite_seq
);
489 /* The aircraft's shadow will have the same image as the aircraft, but no colour */
490 Vehicle
*shadow
= v
->Next();
491 if (shadow
== nullptr) SlErrorCorrupt("Missing shadow for aircraft");
493 shadow
->sprite_cache
.sprite_seq
.CopyWithoutPalette(v
->sprite_cache
.sprite_seq
);
495 /* In the case of a helicopter we will update the rotor sprites */
496 if (v
->subtype
== AIR_HELICOPTER
) {
497 Vehicle
*rotor
= shadow
->Next();
498 if (rotor
== nullptr) SlErrorCorrupt("Missing rotor for helicopter");
500 GetRotorImage(Aircraft::From(v
), EIT_ON_MAP
, &rotor
->sprite_cache
.sprite_seq
);
503 UpdateAircraftCache(Aircraft::From(v
), true);
508 auto *dv
= DisasterVehicle::From(v
);
509 if (dv
->subtype
== ST_SMALL_UFO
&& dv
->state
!= 0) {
510 RoadVehicle
*u
= RoadVehicle::GetIfValid(v
->dest_tile
.base());
511 if (u
!= nullptr && u
->IsFrontEngine()) {
512 /* Delete UFO targetting a vehicle which is already a target. */
513 if (u
->disaster_vehicle
!= INVALID_VEHICLE
&& u
->disaster_vehicle
!= dv
->index
) {
517 u
->disaster_vehicle
= dv
->index
;
527 if (part_of_load
&& v
->unitnumber
!= 0) {
528 Company::Get(v
->owner
)->freeunits
[v
->type
].UseID(v
->unitnumber
);
532 v
->coord
.left
= INVALID_COORD
;
533 v
->sprite_cache
.old_coord
.left
= INVALID_COORD
;
535 v
->UpdateViewport(false);
539 bool TrainController(Train
*v
, Vehicle
*nomove
, bool reverse
= true); // From train_cmd.cpp
540 void ReverseTrainDirection(Train
*v
);
541 void ReverseTrainSwapVeh(Train
*v
, int l
, int r
);
543 /** Fixup old train spacing. */
544 void FixupTrainLengths()
546 /* Vehicle center was moved from 4 units behind the front to half the length
547 * behind the front. Move vehicles so they end up on the same spot. */
548 for (Vehicle
*v
: Vehicle::Iterate()) {
549 if (v
->type
== VEH_TRAIN
&& v
->IsPrimaryVehicle()) {
550 /* The vehicle center is now more to the front depending on vehicle length,
551 * so we need to move all vehicles forward to cover the difference to the
552 * old center, otherwise wagon spacing in trains would be broken upon load. */
553 for (Train
*u
= Train::From(v
); u
!= nullptr; u
= u
->Next()) {
554 if (u
->track
== TRACK_BIT_DEPOT
|| (u
->vehstatus
& VS_CRASHED
)) continue;
556 Train
*next
= u
->Next();
558 /* Try to pull the vehicle half its length forward. */
559 int diff
= (VEHICLE_LENGTH
- u
->gcache
.cached_veh_length
) / 2;
561 for (done
= 0; done
< diff
; done
++) {
562 if (!TrainController(u
, next
, false)) break;
565 if (next
!= nullptr && done
< diff
&& u
->IsFrontEngine()) {
566 /* Pulling the front vehicle forwards failed, we either encountered a dead-end
567 * or a red signal. To fix this, we try to move the whole train the required
568 * space backwards and re-do the fix up of the front vehicle. */
570 /* Ignore any signals when backtracking. */
571 TrainForceProceeding old_tfp
= u
->force_proceed
;
572 u
->force_proceed
= TFP_SIGNAL
;
574 /* Swap start<>end, start+1<>end-1, ... */
575 int r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
577 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
579 /* We moved the first vehicle which is now the last. Move it back to the
580 * original position as we will fix up the last vehicle later in the loop. */
581 for (int i
= 0; i
< done
; i
++) TrainController(u
->Last(), nullptr);
583 /* Move the train backwards to get space for the first vehicle. As the stopping
584 * distance from a line end is rounded up, move the train one unit more to cater
585 * for front vehicles with odd lengths. */
587 for (moved
= 0; moved
< diff
+ 1; moved
++) {
588 if (!TrainController(u
, nullptr, false)) break;
591 /* Swap start<>end, start+1<>end-1, ... again. */
592 r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
594 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
596 u
->force_proceed
= old_tfp
;
598 /* Tracks are too short to fix the train length. The player has to fix the
599 * train in a depot. Bail out so we don't damage the vehicle chain any more. */
600 if (moved
< diff
+ 1) break;
602 /* Re-do the correction for the first vehicle. */
603 for (done
= 0; done
< diff
; done
++) TrainController(u
, next
, false);
605 /* We moved one unit more backwards than needed for even-length front vehicles,
606 * try to move that unit forward again. We don't care if this step fails. */
607 TrainController(u
, nullptr, false);
610 /* If the next wagon is still in a depot, check if it shouldn't be outside already. */
611 if (next
!= nullptr && next
->track
== TRACK_BIT_DEPOT
) {
612 int d
= TicksToLeaveDepot(u
);
614 /* Next vehicle should have left the depot already, show it and pull forward. */
615 next
->vehstatus
&= ~VS_HIDDEN
;
616 next
->track
= TrackToTrackBits(GetRailDepotTrack(next
->tile
));
617 for (int i
= 0; i
>= d
; i
--) TrainController(next
, nullptr);
622 /* Update all cached properties after moving the vehicle chain around. */
623 Train::From(v
)->ConsistChanged(CCF_TRACK
);
628 static uint8_t _cargo_periods
;
629 static uint16_t _cargo_source
;
630 static uint32_t _cargo_source_xy
;
631 static uint16_t _cargo_count
;
632 static uint16_t _cargo_paid_for
;
633 static Money _cargo_feeder_share
;
635 class SlVehicleCommon
: public DefaultSaveLoadHandler
<SlVehicleCommon
, Vehicle
> {
637 inline static const SaveLoad description
[] = {
638 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
640 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
641 SLE_CONDVAR(Vehicle
, name
, SLE_NAME
, SL_MIN_VERSION
, SLV_84
),
642 SLE_CONDSSTR(Vehicle
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, SLV_84
, SL_MAX_VERSION
),
643 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_8
),
644 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_UINT16
, SLV_8
, SL_MAX_VERSION
),
645 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
646 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
647 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
648 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
649 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
651 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
652 SLE_CONDVAR(Vehicle
, x_pos
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
653 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
654 SLE_CONDVAR(Vehicle
, y_pos
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
655 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
656 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
657 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
659 SLE_VAR(Vehicle
, spritenum
, SLE_UINT8
),
660 SLE_VAR(Vehicle
, engine_type
, SLE_UINT16
),
661 SLE_VAR(Vehicle
, cur_speed
, SLE_UINT16
),
662 SLE_VAR(Vehicle
, subspeed
, SLE_UINT8
),
663 SLE_VAR(Vehicle
, acceleration
, SLE_UINT8
),
664 SLE_CONDVAR(Vehicle
, motion_counter
, SLE_UINT32
, SLV_VEH_MOTION_COUNTER
, SL_MAX_VERSION
),
665 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
667 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
668 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
669 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
670 SLE_CONDVAR(Vehicle
, last_loading_station
, SLE_UINT16
, SLV_182
, SL_MAX_VERSION
),
672 SLE_VAR(Vehicle
, cargo_type
, SLE_UINT8
),
673 SLE_CONDVAR(Vehicle
, cargo_subtype
, SLE_UINT8
, SLV_35
, SL_MAX_VERSION
),
674 SLEG_CONDVAR("cargo_days", _cargo_periods
, SLE_UINT8
, SL_MIN_VERSION
, SLV_68
),
675 SLEG_CONDVAR("cargo_source", _cargo_source
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_7
),
676 SLEG_CONDVAR("cargo_source", _cargo_source
, SLE_UINT16
, SLV_7
, SLV_68
),
677 SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy
, SLE_UINT32
, SLV_44
, SLV_68
),
678 SLE_VAR(Vehicle
, cargo_cap
, SLE_UINT16
),
679 SLE_CONDVAR(Vehicle
, refit_cap
, SLE_UINT16
, SLV_182
, SL_MAX_VERSION
),
680 SLEG_CONDVAR("cargo_count", _cargo_count
, SLE_UINT16
, SL_MIN_VERSION
, SLV_68
),
681 SLE_CONDREFLIST(Vehicle
, cargo
.packets
, REF_CARGO_PACKET
, SLV_68
, SL_MAX_VERSION
),
682 SLE_CONDARR(Vehicle
, cargo
.action_counts
, SLE_UINT
, VehicleCargoList::NUM_MOVE_TO_ACTION
, SLV_181
, SL_MAX_VERSION
),
683 SLE_CONDVAR(Vehicle
, cargo_age_counter
, SLE_UINT16
, SLV_162
, SL_MAX_VERSION
),
685 SLE_VAR(Vehicle
, day_counter
, SLE_UINT8
),
686 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
687 SLE_CONDVAR(Vehicle
, running_ticks
, SLE_UINT8
, SLV_88
, SL_MAX_VERSION
),
689 SLE_VAR(Vehicle
, cur_implicit_order_index
, SLE_UINT8
),
690 SLE_CONDVAR(Vehicle
, cur_real_order_index
, SLE_UINT8
, SLV_158
, SL_MAX_VERSION
),
692 /* This next line is for version 4 and prior compatibility.. it temporarily reads
693 type and flags (which were both 4 bits) into type. Later on this is
694 converted correctly */
695 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, SL_MIN_VERSION
, SLV_5
),
696 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
698 /* Orders for version 5 and on */
699 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, SLV_5
, SL_MAX_VERSION
),
700 SLE_CONDVAR(Vehicle
, current_order
.flags
, SLE_UINT8
, SLV_5
, SL_MAX_VERSION
),
701 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
703 /* Refit in current order */
704 SLE_CONDVAR(Vehicle
, current_order
.refit_cargo
, SLE_UINT8
, SLV_36
, SL_MAX_VERSION
),
706 /* Timetable in current order */
707 SLE_CONDVAR(Vehicle
, current_order
.wait_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
708 SLE_CONDVAR(Vehicle
, current_order
.travel_time
, SLE_UINT16
, SLV_67
, SL_MAX_VERSION
),
709 SLE_CONDVAR(Vehicle
, current_order
.max_speed
, SLE_UINT16
, SLV_174
, SL_MAX_VERSION
),
710 SLE_CONDVAR(Vehicle
, timetable_start
, SLE_FILE_I32
| SLE_VAR_U64
, SLV_129
, SLV_TIMETABLE_START_TICKS
),
711 SLE_CONDVAR(Vehicle
, timetable_start
, SLE_UINT64
, SLV_TIMETABLE_START_TICKS
, SL_MAX_VERSION
),
713 SLE_CONDREF(Vehicle
, orders
, REF_ORDER
, SL_MIN_VERSION
, SLV_105
),
714 SLE_CONDREF(Vehicle
, orders
, REF_ORDERLIST
, SLV_105
, SL_MAX_VERSION
),
716 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
717 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
718 SLE_CONDVAR(Vehicle
, economy_age
, SLE_INT32
, SLV_VEHICLE_ECONOMY_AGE
, SL_MAX_VERSION
),
719 SLE_CONDVAR(Vehicle
, max_age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
720 SLE_CONDVAR(Vehicle
, max_age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
721 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
722 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
723 SLE_CONDVAR(Vehicle
, date_of_last_service_newgrf
, SLE_INT32
, SLV_NEWGRF_LAST_SERVICE
, SL_MAX_VERSION
),
724 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, SL_MIN_VERSION
, SLV_31
),
725 SLE_CONDVAR(Vehicle
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, SLV_31
, SLV_180
),
726 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, SLV_180
, SL_MAX_VERSION
),
727 SLE_VAR(Vehicle
, reliability
, SLE_UINT16
),
728 SLE_VAR(Vehicle
, reliability_spd_dec
, SLE_UINT16
),
729 SLE_VAR(Vehicle
, breakdown_ctr
, SLE_UINT8
),
730 SLE_VAR(Vehicle
, breakdown_delay
, SLE_UINT8
),
731 SLE_VAR(Vehicle
, breakdowns_since_last_service
, SLE_UINT8
),
732 SLE_VAR(Vehicle
, breakdown_chance
, SLE_UINT8
),
733 SLE_CONDVAR(Vehicle
, build_year
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
734 SLE_CONDVAR(Vehicle
, build_year
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
736 SLE_VAR(Vehicle
, load_unload_ticks
, SLE_UINT16
),
737 SLEG_CONDVAR("cargo_paid_for", _cargo_paid_for
, SLE_UINT16
, SLV_45
, SL_MAX_VERSION
),
738 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_40
, SLV_180
),
739 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_UINT16
, SLV_180
, SL_MAX_VERSION
),
741 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
742 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
743 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
744 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
745 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share
, SLE_FILE_I32
| SLE_VAR_I64
, SLV_51
, SLV_65
),
746 SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share
, SLE_INT64
, SLV_65
, SLV_68
),
747 SLE_CONDVAR(Vehicle
, value
, SLE_FILE_I32
| SLE_VAR_I64
, SL_MIN_VERSION
, SLV_65
),
748 SLE_CONDVAR(Vehicle
, value
, SLE_INT64
, SLV_65
, SL_MAX_VERSION
),
750 SLE_CONDVAR(Vehicle
, random_bits
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_2
, SLV_EXTEND_VEHICLE_RANDOM
),
751 SLE_CONDVAR(Vehicle
, random_bits
, SLE_UINT16
, SLV_EXTEND_VEHICLE_RANDOM
, SL_MAX_VERSION
),
752 SLE_CONDVAR(Vehicle
, waiting_triggers
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
754 SLE_CONDREF(Vehicle
, next_shared
, REF_VEHICLE
, SLV_2
, SL_MAX_VERSION
),
755 SLE_CONDVAR(Vehicle
, group_id
, SLE_UINT16
, SLV_60
, SL_MAX_VERSION
),
757 SLE_CONDVAR(Vehicle
, current_order_time
, SLE_FILE_U32
| SLE_VAR_I32
, SLV_67
, SLV_TIMETABLE_TICKS_TYPE
),
758 SLE_CONDVAR(Vehicle
, current_order_time
, SLE_INT32
, SLV_TIMETABLE_TICKS_TYPE
, SL_MAX_VERSION
),
759 SLE_CONDVAR(Vehicle
, last_loading_tick
, SLE_UINT64
, SLV_LAST_LOADING_TICK
, SL_MAX_VERSION
),
760 SLE_CONDVAR(Vehicle
, lateness_counter
, SLE_INT32
, SLV_67
, SL_MAX_VERSION
),
762 SLE_CONDVAR(Vehicle
, depot_unbunching_last_departure
, SLE_UINT64
, SLV_DEPOT_UNBUNCHING
, SL_MAX_VERSION
),
763 SLE_CONDVAR(Vehicle
, depot_unbunching_next_departure
, SLE_UINT64
, SLV_DEPOT_UNBUNCHING
, SL_MAX_VERSION
),
764 SLE_CONDVAR(Vehicle
, round_trip_time
, SLE_INT32
, SLV_DEPOT_UNBUNCHING
, SL_MAX_VERSION
),
767 inline const static SaveLoadCompatTable compat_description
= _vehicle_common_sl_compat
;
769 void Save(Vehicle
*v
) const override
771 SlObject(v
, this->GetDescription());
774 void Load(Vehicle
*v
) const override
776 SlObject(v
, this->GetLoadDescription());
779 void FixPointers(Vehicle
*v
) const override
781 SlObject(v
, this->GetDescription());
785 class SlVehicleTrain
: public DefaultSaveLoadHandler
<SlVehicleTrain
, Vehicle
> {
787 inline static const SaveLoad description
[] = {
788 SLEG_STRUCT("common", SlVehicleCommon
),
789 SLE_VAR(Train
, crash_anim_pos
, SLE_UINT16
),
790 SLE_VAR(Train
, force_proceed
, SLE_UINT8
),
791 SLE_VAR(Train
, railtype
, SLE_UINT8
),
792 SLE_VAR(Train
, track
, SLE_UINT8
),
794 SLE_CONDVAR(Train
, flags
, SLE_FILE_U8
| SLE_VAR_U16
, SLV_2
, SLV_100
),
795 SLE_CONDVAR(Train
, flags
, SLE_UINT16
, SLV_100
, SL_MAX_VERSION
),
796 SLE_CONDVAR(Train
, wait_counter
, SLE_UINT16
, SLV_136
, SL_MAX_VERSION
),
797 SLE_CONDVAR(Train
, gv_flags
, SLE_UINT16
, SLV_139
, SL_MAX_VERSION
),
799 inline const static SaveLoadCompatTable compat_description
= _vehicle_train_sl_compat
;
801 void Save(Vehicle
*v
) const override
803 if (v
->type
!= VEH_TRAIN
) return;
804 SlObject(v
, this->GetDescription());
807 void Load(Vehicle
*v
) const override
809 if (v
->type
!= VEH_TRAIN
) return;
810 SlObject(v
, this->GetLoadDescription());
813 void FixPointers(Vehicle
*v
) const override
815 if (v
->type
!= VEH_TRAIN
) return;
816 SlObject(v
, this->GetDescription());
820 class SlVehicleRoadVeh
: public DefaultSaveLoadHandler
<SlVehicleRoadVeh
, Vehicle
> {
822 inline static const SaveLoad description
[] = {
823 SLEG_STRUCT("common", SlVehicleCommon
),
824 SLE_VAR(RoadVehicle
, state
, SLE_UINT8
),
825 SLE_VAR(RoadVehicle
, frame
, SLE_UINT8
),
826 SLE_VAR(RoadVehicle
, blocked_ctr
, SLE_UINT16
),
827 SLE_VAR(RoadVehicle
, overtaking
, SLE_UINT8
),
828 SLE_VAR(RoadVehicle
, overtaking_ctr
, SLE_UINT8
),
829 SLE_VAR(RoadVehicle
, crashed_ctr
, SLE_UINT16
),
830 SLE_VAR(RoadVehicle
, reverse_ctr
, SLE_UINT8
),
831 SLE_CONDDEQUE(RoadVehicle
, path
.td
, SLE_UINT8
, SLV_ROADVEH_PATH_CACHE
, SL_MAX_VERSION
),
832 SLE_CONDDEQUE(RoadVehicle
, path
.tile
, SLE_UINT32
, SLV_ROADVEH_PATH_CACHE
, SL_MAX_VERSION
),
833 SLE_CONDVAR(RoadVehicle
, gv_flags
, SLE_UINT16
, SLV_139
, SL_MAX_VERSION
),
835 inline const static SaveLoadCompatTable compat_description
= _vehicle_roadveh_sl_compat
;
837 void Save(Vehicle
*v
) const override
839 if (v
->type
!= VEH_ROAD
) return;
840 SlObject(v
, this->GetDescription());
843 void Load(Vehicle
*v
) const override
845 if (v
->type
!= VEH_ROAD
) return;
846 SlObject(v
, this->GetLoadDescription());
849 void FixPointers(Vehicle
*v
) const override
851 if (v
->type
!= VEH_ROAD
) return;
852 SlObject(v
, this->GetDescription());
856 class SlVehicleShip
: public DefaultSaveLoadHandler
<SlVehicleShip
, Vehicle
> {
858 inline static const SaveLoad description
[] = {
859 SLEG_STRUCT("common", SlVehicleCommon
),
860 SLE_VAR(Ship
, state
, SLE_UINT8
),
861 SLE_CONDDEQUE(Ship
, path
, SLE_UINT8
, SLV_SHIP_PATH_CACHE
, SL_MAX_VERSION
),
862 SLE_CONDVAR(Ship
, rotation
, SLE_UINT8
, SLV_SHIP_ROTATION
, SL_MAX_VERSION
),
864 inline const static SaveLoadCompatTable compat_description
= _vehicle_ship_sl_compat
;
866 void Save(Vehicle
*v
) const override
868 if (v
->type
!= VEH_SHIP
) return;
869 SlObject(v
, this->GetDescription());
872 void Load(Vehicle
*v
) const override
874 if (v
->type
!= VEH_SHIP
) return;
875 SlObject(v
, this->GetLoadDescription());
878 void FixPointers(Vehicle
*v
) const override
880 if (v
->type
!= VEH_SHIP
) return;
881 SlObject(v
, this->GetDescription());
885 class SlVehicleAircraft
: public DefaultSaveLoadHandler
<SlVehicleAircraft
, Vehicle
> {
887 inline static const SaveLoad description
[] = {
888 SLEG_STRUCT("common", SlVehicleCommon
),
889 SLE_VAR(Aircraft
, crashed_counter
, SLE_UINT16
),
890 SLE_VAR(Aircraft
, pos
, SLE_UINT8
),
892 SLE_CONDVAR(Aircraft
, targetairport
, SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
893 SLE_CONDVAR(Aircraft
, targetairport
, SLE_UINT16
, SLV_5
, SL_MAX_VERSION
),
895 SLE_VAR(Aircraft
, state
, SLE_UINT8
),
897 SLE_CONDVAR(Aircraft
, previous_pos
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
898 SLE_CONDVAR(Aircraft
, last_direction
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
899 SLE_CONDVAR(Aircraft
, number_consecutive_turns
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
901 SLE_CONDVAR(Aircraft
, turn_counter
, SLE_UINT8
, SLV_136
, SL_MAX_VERSION
),
902 SLE_CONDVAR(Aircraft
, flags
, SLE_UINT8
, SLV_167
, SL_MAX_VERSION
),
904 inline const static SaveLoadCompatTable compat_description
= _vehicle_aircraft_sl_compat
;
906 void Save(Vehicle
*v
) const override
908 if (v
->type
!= VEH_AIRCRAFT
) return;
909 SlObject(v
, this->GetDescription());
912 void Load(Vehicle
*v
) const override
914 if (v
->type
!= VEH_AIRCRAFT
) return;
915 SlObject(v
, this->GetLoadDescription());
918 void FixPointers(Vehicle
*v
) const override
920 if (v
->type
!= VEH_AIRCRAFT
) return;
921 SlObject(v
, this->GetDescription());
925 class SlVehicleEffect
: public DefaultSaveLoadHandler
<SlVehicleEffect
, Vehicle
> {
927 inline static const SaveLoad description
[] = {
928 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
930 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
931 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
933 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
934 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
935 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
936 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
937 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
938 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
940 SLE_VAR(Vehicle
, sprite_cache
.sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
941 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
942 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
944 SLE_VAR(EffectVehicle
, animation_state
, SLE_UINT16
),
945 SLE_VAR(EffectVehicle
, animation_substate
, SLE_UINT8
),
947 SLE_CONDVAR(Vehicle
, spritenum
, SLE_UINT8
, SLV_2
, SL_MAX_VERSION
),
949 inline const static SaveLoadCompatTable compat_description
= _vehicle_effect_sl_compat
;
951 void Save(Vehicle
*v
) const override
953 if (v
->type
!= VEH_EFFECT
) return;
954 SlObject(v
, this->GetDescription());
957 void Load(Vehicle
*v
) const override
959 if (v
->type
!= VEH_EFFECT
) return;
960 SlObject(v
, this->GetLoadDescription());
963 void FixPointers(Vehicle
*v
) const override
965 if (v
->type
!= VEH_EFFECT
) return;
966 SlObject(v
, this->GetDescription());
970 class SlVehicleDisaster
: public DefaultSaveLoadHandler
<SlVehicleDisaster
, Vehicle
> {
972 inline static const SaveLoad description
[] = {
973 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
975 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
976 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
977 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
978 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_6
),
979 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, SLV_6
, SL_MAX_VERSION
),
981 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
982 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
983 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_6
),
984 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, SLV_6
, SL_MAX_VERSION
),
985 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_164
),
986 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, SLV_164
, SL_MAX_VERSION
),
987 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
989 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
990 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
991 SLE_CONDVARNAME(DisasterVehicle
, state
, "current_order.dest", SLE_FILE_U8
| SLE_VAR_U16
, SL_MIN_VERSION
, SLV_5
),
992 SLE_CONDVARNAME(DisasterVehicle
, state
, "current_order.dest", SLE_UINT16
, SLV_5
, SLV_DISASTER_VEH_STATE
),
993 SLE_CONDVAR(DisasterVehicle
, state
, SLE_UINT16
, SLV_DISASTER_VEH_STATE
, SL_MAX_VERSION
),
995 SLE_VAR(Vehicle
, sprite_cache
.sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
996 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, SL_MIN_VERSION
, SLV_31
),
997 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, SLV_31
, SL_MAX_VERSION
),
998 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
1000 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_191
),
1001 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_UINT32
, SLV_191
, SL_MAX_VERSION
),
1002 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_FILE_U16
| SLE_VAR_U32
, SL_MIN_VERSION
, SLV_191
),
1003 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_UINT32
, SLV_191
, SL_MAX_VERSION
),
1004 SLE_CONDVAR(DisasterVehicle
, flags
, SLE_UINT8
, SLV_194
, SL_MAX_VERSION
),
1007 inline const static SaveLoadCompatTable compat_description
= _vehicle_disaster_sl_compat
;
1009 void Save(Vehicle
*v
) const override
1011 if (v
->type
!= VEH_DISASTER
) return;
1012 SlObject(v
, this->GetDescription());
1015 void Load(Vehicle
*v
) const override
1017 if (v
->type
!= VEH_DISASTER
) return;
1018 SlObject(v
, this->GetLoadDescription());
1021 void FixPointers(Vehicle
*v
) const override
1023 if (v
->type
!= VEH_DISASTER
) return;
1024 SlObject(v
, this->GetDescription());
1028 const static SaveLoad _vehicle_desc
[] = {
1029 SLE_SAVEBYTE(Vehicle
, type
),
1030 SLEG_STRUCT("train", SlVehicleTrain
),
1031 SLEG_STRUCT("roadveh", SlVehicleRoadVeh
),
1032 SLEG_STRUCT("ship", SlVehicleShip
),
1033 SLEG_STRUCT("aircraft", SlVehicleAircraft
),
1034 SLEG_STRUCT("effect", SlVehicleEffect
),
1035 SLEG_STRUCT("disaster", SlVehicleDisaster
),
1038 struct VEHSChunkHandler
: ChunkHandler
{
1039 VEHSChunkHandler() : ChunkHandler('VEHS', CH_SPARSE_TABLE
) {}
1041 void Save() const override
1043 SlTableHeader(_vehicle_desc
);
1045 /* Write the vehicles */
1046 for (Vehicle
*v
: Vehicle::Iterate()) {
1047 SlSetArrayIndex(v
->index
);
1048 SlObject(v
, _vehicle_desc
);
1052 void Load() const override
1054 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(_vehicle_desc
, _vehicle_sl_compat
);
1060 while ((index
= SlIterateArray()) != -1) {
1062 VehicleType vtype
= (VehicleType
)SlReadByte();
1065 case VEH_TRAIN
: v
= new (index
) Train(); break;
1066 case VEH_ROAD
: v
= new (index
) RoadVehicle(); break;
1067 case VEH_SHIP
: v
= new (index
) Ship(); break;
1068 case VEH_AIRCRAFT
: v
= new (index
) Aircraft(); break;
1069 case VEH_EFFECT
: v
= new (index
) EffectVehicle(); break;
1070 case VEH_DISASTER
: v
= new (index
) DisasterVehicle(); break;
1071 case VEH_INVALID
: // Savegame shouldn't contain invalid vehicles
1072 default: SlErrorCorrupt("Invalid vehicle type");
1077 if (_cargo_count
!= 0 && IsCompanyBuildableVehicleType(v
) && CargoPacket::CanAllocateItem()) {
1078 /* Don't construct the packet with station here, because that'll fail with old savegames */
1079 CargoPacket
*cp
= new CargoPacket(_cargo_count
, _cargo_periods
, _cargo_source
, _cargo_source_xy
, _cargo_feeder_share
);
1080 v
->cargo
.Append(cp
);
1083 /* Old savegames used 'last_station_visited = 0xFF' */
1084 if (IsSavegameVersionBefore(SLV_5
) && v
->last_station_visited
== 0xFF) {
1085 v
->last_station_visited
= INVALID_STATION
;
1088 if (IsSavegameVersionBefore(SLV_182
)) v
->last_loading_station
= INVALID_STATION
;
1090 if (IsSavegameVersionBefore(SLV_5
)) {
1091 /* Convert the current_order.type (which is a mix of type and flags, because
1092 * in those versions, they both were 4 bits big) to type and flags */
1093 v
->current_order
.flags
= GB(v
->current_order
.type
, 4, 4);
1094 v
->current_order
.type
&= 0x0F;
1097 /* Advanced vehicle lists got added */
1098 if (IsSavegameVersionBefore(SLV_60
)) v
->group_id
= DEFAULT_GROUP
;
1102 void FixPointers() const override
1104 for (Vehicle
*v
: Vehicle::Iterate()) {
1105 SlObject(v
, _vehicle_desc
);
1110 static const VEHSChunkHandler VEHS
;
1111 static const ChunkHandlerRef veh_chunk_handlers
[] = {
1115 extern const ChunkHandlerTable
_veh_chunk_handlers(veh_chunk_handlers
);