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 vehicle_sl.cpp Code handling saving and loading of vehicles */
12 #include "../stdafx.h"
13 #include "../vehicle_func.h"
15 #include "../roadveh.h"
17 #include "../aircraft.h"
18 #include "../station_base.h"
19 #include "../effectvehicle_base.h"
20 #include "../company_base.h"
21 #include "../company_func.h"
22 #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()
39 v
->other_multiheaded_part
= nullptr;
43 if (v
->IsFrontEngine() || v
->IsFreeWagon()) {
44 /* Two ways to associate multiheaded parts to each other:
45 * sequential-matching: Trains shall be arranged to look like <..>..<..>..<..>..
46 * bracket-matching: Free vehicle chains shall be arranged to look like ..<..<..>..<..>..>..
48 * Note: Old savegames might contain chains which do not comply with these rules, e.g.
49 * - the front and read parts have invalid orders
50 * - different engine types might be combined
51 * - there might be different amounts of front and rear parts.
53 * Note: The multiheaded parts need to be matched exactly like they are matched on the server, else desyncs will occur.
54 * This is why two matching strategies are needed.
57 bool sequential_matching
= v
->IsFrontEngine();
59 for (Train
*u
= v
; u
!= nullptr; u
= u
->GetNextVehicle()) {
60 if (u
->other_multiheaded_part
!= nullptr) continue; // we already linked this one
62 if (u
->IsMultiheaded()) {
64 /* we got a rear car without a front car. We will convert it to a front one */
69 /* Find a matching back part */
70 EngineID eid
= u
->engine_type
;
72 if (sequential_matching
) {
73 for (w
= u
->GetNextVehicle(); w
!= nullptr; w
= w
->GetNextVehicle()) {
74 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= nullptr || !w
->IsMultiheaded()) continue;
76 /* we found a car to partner with this engine. Now we will make sure it face the right way */
85 for (w
= u
->GetNextVehicle(); w
!= nullptr; w
= w
->GetNextVehicle()) {
86 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= nullptr || !w
->IsMultiheaded()) continue;
91 if (stack_pos
== 0) break;
98 w
->other_multiheaded_part
= u
;
99 u
->other_multiheaded_part
= w
;
101 /* we got a front car and no rear cars. We will fake this one for forget that it should have been multiheaded */
102 u
->ClearMultiheaded();
111 * Converts all trains to the new subtype format introduced in savegame 16.2
112 * It also links multiheaded engines or make them forget they are multiheaded if no suitable partner is found
114 void ConvertOldMultiheadToNew()
117 FOR_ALL_TRAINS(t
) SetBit(t
->subtype
, 7); // indicates that it's the old format and needs to be converted in the next loop
120 if (HasBit(t
->subtype
, 7) && ((t
->subtype
& ~0x80) == 0 || (t
->subtype
& ~0x80) == 4)) {
121 for (Train
*u
= t
; u
!= nullptr; u
= u
->Next()) {
122 const RailVehicleInfo
*rvi
= RailVehInfo(u
->engine_type
);
124 ClrBit(u
->subtype
, 7);
125 switch (u
->subtype
) {
126 case 0: // TS_Front_Engine
127 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
) u
->SetMultiheaded();
132 case 1: // TS_Artic_Part
134 u
->SetArticulatedPart();
137 case 2: // TS_Not_First
139 if (rvi
->railveh_type
== RAILVEH_WAGON
) {
144 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
&& rvi
->image_index
== u
->spritenum
- 1) {
145 /* rear end of a multiheaded engine */
149 if (rvi
->railveh_type
== RAILVEH_MULTIHEAD
) u
->SetMultiheaded();
153 case 4: // TS_Free_Car
158 default: SlErrorCorrupt("Invalid train subtype");
166 /** need to be called to load aircraft from old version */
167 void UpdateOldAircraft()
169 /* set airport_flags to 0 for all airports just to be sure */
171 FOR_ALL_STATIONS(st
) {
172 st
->airport
.flags
= 0; // reset airport
176 FOR_ALL_AIRCRAFT(a
) {
177 /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor)
179 if (a
->IsNormalAircraft()) {
180 /* airplane in terminal stopped doesn't hurt anyone, so goto next */
181 if ((a
->vehstatus
& VS_STOPPED
) && a
->state
== 0) {
186 AircraftLeaveHangar(a
, a
->direction
); // make airplane visible if it was in a depot for example
187 a
->vehstatus
&= ~VS_STOPPED
; // make airplane moving
188 UpdateAircraftCache(a
);
189 a
->cur_speed
= a
->vcache
.cached_max_speed
; // so aircraft don't have zero speed while in air
190 if (!a
->current_order
.IsType(OT_GOTO_STATION
) && !a
->current_order
.IsType(OT_GOTO_DEPOT
)) {
191 /* reset current order so aircraft doesn't have invalid "station-only" order */
192 a
->current_order
.MakeDummy();
195 AircraftNextAirportPos_and_Order(a
); // move it to the entry point of the airport
196 GetNewVehiclePosResult gp
= GetNewVehiclePos(a
);
197 a
->tile
= 0; // aircraft in air is tile=0
199 /* correct speed of helicopter-rotors */
200 if (a
->subtype
== AIR_HELICOPTER
) a
->Next()->Next()->cur_speed
= 32;
202 /* set new position x,y,z */
203 GetAircraftFlightLevelBounds(a
, &a
->z_pos
, nullptr);
204 SetAircraftPosition(a
, gp
.x
, gp
.y
, GetAircraftFlightLevel(a
));
210 * Check all vehicles to ensure their engine type is valid
211 * for the currently loaded NewGRFs (that includes none...)
212 * This only makes a difference if NewGRFs are missing, otherwise
213 * all vehicles will be valid. This does not make such a game
214 * playable, it only prevents crash.
216 static void CheckValidVehicles()
218 size_t total_engines
= Engine::GetPoolSize();
219 EngineID first_engine
[4] = { INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
, INVALID_ENGINE
};
222 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_TRAIN
) { first_engine
[VEH_TRAIN
] = e
->index
; break; }
223 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_ROAD
) { first_engine
[VEH_ROAD
] = e
->index
; break; }
224 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_SHIP
) { first_engine
[VEH_SHIP
] = e
->index
; break; }
225 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_AIRCRAFT
) { first_engine
[VEH_AIRCRAFT
] = e
->index
; break; }
228 FOR_ALL_VEHICLES(v
) {
229 /* Test if engine types match */
235 if (v
->engine_type
>= total_engines
|| v
->type
!= v
->GetEngine()->type
) {
236 v
->engine_type
= first_engine
[v
->type
];
246 extern byte _age_cargo_skip_counter
; // From misc_sl.cpp
248 /** Called after load to update coordinates */
249 void AfterLoadVehicles(bool part_of_load
)
253 FOR_ALL_VEHICLES(v
) {
254 /* Reinstate the previous pointer */
255 if (v
->Next() != nullptr) v
->Next()->previous
= v
;
256 if (v
->NextShared() != nullptr) v
->NextShared()->previous_shared
= v
;
258 if (part_of_load
) v
->fill_percent_te_id
= INVALID_TE_ID
;
260 if (v
->IsGroundVehicle()) v
->GetGroundVehicleCache()->first_engine
= INVALID_ENGINE
;
263 /* AfterLoadVehicles may also be called in case of NewGRF reload, in this
264 * case we may not convert orders again. */
266 /* Create shared vehicle chain for very old games (pre 5,2) and create
267 * OrderList from shared vehicle chains. For this to work correctly, the
268 * following conditions must be fulfilled:
269 * a) both next_shared and previous_shared are not set for pre 5,2 games
270 * b) both next_shared and previous_shared are set for later games
272 std::map
<Order
*, OrderList
*> mapping
;
274 FOR_ALL_VEHICLES(v
) {
275 if (v
->orders
.old
!= nullptr) {
276 if (IsSavegameVersionBefore(105)) { // Pre-105 didn't save an OrderList
277 if (mapping
[v
->orders
.old
] == nullptr) {
278 /* This adds the whole shared vehicle chain for case b */
280 /* Creating an OrderList here is safe because the number of vehicles
281 * allowed in these savegames matches the number of OrderLists. As
282 * such each vehicle can get an OrderList and it will (still) fit. */
283 assert(OrderList::CanAllocateItem());
284 v
->orders
.list
= mapping
[v
->orders
.old
] = new OrderList(v
->orders
.old
, v
);
286 v
->orders
.list
= mapping
[v
->orders
.old
];
287 /* For old games (case a) we must create the shared vehicle chain */
288 if (IsSavegameVersionBefore(5, 2)) {
289 v
->AddToShared(v
->orders
.list
->GetFirstSharedVehicle());
292 } else { // OrderList was saved as such, only recalculate not saved values
293 if (v
->PreviousShared() == nullptr) {
294 v
->orders
.list
->Initialize(v
->orders
.list
->first
, v
);
301 FOR_ALL_VEHICLES(v
) {
302 /* Fill the first pointers */
303 if (v
->Previous() == nullptr) {
304 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->Next()) {
311 if (IsSavegameVersionBefore(105)) {
312 /* Before 105 there was no order for shared orders, thus it messed up horribly */
313 FOR_ALL_VEHICLES(v
) {
314 if (v
->First() != v
|| v
->orders
.list
!= nullptr || v
->previous_shared
!= nullptr || v
->next_shared
== nullptr) continue;
316 /* As above, allocating OrderList here is safe. */
317 assert(OrderList::CanAllocateItem());
318 v
->orders
.list
= new OrderList(nullptr, v
);
319 for (Vehicle
*u
= v
; u
!= nullptr; u
= u
->next_shared
) {
320 u
->orders
.list
= v
->orders
.list
;
325 if (IsSavegameVersionBefore(157)) {
326 /* The road vehicle subtype was converted to a flag. */
328 FOR_ALL_ROADVEHICLES(rv
) {
329 if (rv
->subtype
== 0) {
330 /* The road vehicle is at the front. */
331 rv
->SetFrontEngine();
332 } else if (rv
->subtype
== 1) {
333 /* The road vehicle is an articulated part. */
335 rv
->SetArticulatedPart();
337 SlErrorCorrupt("Invalid road vehicle subtype");
342 if (IsSavegameVersionBefore(160)) {
343 /* In some old savegames there might be some "crap" stored. */
344 FOR_ALL_VEHICLES(v
) {
345 if (!v
->IsPrimaryVehicle() && v
->type
!= VEH_DISASTER
) {
346 v
->current_order
.Free();
352 if (IsSavegameVersionBefore(162)) {
353 /* Set the vehicle-local cargo age counter from the old global counter. */
354 FOR_ALL_VEHICLES(v
) {
355 v
->cargo_age_counter
= _age_cargo_skip_counter
;
359 if (IsSavegameVersionBefore(180)) {
360 /* Set service interval flags */
361 FOR_ALL_VEHICLES(v
) {
362 if (!v
->IsPrimaryVehicle()) continue;
364 const Company
*c
= Company::Get(v
->owner
);
365 int interval
= CompanyServiceInterval(c
, v
->type
);
367 v
->SetServiceIntervalIsCustom(v
->GetServiceInterval() != interval
);
368 v
->SetServiceIntervalIsPercent(c
->settings
.vehicle
.servint_ispercent
);
373 CheckValidVehicles();
375 FOR_ALL_VEHICLES(v
) {
376 assert(v
->first
!= nullptr);
380 Train
*t
= Train::From(v
);
381 if (t
->IsFrontEngine() || t
->IsFreeWagon()) {
382 t
->gcache
.last_speed
= t
->cur_speed
; // update displayed train speed
383 t
->ConsistChanged(CCF_SAVELOAD
);
389 RoadVehicle
*rv
= RoadVehicle::From(v
);
390 if (rv
->IsFrontEngine()) {
391 rv
->gcache
.last_speed
= rv
->cur_speed
; // update displayed road vehicle speed
393 rv
->rtid
= Engine::Get(rv
->engine_type
)->GetRoadType();
394 rv
->compatible_subtypes
= GetRoadTypeInfo(rv
->rtid
)->powered_roadtypes
;
395 for (RoadVehicle
*u
= rv
; u
!= NULL
; u
= u
->Next()) {
397 u
->compatible_subtypes
= rv
->compatible_subtypes
;
400 RoadVehUpdateCache(rv
);
401 if (_settings_game
.vehicle
.roadveh_acceleration_model
!= AM_ORIGINAL
) {
409 Ship::From(v
)->UpdateCache();
416 /* Stop non-front engines */
417 if (part_of_load
&& IsSavegameVersionBefore(112)) {
418 FOR_ALL_VEHICLES(v
) {
419 if (v
->type
== VEH_TRAIN
) {
420 Train
*t
= Train::From(v
);
421 if (!t
->IsFrontEngine()) {
423 t
->vehstatus
|= VS_STOPPED
;
424 /* cur_speed is now relevant for non-front parts - nonzero breaks
425 * moving-wagons-inside-depot- and autoreplace- code */
429 /* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
430 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
431 if ((v
->vehstatus
& VS_STOPPED
) && (v
->type
!= VEH_TRAIN
|| IsSavegameVersionBefore(2, 1))) {
437 FOR_ALL_VEHICLES(v
) {
442 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_seq
);
443 v
->UpdateSpriteSeqBound();
447 if (Aircraft::From(v
)->IsNormalAircraft()) {
448 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_seq
);
449 v
->UpdateSpriteSeqBound();
451 /* The plane's shadow will have the same image as the plane, but no colour */
452 Vehicle
*shadow
= v
->Next();
453 shadow
->sprite_seq
.CopyWithoutPalette(v
->sprite_seq
);
454 shadow
->sprite_seq_bounds
= v
->sprite_seq_bounds
;
456 /* In the case of a helicopter we will update the rotor sprites */
457 if (v
->subtype
== AIR_HELICOPTER
) {
458 Vehicle
*rotor
= shadow
->Next();
459 GetRotorImage(Aircraft::From(v
), EIT_ON_MAP
, &rotor
->sprite_seq
);
460 rotor
->UpdateSpriteSeqBound();
463 UpdateAircraftCache(Aircraft::From(v
), true);
469 v
->UpdateDeltaXY(v
->direction
);
470 v
->coord
.left
= INVALID_COORD
;
472 v
->UpdateViewport(false);
476 void AfterLoadTripHistory()
480 FOR_ALL_VEHICLES(v
) {
481 // We used to only story the date. Now we store the ticks, so multiply by DAY_TICKS.
482 // Old values will be less accurate because of this, but they're constantly overwritten anyway.
483 if (IsSavegameVersionBefore(SL_PATCH_PACK_1_24
)) {
484 for (int i
= 0; i
< NUM_TRIP_HISTORY_ENTRIES
; ++i
) {
485 v
->trip_history
.entries
[i
].ticks
*= DAY_TICKS
;
489 v
->trip_history
.UpdateCalculated(true);
493 bool TrainController(Train
*v
, Vehicle
*nomove
, bool reverse
= true); // From train_cmd.cpp
494 void ReverseTrainDirection(Train
*v
);
495 void ReverseTrainSwapVeh(Train
*v
, int l
, int r
);
497 /** Fixup old train spacing. */
498 void FixupTrainLengths()
500 /* Vehicle center was moved from 4 units behind the front to half the length
501 * behind the front. Move vehicles so they end up on the same spot. */
503 FOR_ALL_VEHICLES(v
) {
504 if (v
->type
== VEH_TRAIN
&& v
->IsPrimaryVehicle()) {
505 /* The vehicle center is now more to the front depending on vehicle length,
506 * so we need to move all vehicles forward to cover the difference to the
507 * old center, otherwise wagon spacing in trains would be broken upon load. */
508 for (Train
*u
= Train::From(v
); u
!= nullptr; u
= u
->Next()) {
509 if (u
->track
== TRACK_BIT_DEPOT
|| (u
->vehstatus
& VS_CRASHED
)) continue;
511 Train
*next
= u
->Next();
513 /* Try to pull the vehicle half its length forward. */
514 int diff
= (VEHICLE_LENGTH
- u
->gcache
.cached_veh_length
) / 2;
516 for (done
= 0; done
< diff
; done
++) {
517 if (!TrainController(u
, next
, false)) break;
520 if (next
!= nullptr && done
< diff
&& u
->IsFrontEngine()) {
521 /* Pulling the front vehicle forwards failed, we either encountered a dead-end
522 * or a red signal. To fix this, we try to move the whole train the required
523 * space backwards and re-do the fix up of the front vehicle. */
525 /* Ignore any signals when backtracking. */
526 TrainForceProceeding old_tfp
= u
->force_proceed
;
527 u
->force_proceed
= TFP_SIGNAL
;
529 /* Swap start<>end, start+1<>end-1, ... */
530 int r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
532 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
534 /* We moved the first vehicle which is now the last. Move it back to the
535 * original position as we will fix up the last vehicle later in the loop. */
536 for (int i
= 0; i
< done
; i
++) TrainController(u
->Last(), nullptr);
538 /* Move the train backwards to get space for the first vehicle. As the stopping
539 * distance from a line end is rounded up, move the train one unit more to cater
540 * for front vehicles with odd lengths. */
542 for (moved
= 0; moved
< diff
+ 1; moved
++) {
543 if (!TrainController(u
, nullptr, false)) break;
546 /* Swap start<>end, start+1<>end-1, ... again. */
547 r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
549 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
551 u
->force_proceed
= old_tfp
;
553 /* Tracks are too short to fix the train length. The player has to fix the
554 * train in a depot. Bail out so we don't damage the vehicle chain any more. */
555 if (moved
< diff
+ 1) break;
557 /* Re-do the correction for the first vehicle. */
558 for (done
= 0; done
< diff
; done
++) TrainController(u
, next
, false);
560 /* We moved one unit more backwards than needed for even-length front vehicles,
561 * try to move that unit forward again. We don't care if this step fails. */
562 TrainController(u
, nullptr, false);
565 /* If the next wagon is still in a depot, check if it shouldn't be outside already. */
566 if (next
!= nullptr && next
->track
== TRACK_BIT_DEPOT
) {
567 int d
= TicksToLeaveDepot(u
);
569 /* Next vehicle should have left the depot already, show it and pull forward. */
570 next
->vehstatus
&= ~VS_HIDDEN
;
571 next
->track
= TrackToTrackBits(GetRailDepotTrack(next
->tile
));
572 for (int i
= 0; i
>= d
; i
--) TrainController(next
, nullptr);
577 /* Update all cached properties after moving the vehicle chain around. */
578 Train::From(v
)->ConsistChanged(CCF_TRACK
);
583 static uint8 _cargo_days
;
584 static uint16 _cargo_source
;
585 static uint32 _cargo_source_xy
;
586 static uint16 _cargo_count
;
587 static uint16 _cargo_paid_for
;
588 static Money _cargo_feeder_share
;
589 static uint32 _cargo_loaded_at_xy
;
592 * Make it possible to make the saveload tables "friends" of other classes.
593 * @param vt the vehicle type. Can be VEH_END for the common vehicle description data
594 * @return the saveload description
596 const SaveLoad
*GetVehicleDescription(VehicleType vt
)
598 /** Save and load of vehicles */
599 static const SaveLoad _common_veh_desc
[] = {
600 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
602 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
603 SLE_CONDVAR(Vehicle
, name
, SLE_NAME
, 0, 83),
604 SLE_CONDSTR(Vehicle
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, 0, 84, SL_MAX_VERSION
),
605 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 7),
606 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_UINT16
, 8, SL_MAX_VERSION
),
607 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
608 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
609 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
610 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
611 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
613 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
614 SLE_CONDVAR(Vehicle
, x_pos
, SLE_UINT32
, 6, SL_MAX_VERSION
),
615 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
616 SLE_CONDVAR(Vehicle
, y_pos
, SLE_UINT32
, 6, SL_MAX_VERSION
),
617 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
618 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
619 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
621 SLE_CONDNULL(2, 0, 57),
622 SLE_VAR(Vehicle
, spritenum
, SLE_UINT8
),
623 SLE_CONDNULL(5, 0, 57),
624 SLE_VAR(Vehicle
, engine_type
, SLE_UINT16
),
626 SLE_CONDNULL(2, 0, 151),
627 SLE_VAR(Vehicle
, cur_speed
, SLE_UINT16
),
628 SLE_VAR(Vehicle
, subspeed
, SLE_UINT8
),
629 SLE_VAR(Vehicle
, acceleration
, SLE_UINT8
),
630 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
632 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
633 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
634 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_UINT16
, 5, SL_MAX_VERSION
),
635 SLE_CONDVAR(Vehicle
, last_loading_station
, SLE_UINT16
, 182, SL_MAX_VERSION
),
637 SLE_VAR(Vehicle
, cargo_type
, SLE_UINT8
),
638 SLE_CONDVAR(Vehicle
, cargo_subtype
, SLE_UINT8
, 35, SL_MAX_VERSION
),
639 SLEG_CONDVAR( _cargo_days
, SLE_UINT8
, 0, 67),
640 SLEG_CONDVAR( _cargo_source
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 6),
641 SLEG_CONDVAR( _cargo_source
, SLE_UINT16
, 7, 67),
642 SLEG_CONDVAR( _cargo_source_xy
, SLE_UINT32
, 44, 67),
643 SLE_VAR(Vehicle
, cargo_cap
, SLE_UINT16
),
644 SLE_CONDVAR(Vehicle
, refit_cap
, SLE_UINT16
, 182, SL_MAX_VERSION
),
645 SLEG_CONDVAR( _cargo_count
, SLE_UINT16
, 0, 67),
646 SLE_CONDDEQ(Vehicle
, cargo
.packets
, REF_CARGO_PACKET
, 68, SL_MAX_VERSION
),
647 SLE_CONDARR(Vehicle
, cargo
.action_counts
, SLE_UINT
, VehicleCargoList::NUM_MOVE_TO_ACTION
, 181, SL_MAX_VERSION
),
648 SLE_CONDVAR(Vehicle
, cargo_age_counter
, SLE_UINT16
, 162, SL_MAX_VERSION
),
650 SLE_CONDNULL(1, SL_PATCH_PACK_1_8
, SL_PATCH_PACK_1_19
- 1), // trip_occupancy
652 SLE_VAR(Vehicle
, day_counter
, SLE_UINT8
),
653 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
655 SLE_CONDVAR(Vehicle
, running_ticks
, SLE_FILE_U8
| SLE_VAR_U16
, 88, SL_PATCH_PACK_1_8
- 1),
656 SLE_CONDVAR(Vehicle
, running_ticks
, SLE_UINT16
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
658 SLE_VAR(Vehicle
, cur_implicit_order_index
, SLE_UINT8
),
659 SLE_CONDVAR(Vehicle
, cur_real_order_index
, SLE_UINT8
, 158, SL_MAX_VERSION
),
660 SLE_CONDVAR(Vehicle
, cur_timetable_order_index
, SLE_UINT8
, SL_PATCH_PACK_1_24
, SL_MAX_VERSION
),
661 /* num_orders is now part of OrderList and is not saved but counted */
662 SLE_CONDNULL(1, 0, 104),
664 /* This next line is for version 4 and prior compatibility.. it temporarily reads
665 type and flags (which were both 4 bits) into type. Later on this is
666 converted correctly */
667 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, 0, 4),
668 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
670 /* Orders for version 5 and on */
671 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, 5, SL_MAX_VERSION
),
672 SLE_CONDVAR(Vehicle
, current_order
.flags
, SLE_UINT8
, 5, SL_MAX_VERSION
),
673 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, 5, SL_MAX_VERSION
),
675 /* Refit in current order */
676 SLE_CONDVAR(Vehicle
, current_order
.refit_cargo
, SLE_UINT8
, 36, SL_MAX_VERSION
),
677 SLE_CONDNULL(1, 36, 181), // refit_subtype
679 /* Timetable in current order */
680 SLE_CONDVAR(Vehicle
, current_order
.wait_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
681 SLE_CONDVAR(Vehicle
, current_order
.travel_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
682 SLE_CONDVAR(Vehicle
, current_order
.max_speed
, SLE_UINT16
, 174, SL_MAX_VERSION
),
683 SLE_CONDVAR(Vehicle
, timetable_start
, SLE_INT32
, 129, SL_MAX_VERSION
),
685 SLE_CONDREF(Vehicle
, orders
, REF_ORDER
, 0, 104),
686 SLE_CONDREF(Vehicle
, orders
, REF_ORDERLIST
, 105, SL_MAX_VERSION
),
688 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
689 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, 31, SL_MAX_VERSION
),
690 SLE_CONDVAR(Vehicle
, max_age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
691 SLE_CONDVAR(Vehicle
, max_age
, SLE_INT32
, 31, SL_MAX_VERSION
),
692 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
693 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_INT32
, 31, SL_MAX_VERSION
),
694 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, 0, 30),
695 SLE_CONDVAR(Vehicle
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, 31, 179),
696 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, 180, SL_MAX_VERSION
),
697 SLE_VAR(Vehicle
, reliability
, SLE_UINT16
),
698 SLE_VAR(Vehicle
, reliability_spd_dec
, SLE_UINT16
),
699 SLE_VAR(Vehicle
, breakdown_ctr
, SLE_UINT8
),
700 SLE_VAR(Vehicle
, breakdown_delay
, SLE_UINT8
),
701 SLE_VAR(Vehicle
, breakdowns_since_last_service
, SLE_UINT8
),
702 SLE_VAR(Vehicle
, breakdown_chance
, SLE_UINT8
),
703 SLE_CONDVAR(Vehicle
, build_year
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 30),
704 SLE_CONDVAR(Vehicle
, build_year
, SLE_INT32
, 31, SL_MAX_VERSION
),
706 SLE_VAR(Vehicle
, load_unload_ticks
, SLE_UINT16
),
707 SLEG_CONDVAR( _cargo_paid_for
, SLE_UINT16
, 45, SL_MAX_VERSION
),
708 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, 40, 179),
709 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_UINT16
, 180, SL_MAX_VERSION
),
711 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
712 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_INT64
, 65, SL_MAX_VERSION
),
713 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
714 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_INT64
, 65, SL_MAX_VERSION
),
715 SLE_CONDVAR(Vehicle
, profit_lifetime
, SLE_INT64
, SL_PATCH_PACK_1_14
, SL_MAX_VERSION
),
716 SLEG_CONDVAR( _cargo_feeder_share
, SLE_FILE_I32
| SLE_VAR_I64
, 51, 64),
717 SLEG_CONDVAR( _cargo_feeder_share
, SLE_INT64
, 65, 67),
718 SLEG_CONDVAR( _cargo_loaded_at_xy
, SLE_UINT32
, 51, 67),
719 SLE_CONDVAR(Vehicle
, value
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
720 SLE_CONDVAR(Vehicle
, value
, SLE_INT64
, 65, SL_MAX_VERSION
),
722 SLE_CONDVAR(Vehicle
, random_bits
, SLE_UINT8
, 2, SL_MAX_VERSION
),
723 SLE_CONDVAR(Vehicle
, waiting_triggers
, SLE_UINT8
, 2, SL_MAX_VERSION
),
725 SLE_CONDREF(Vehicle
, ahead_separation
, REF_VEHICLE
, SL_PATCH_PACK
, SL_PATCH_PACK_1_5
),
726 SLE_CONDREF(Vehicle
, behind_separation
, REF_VEHICLE
, SL_PATCH_PACK
, SL_PATCH_PACK_1_5
),
728 SLE_CONDREF(Vehicle
, next_shared
, REF_VEHICLE
, 2, SL_MAX_VERSION
),
729 SLE_CONDNULL(2, 2, 68),
730 SLE_CONDNULL(4, 69, 100),
732 SLE_CONDVAR(Vehicle
, group_id
, SLE_UINT16
, 60, SL_MAX_VERSION
),
734 SLE_CONDVAR(Vehicle
, current_order_time
, SLE_UINT32
, 67, SL_MAX_VERSION
),
735 SLE_CONDVAR(Vehicle
, current_loading_time
, SLE_UINT32
, SL_PATCH_PACK
, SL_PATCH_PACK_1_5
),
736 SLE_CONDVAR(Vehicle
, current_loading_time
, SLE_UINT32
, SL_PATCH_PACK_1_23
, SL_MAX_VERSION
),
737 SLE_CONDVAR(Vehicle
, lateness_counter
, SLE_INT32
, 67, SL_MAX_VERSION
),
739 SLE_CONDNULL(10, 2, 143), // old reserved space
741 // Trip History Arrays
742 SLE_CONDVAR(Vehicle
, trip_history
.entries
[0].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
743 SLE_CONDVAR(Vehicle
, trip_history
.entries
[1].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
744 SLE_CONDVAR(Vehicle
, trip_history
.entries
[2].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
745 SLE_CONDVAR(Vehicle
, trip_history
.entries
[3].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
746 SLE_CONDVAR(Vehicle
, trip_history
.entries
[4].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
747 SLE_CONDVAR(Vehicle
, trip_history
.entries
[5].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
748 SLE_CONDVAR(Vehicle
, trip_history
.entries
[6].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
749 SLE_CONDVAR(Vehicle
, trip_history
.entries
[7].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
750 SLE_CONDVAR(Vehicle
, trip_history
.entries
[8].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
751 SLE_CONDVAR(Vehicle
, trip_history
.entries
[9].profit
, SLE_INT64
, SL_PATCH_PACK
, SL_MAX_VERSION
),
752 SLE_CONDVAR(Vehicle
, trip_history
.entries
[0].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
753 SLE_CONDVAR(Vehicle
, trip_history
.entries
[1].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
754 SLE_CONDVAR(Vehicle
, trip_history
.entries
[2].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
755 SLE_CONDVAR(Vehicle
, trip_history
.entries
[3].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
756 SLE_CONDVAR(Vehicle
, trip_history
.entries
[4].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
757 SLE_CONDVAR(Vehicle
, trip_history
.entries
[5].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
758 SLE_CONDVAR(Vehicle
, trip_history
.entries
[6].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
759 SLE_CONDVAR(Vehicle
, trip_history
.entries
[7].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
760 SLE_CONDVAR(Vehicle
, trip_history
.entries
[8].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
761 SLE_CONDVAR(Vehicle
, trip_history
.entries
[9].ticks
, SLE_FILE_I64
| SLE_VAR_I32
, SL_PATCH_PACK
, SL_MAX_VERSION
),
767 static const SaveLoad _train_desc
[] = {
768 SLE_WRITEBYTE(Vehicle
, type
, VEH_TRAIN
),
770 SLE_VAR(Train
, crash_anim_pos
, SLE_UINT16
),
771 SLE_VAR(Train
, force_proceed
, SLE_UINT8
),
772 SLE_VAR(Train
, railtype
, SLE_UINT8
),
773 SLE_VAR(Train
, track
, SLE_UINT8
),
775 SLE_CONDVAR(Train
, flags
, SLE_FILE_U8
| SLE_VAR_U32
, 2, 99),
776 SLE_CONDVAR(Train
, flags
, SLE_FILE_U16
| SLE_VAR_U32
, 100, SL_PATCH_PACK_1_19
-1),
777 SLE_CONDVAR(Train
, flags
, SLE_UINT32
, SL_PATCH_PACK_1_19
, SL_MAX_VERSION
),
778 SLE_CONDNULL(2, 2, 59),
780 SLE_CONDVAR(Train
, wait_counter
, SLE_UINT16
, 136, SL_MAX_VERSION
),
781 SLE_CONDVAR(Train
, tunnel_bridge_signal_num
, SLE_UINT16
, SL_PATCH_PACK_1_19
, SL_MAX_VERSION
),
783 SLE_CONDNULL(2, 2, 19),
784 SLE_CONDVAR(Train
, gv_flags
, SLE_UINT16
, 139, SL_MAX_VERSION
),
785 SLE_CONDNULL(11, 2, 143), // old reserved space
786 SLE_CONDVAR(Train
, reverse_distance
, SLE_UINT16
, SL_PATCH_PACK_1_12
, SL_MAX_VERSION
),
791 static const SaveLoad _roadveh_desc
[] = {
792 SLE_WRITEBYTE(Vehicle
, type
, VEH_ROAD
),
794 SLE_VAR(RoadVehicle
, state
, SLE_UINT8
),
795 SLE_VAR(RoadVehicle
, frame
, SLE_UINT8
),
796 SLE_VAR(RoadVehicle
, blocked_ctr
, SLE_UINT16
),
797 SLE_VAR(RoadVehicle
, overtaking
, SLE_UINT8
),
798 SLE_VAR(RoadVehicle
, overtaking_ctr
, SLE_UINT8
),
799 SLE_VAR(RoadVehicle
, crashed_ctr
, SLE_UINT16
),
800 SLE_VAR(RoadVehicle
, reverse_ctr
, SLE_UINT8
),
802 SLE_CONDNULL(2, 6, 68),
803 SLE_CONDVAR(RoadVehicle
, gv_flags
, SLE_UINT16
, 139, SL_MAX_VERSION
),
804 SLE_CONDNULL(4, 69, 130),
805 SLE_CONDNULL(2, 6, 130),
806 SLE_CONDNULL(16, 2, 143), // old reserved space
811 static const SaveLoad _ship_desc
[] = {
812 SLE_WRITEBYTE(Vehicle
, type
, VEH_SHIP
),
814 SLE_VAR(Ship
, state
, SLE_UINT8
),
816 SLE_CONDNULL(16, 2, 143), // old reserved space
821 static const SaveLoad _aircraft_desc
[] = {
822 SLE_WRITEBYTE(Vehicle
, type
, VEH_AIRCRAFT
),
824 SLE_VAR(Aircraft
, crashed_counter
, SLE_UINT16
),
825 SLE_VAR(Aircraft
, pos
, SLE_UINT8
),
827 SLE_CONDVAR(Aircraft
, targetairport
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
828 SLE_CONDVAR(Aircraft
, targetairport
, SLE_UINT16
, 5, SL_MAX_VERSION
),
830 SLE_VAR(Aircraft
, state
, SLE_UINT8
),
832 SLE_CONDVAR(Aircraft
, previous_pos
, SLE_UINT8
, 2, SL_MAX_VERSION
),
833 SLE_CONDVAR(Aircraft
, last_direction
, SLE_UINT8
, 2, SL_MAX_VERSION
),
834 SLE_CONDVAR(Aircraft
, number_consecutive_turns
, SLE_UINT8
, 2, SL_MAX_VERSION
),
836 SLE_CONDVAR(Aircraft
, turn_counter
, SLE_UINT8
, 136, SL_MAX_VERSION
),
837 SLE_CONDVAR(Aircraft
, flags
, SLE_UINT8
, 167, SL_MAX_VERSION
),
839 SLE_CONDNULL(13, 2, 143), // old reserved space
844 static const SaveLoad _special_desc
[] = {
845 SLE_WRITEBYTE(Vehicle
, type
, VEH_EFFECT
),
847 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
849 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
850 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
852 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
853 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
854 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
855 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
856 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
857 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
859 SLE_VAR(Vehicle
, sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
860 SLE_CONDNULL(5, 0, 57),
861 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
862 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
864 SLE_VAR(EffectVehicle
, animation_state
, SLE_UINT16
),
865 SLE_VAR(EffectVehicle
, animation_substate
, SLE_UINT8
),
867 SLE_CONDVAR(Vehicle
, spritenum
, SLE_UINT8
, 2, SL_MAX_VERSION
),
869 SLE_CONDNULL(15, 2, 143), // old reserved space
874 static const SaveLoad _disaster_desc
[] = {
875 SLE_WRITEBYTE(Vehicle
, type
, VEH_DISASTER
),
877 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
879 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
880 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
881 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
882 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
883 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
885 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
886 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
887 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
888 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
889 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
890 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
891 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
893 SLE_CONDNULL(5, 0, 57),
894 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
895 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
896 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
897 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, 5, SL_MAX_VERSION
),
899 SLE_VAR(Vehicle
, sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
900 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
901 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, 31, SL_MAX_VERSION
),
902 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
904 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 190),
905 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_UINT32
, 191, SL_PATCH_PACK
- 1),
906 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_FILE_U16
| SLE_VAR_U32
, SL_PATCH_PACK
, SL_PATCH_PACK_1_7
),
907 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_UINT32
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
909 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 190),
910 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_UINT32
, 191, SL_PATCH_PACK
- 1),
911 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_FILE_U16
| SLE_VAR_U32
, SL_PATCH_PACK
, SL_PATCH_PACK_1_7
),
912 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_UINT32
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
914 SLE_CONDVAR(DisasterVehicle
, flags
, SLE_UINT8
, 194, SL_PATCH_PACK
- 1),
915 SLE_CONDVAR(DisasterVehicle
, flags
, SLE_UINT8
, SL_PATCH_PACK_1_9
, SL_MAX_VERSION
),
917 SLE_CONDNULL(16, 2, 143), // old reserved space
923 static const SaveLoad
* const _veh_descs
[] = {
933 return _veh_descs
[vt
];
936 /** Will be called when the vehicles need to be saved. */
937 static void Save_VEHS()
940 /* Write the vehicles */
941 FOR_ALL_VEHICLES(v
) {
942 SlSetArrayIndex(v
->index
);
943 SlObject(v
, GetVehicleDescription(v
->type
));
947 /** Will be called when vehicles need to be loaded. */
954 while ((index
= SlIterateArray()) != -1) {
956 VehicleType vtype
= (VehicleType
)SlReadByte();
959 case VEH_TRAIN
: v
= new (index
) Train(); break;
960 case VEH_ROAD
: v
= new (index
) RoadVehicle(); break;
961 case VEH_SHIP
: v
= new (index
) Ship(); break;
962 case VEH_AIRCRAFT
: v
= new (index
) Aircraft(); break;
963 case VEH_EFFECT
: v
= new (index
) EffectVehicle(); break;
964 case VEH_DISASTER
: v
= new (index
) DisasterVehicle(); break;
965 case VEH_INVALID
: // Savegame shouldn't contain invalid vehicles
966 default: SlErrorCorrupt("Invalid vehicle type");
969 SlObject(v
, GetVehicleDescription(vtype
));
971 if (_cargo_count
!= 0 && IsCompanyBuildableVehicleType(v
) && CargoPacket::CanAllocateItem()) {
972 /* Don't construct the packet with station here, because that'll fail with old savegames */
973 CargoPacket
*cp
= new CargoPacket(_cargo_count
, _cargo_days
, _cargo_source
, _cargo_source_xy
, _cargo_loaded_at_xy
, _cargo_feeder_share
);
977 /* Old savegames used 'last_station_visited = 0xFF' */
978 if (IsSavegameVersionBefore(5) && v
->last_station_visited
== 0xFF) {
979 v
->last_station_visited
= INVALID_STATION
;
982 if (IsSavegameVersionBefore(182)) v
->last_loading_station
= INVALID_STATION
;
984 if (IsSavegameVersionBefore(5)) {
985 /* Convert the current_order.type (which is a mix of type and flags, because
986 * in those versions, they both were 4 bits big) to type and flags */
987 v
->current_order
.flags
= GB(v
->current_order
.type
, 4, 4);
988 v
->current_order
.type
&= 0x0F;
991 /* Advanced vehicle lists got added */
992 if (IsSavegameVersionBefore(60)) v
->group_id
= DEFAULT_GROUP
;
996 static void Ptrs_VEHS()
999 FOR_ALL_VEHICLES(v
) {
1000 SlObject(v
, GetVehicleDescription(v
->type
));
1004 const SaveLoad
*GetOrderExtraInfoDescription();
1008 /* save extended order info for vehicle current order */
1010 FOR_ALL_VEHICLES(v
) {
1011 if (v
->current_order
.extra
) {
1012 SlSetArrayIndex(v
->index
);
1013 SlObject(v
->current_order
.extra
.get(), GetOrderExtraInfoDescription());
1020 /* load extended order info for vehicle current order */
1022 while ((index
= SlIterateArray()) != -1) {
1023 Vehicle
*v
= Vehicle::GetIfValid(index
);
1024 assert(v
!= nullptr);
1025 v
->current_order
.AllocExtraInfo();
1026 SlObject(v
->current_order
.extra
.get(), GetOrderExtraInfoDescription());
1030 extern const ChunkHandler _veh_chunk_handlers
[] = {
1031 { 'VEHS', Save_VEHS
, Load_VEHS
, Ptrs_VEHS
, nullptr, CH_SPARSE_ARRAY
},
1032 { 'VEOX', Save_VEOX
, Load_VEOX
, nullptr, nullptr, CH_SPARSE_ARRAY
| CH_LAST
},