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
= NULL
;
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
!= NULL
; u
= u
->GetNextVehicle()) {
60 if (u
->other_multiheaded_part
!= NULL
) 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
!= NULL
; w
= w
->GetNextVehicle()) {
74 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= NULL
|| !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
!= NULL
; w
= w
->GetNextVehicle()) {
86 if (w
->engine_type
!= eid
|| w
->other_multiheaded_part
!= NULL
|| !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
!= NULL
; 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
, NULL
);
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() != NULL
) v
->Next()->previous
= v
;
256 if (v
->NextShared() != NULL
) 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
!= NULL
) {
276 if (IsSavegameVersionBefore(105)) { // Pre-105 didn't save an OrderList
277 if (mapping
[v
->orders
.old
] == NULL
) {
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() == NULL
) {
294 v
->orders
.list
->Initialize(v
->orders
.list
->first
, v
);
301 FOR_ALL_VEHICLES(v
) {
302 /* Fill the first pointers */
303 if (v
->Previous() == NULL
) {
304 for (Vehicle
*u
= v
; u
!= NULL
; 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
!= NULL
|| v
->previous_shared
!= NULL
|| v
->next_shared
== NULL
) continue;
316 /* As above, allocating OrderList here is safe. */
317 assert(OrderList::CanAllocateItem());
318 v
->orders
.list
= new OrderList(NULL
, v
);
319 for (Vehicle
*u
= v
; u
!= NULL
; 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
!= NULL
);
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
392 RoadVehUpdateCache(rv
);
393 if (_settings_game
.vehicle
.roadveh_acceleration_model
!= AM_ORIGINAL
) {
401 Ship::From(v
)->UpdateCache();
408 /* Stop non-front engines */
409 if (part_of_load
&& IsSavegameVersionBefore(112)) {
410 FOR_ALL_VEHICLES(v
) {
411 if (v
->type
== VEH_TRAIN
) {
412 Train
*t
= Train::From(v
);
413 if (!t
->IsFrontEngine()) {
414 if (t
->IsEngine()) t
->vehstatus
|= VS_STOPPED
;
415 /* cur_speed is now relevant for non-front parts - nonzero breaks
416 * moving-wagons-inside-depot- and autoreplace- code */
420 /* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
421 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
422 if ((v
->vehstatus
& VS_STOPPED
) && (v
->type
!= VEH_TRAIN
|| IsSavegameVersionBefore(2, 1))) {
428 FOR_ALL_VEHICLES(v
) {
431 RoadVehicle
*rv
= RoadVehicle::From(v
);
432 rv
->roadtype
= HasBit(EngInfo(v
->First()->engine_type
)->misc_flags
, EF_ROAD_TRAM
) ? ROADTYPE_TRAM
: ROADTYPE_ROAD
;
433 rv
->compatible_roadtypes
= RoadTypeToRoadTypes(rv
->roadtype
);
439 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_seq
);
443 if (Aircraft::From(v
)->IsNormalAircraft()) {
444 v
->GetImage(v
->direction
, EIT_ON_MAP
, &v
->sprite_seq
);
446 /* The plane's shadow will have the same image as the plane, but no colour */
447 Vehicle
*shadow
= v
->Next();
448 shadow
->sprite_seq
.CopyWithoutPalette(v
->sprite_seq
);
450 /* In the case of a helicopter we will update the rotor sprites */
451 if (v
->subtype
== AIR_HELICOPTER
) {
452 Vehicle
*rotor
= shadow
->Next();
453 GetRotorImage(Aircraft::From(v
), EIT_ON_MAP
, &rotor
->sprite_seq
);
456 UpdateAircraftCache(Aircraft::From(v
), true);
462 v
->UpdateDeltaXY(v
->direction
);
463 v
->coord
.left
= INVALID_COORD
;
465 v
->UpdateViewport(false);
469 bool TrainController(Train
*v
, Vehicle
*nomove
, bool reverse
= true); // From train_cmd.cpp
470 void ReverseTrainDirection(Train
*v
);
471 void ReverseTrainSwapVeh(Train
*v
, int l
, int r
);
473 /** Fixup old train spacing. */
474 void FixupTrainLengths()
476 /* Vehicle center was moved from 4 units behind the front to half the length
477 * behind the front. Move vehicles so they end up on the same spot. */
479 FOR_ALL_VEHICLES(v
) {
480 if (v
->type
== VEH_TRAIN
&& v
->IsPrimaryVehicle()) {
481 /* The vehicle center is now more to the front depending on vehicle length,
482 * so we need to move all vehicles forward to cover the difference to the
483 * old center, otherwise wagon spacing in trains would be broken upon load. */
484 for (Train
*u
= Train::From(v
); u
!= NULL
; u
= u
->Next()) {
485 if (u
->track
== TRACK_BIT_DEPOT
|| (u
->vehstatus
& VS_CRASHED
)) continue;
487 Train
*next
= u
->Next();
489 /* Try to pull the vehicle half its length forward. */
490 int diff
= (VEHICLE_LENGTH
- u
->gcache
.cached_veh_length
) / 2;
492 for (done
= 0; done
< diff
; done
++) {
493 if (!TrainController(u
, next
, false)) break;
496 if (next
!= NULL
&& done
< diff
&& u
->IsFrontEngine()) {
497 /* Pulling the front vehicle forwards failed, we either encountered a dead-end
498 * or a red signal. To fix this, we try to move the whole train the required
499 * space backwards and re-do the fix up of the front vehicle. */
501 /* Ignore any signals when backtracking. */
502 TrainForceProceeding old_tfp
= u
->force_proceed
;
503 u
->force_proceed
= TFP_SIGNAL
;
505 /* Swap start<>end, start+1<>end-1, ... */
506 int r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
508 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
510 /* We moved the first vehicle which is now the last. Move it back to the
511 * original position as we will fix up the last vehicle later in the loop. */
512 for (int i
= 0; i
< done
; i
++) TrainController(u
->Last(), NULL
);
514 /* Move the train backwards to get space for the first vehicle. As the stopping
515 * distance from a line end is rounded up, move the train one unit more to cater
516 * for front vehicles with odd lengths. */
518 for (moved
= 0; moved
< diff
+ 1; moved
++) {
519 if (!TrainController(u
, NULL
, false)) break;
522 /* Swap start<>end, start+1<>end-1, ... again. */
523 r
= CountVehiclesInChain(u
) - 1; // number of vehicles - 1
525 do ReverseTrainSwapVeh(u
, l
++, r
--); while (l
<= r
);
527 u
->force_proceed
= old_tfp
;
529 /* Tracks are too short to fix the train length. The player has to fix the
530 * train in a depot. Bail out so we don't damage the vehicle chain any more. */
531 if (moved
< diff
+ 1) break;
533 /* Re-do the correction for the first vehicle. */
534 for (done
= 0; done
< diff
; done
++) TrainController(u
, next
, false);
536 /* We moved one unit more backwards than needed for even-length front vehicles,
537 * try to move that unit forward again. We don't care if this step fails. */
538 TrainController(u
, NULL
, false);
541 /* If the next wagon is still in a depot, check if it shouldn't be outside already. */
542 if (next
!= NULL
&& next
->track
== TRACK_BIT_DEPOT
) {
543 int d
= TicksToLeaveDepot(u
);
545 /* Next vehicle should have left the depot already, show it and pull forward. */
546 next
->vehstatus
&= ~VS_HIDDEN
;
547 next
->track
= TrackToTrackBits(GetRailDepotTrack(next
->tile
));
548 for (int i
= 0; i
>= d
; i
--) TrainController(next
, NULL
);
553 /* Update all cached properties after moving the vehicle chain around. */
554 Train::From(v
)->ConsistChanged(CCF_TRACK
);
559 static uint8 _cargo_days
;
560 static uint16 _cargo_source
;
561 static uint32 _cargo_source_xy
;
562 static uint16 _cargo_count
;
563 static uint16 _cargo_paid_for
;
564 static Money _cargo_feeder_share
;
565 static uint32 _cargo_loaded_at_xy
;
568 * Make it possible to make the saveload tables "friends" of other classes.
569 * @param vt the vehicle type. Can be VEH_END for the common vehicle description data
570 * @return the saveload description
572 const SaveLoad
*GetVehicleDescription(VehicleType vt
)
574 /** Save and load of vehicles */
575 static const SaveLoad _common_veh_desc
[] = {
576 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
578 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
579 SLE_CONDVAR(Vehicle
, name
, SLE_NAME
, 0, 83),
580 SLE_CONDSTR(Vehicle
, name
, SLE_STR
| SLF_ALLOW_CONTROL
, 0, 84, SL_MAX_VERSION
),
581 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 7),
582 SLE_CONDVAR(Vehicle
, unitnumber
, SLE_UINT16
, 8, SL_MAX_VERSION
),
583 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
584 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
585 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
586 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
587 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
589 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
590 SLE_CONDVAR(Vehicle
, x_pos
, SLE_UINT32
, 6, SL_MAX_VERSION
),
591 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
592 SLE_CONDVAR(Vehicle
, y_pos
, SLE_UINT32
, 6, SL_MAX_VERSION
),
593 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
594 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
595 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
597 SLE_CONDNULL(2, 0, 57),
598 SLE_VAR(Vehicle
, spritenum
, SLE_UINT8
),
599 SLE_CONDNULL(5, 0, 57),
600 SLE_VAR(Vehicle
, engine_type
, SLE_UINT16
),
602 SLE_CONDNULL(2, 0, 151),
603 SLE_VAR(Vehicle
, cur_speed
, SLE_UINT16
),
604 SLE_VAR(Vehicle
, subspeed
, SLE_UINT8
),
605 SLE_VAR(Vehicle
, acceleration
, SLE_UINT8
),
606 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
608 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
609 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
610 SLE_CONDVAR(Vehicle
, last_station_visited
, SLE_UINT16
, 5, SL_MAX_VERSION
),
611 SLE_CONDVAR(Vehicle
, last_loading_station
, SLE_UINT16
, 182, SL_MAX_VERSION
),
613 SLE_VAR(Vehicle
, cargo_type
, SLE_UINT8
),
614 SLE_CONDVAR(Vehicle
, cargo_subtype
, SLE_UINT8
, 35, SL_MAX_VERSION
),
615 SLEG_CONDVAR( _cargo_days
, SLE_UINT8
, 0, 67),
616 SLEG_CONDVAR( _cargo_source
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 6),
617 SLEG_CONDVAR( _cargo_source
, SLE_UINT16
, 7, 67),
618 SLEG_CONDVAR( _cargo_source_xy
, SLE_UINT32
, 44, 67),
619 SLE_VAR(Vehicle
, cargo_cap
, SLE_UINT16
),
620 SLE_CONDVAR(Vehicle
, refit_cap
, SLE_UINT16
, 182, SL_MAX_VERSION
),
621 SLEG_CONDVAR( _cargo_count
, SLE_UINT16
, 0, 67),
622 SLE_CONDLST(Vehicle
, cargo
.packets
, REF_CARGO_PACKET
, 68, SL_MAX_VERSION
),
623 SLE_CONDARR(Vehicle
, cargo
.action_counts
, SLE_UINT
, VehicleCargoList::NUM_MOVE_TO_ACTION
, 181, SL_MAX_VERSION
),
624 SLE_CONDVAR(Vehicle
, cargo_age_counter
, SLE_UINT16
, 162, SL_MAX_VERSION
),
626 SLE_VAR(Vehicle
, day_counter
, SLE_UINT8
),
627 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
628 SLE_CONDVAR(Vehicle
, running_ticks
, SLE_UINT8
, 88, SL_MAX_VERSION
),
630 SLE_VAR(Vehicle
, cur_implicit_order_index
, SLE_UINT8
),
631 SLE_CONDVAR(Vehicle
, cur_real_order_index
, SLE_UINT8
, 158, SL_MAX_VERSION
),
632 /* num_orders is now part of OrderList and is not saved but counted */
633 SLE_CONDNULL(1, 0, 104),
635 /* This next line is for version 4 and prior compatibility.. it temporarily reads
636 type and flags (which were both 4 bits) into type. Later on this is
637 converted correctly */
638 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, 0, 4),
639 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
641 /* Orders for version 5 and on */
642 SLE_CONDVAR(Vehicle
, current_order
.type
, SLE_UINT8
, 5, SL_MAX_VERSION
),
643 SLE_CONDVAR(Vehicle
, current_order
.flags
, SLE_UINT8
, 5, SL_MAX_VERSION
),
644 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, 5, SL_MAX_VERSION
),
646 /* Refit in current order */
647 SLE_CONDVAR(Vehicle
, current_order
.refit_cargo
, SLE_UINT8
, 36, SL_MAX_VERSION
),
648 SLE_CONDNULL(1, 36, 181), // refit_subtype
650 /* Timetable in current order */
651 SLE_CONDVAR(Vehicle
, current_order
.wait_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
652 SLE_CONDVAR(Vehicle
, current_order
.travel_time
, SLE_UINT16
, 67, SL_MAX_VERSION
),
653 SLE_CONDVAR(Vehicle
, current_order
.max_speed
, SLE_UINT16
, 174, SL_MAX_VERSION
),
654 SLE_CONDVAR(Vehicle
, timetable_start
, SLE_INT32
, 129, SL_MAX_VERSION
),
656 SLE_CONDREF(Vehicle
, orders
, REF_ORDER
, 0, 104),
657 SLE_CONDREF(Vehicle
, orders
, REF_ORDERLIST
, 105, SL_MAX_VERSION
),
659 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
660 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, 31, SL_MAX_VERSION
),
661 SLE_CONDVAR(Vehicle
, max_age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
662 SLE_CONDVAR(Vehicle
, max_age
, SLE_INT32
, 31, SL_MAX_VERSION
),
663 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
664 SLE_CONDVAR(Vehicle
, date_of_last_service
, SLE_INT32
, 31, SL_MAX_VERSION
),
665 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, 0, 30),
666 SLE_CONDVAR(Vehicle
, service_interval
, SLE_FILE_U32
| SLE_VAR_U16
, 31, 179),
667 SLE_CONDVAR(Vehicle
, service_interval
, SLE_UINT16
, 180, SL_MAX_VERSION
),
668 SLE_VAR(Vehicle
, reliability
, SLE_UINT16
),
669 SLE_VAR(Vehicle
, reliability_spd_dec
, SLE_UINT16
),
670 SLE_VAR(Vehicle
, breakdown_ctr
, SLE_UINT8
),
671 SLE_VAR(Vehicle
, breakdown_delay
, SLE_UINT8
),
672 SLE_VAR(Vehicle
, breakdowns_since_last_service
, SLE_UINT8
),
673 SLE_VAR(Vehicle
, breakdown_chance
, SLE_UINT8
),
674 SLE_CONDVAR(Vehicle
, build_year
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 30),
675 SLE_CONDVAR(Vehicle
, build_year
, SLE_INT32
, 31, SL_MAX_VERSION
),
677 SLE_VAR(Vehicle
, load_unload_ticks
, SLE_UINT16
),
678 SLEG_CONDVAR( _cargo_paid_for
, SLE_UINT16
, 45, SL_MAX_VERSION
),
679 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_FILE_U8
| SLE_VAR_U16
, 40, 179),
680 SLE_CONDVAR(Vehicle
, vehicle_flags
, SLE_UINT16
, 180, SL_MAX_VERSION
),
682 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
683 SLE_CONDVAR(Vehicle
, profit_this_year
, SLE_INT64
, 65, SL_MAX_VERSION
),
684 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
685 SLE_CONDVAR(Vehicle
, profit_last_year
, SLE_INT64
, 65, SL_MAX_VERSION
),
686 SLEG_CONDVAR( _cargo_feeder_share
, SLE_FILE_I32
| SLE_VAR_I64
, 51, 64),
687 SLEG_CONDVAR( _cargo_feeder_share
, SLE_INT64
, 65, 67),
688 SLEG_CONDVAR( _cargo_loaded_at_xy
, SLE_UINT32
, 51, 67),
689 SLE_CONDVAR(Vehicle
, value
, SLE_FILE_I32
| SLE_VAR_I64
, 0, 64),
690 SLE_CONDVAR(Vehicle
, value
, SLE_INT64
, 65, SL_MAX_VERSION
),
692 SLE_CONDVAR(Vehicle
, random_bits
, SLE_UINT8
, 2, SL_MAX_VERSION
),
693 SLE_CONDVAR(Vehicle
, waiting_triggers
, SLE_UINT8
, 2, SL_MAX_VERSION
),
695 SLE_CONDREF(Vehicle
, next_shared
, REF_VEHICLE
, 2, SL_MAX_VERSION
),
696 SLE_CONDNULL(2, 2, 68),
697 SLE_CONDNULL(4, 69, 100),
699 SLE_CONDVAR(Vehicle
, group_id
, SLE_UINT16
, 60, SL_MAX_VERSION
),
701 SLE_CONDVAR(Vehicle
, current_order_time
, SLE_UINT32
, 67, SL_MAX_VERSION
),
702 SLE_CONDVAR(Vehicle
, lateness_counter
, SLE_INT32
, 67, SL_MAX_VERSION
),
704 SLE_CONDNULL(10, 2, 143), // old reserved space
710 static const SaveLoad _train_desc
[] = {
711 SLE_WRITEBYTE(Vehicle
, type
, VEH_TRAIN
),
713 SLE_VAR(Train
, crash_anim_pos
, SLE_UINT16
),
714 SLE_VAR(Train
, force_proceed
, SLE_UINT8
),
715 SLE_VAR(Train
, railtype
, SLE_UINT8
),
716 SLE_VAR(Train
, track
, SLE_UINT8
),
718 SLE_CONDVAR(Train
, flags
, SLE_FILE_U8
| SLE_VAR_U16
, 2, 99),
719 SLE_CONDVAR(Train
, flags
, SLE_UINT16
, 100, SL_MAX_VERSION
),
720 SLE_CONDNULL(2, 2, 59),
722 SLE_CONDVAR(Train
, wait_counter
, SLE_UINT16
, 136, SL_MAX_VERSION
),
724 SLE_CONDNULL(2, 2, 19),
725 SLE_CONDVAR(Train
, gv_flags
, SLE_UINT16
, 139, SL_MAX_VERSION
),
726 SLE_CONDNULL(11, 2, 143), // old reserved space
731 static const SaveLoad _roadveh_desc
[] = {
732 SLE_WRITEBYTE(Vehicle
, type
, VEH_ROAD
),
734 SLE_VAR(RoadVehicle
, state
, SLE_UINT8
),
735 SLE_VAR(RoadVehicle
, frame
, SLE_UINT8
),
736 SLE_VAR(RoadVehicle
, blocked_ctr
, SLE_UINT16
),
737 SLE_VAR(RoadVehicle
, overtaking
, SLE_UINT8
),
738 SLE_VAR(RoadVehicle
, overtaking_ctr
, SLE_UINT8
),
739 SLE_VAR(RoadVehicle
, crashed_ctr
, SLE_UINT16
),
740 SLE_VAR(RoadVehicle
, reverse_ctr
, SLE_UINT8
),
742 SLE_CONDNULL(2, 6, 68),
743 SLE_CONDVAR(RoadVehicle
, gv_flags
, SLE_UINT16
, 139, SL_MAX_VERSION
),
744 SLE_CONDNULL(4, 69, 130),
745 SLE_CONDNULL(2, 6, 130),
746 SLE_CONDNULL(16, 2, 143), // old reserved space
751 static const SaveLoad _ship_desc
[] = {
752 SLE_WRITEBYTE(Vehicle
, type
, VEH_SHIP
),
754 SLE_VAR(Ship
, state
, SLE_UINT8
),
756 SLE_CONDNULL(16, 2, 143), // old reserved space
761 static const SaveLoad _aircraft_desc
[] = {
762 SLE_WRITEBYTE(Vehicle
, type
, VEH_AIRCRAFT
),
764 SLE_VAR(Aircraft
, crashed_counter
, SLE_UINT16
),
765 SLE_VAR(Aircraft
, pos
, SLE_UINT8
),
767 SLE_CONDVAR(Aircraft
, targetairport
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
768 SLE_CONDVAR(Aircraft
, targetairport
, SLE_UINT16
, 5, SL_MAX_VERSION
),
770 SLE_VAR(Aircraft
, state
, SLE_UINT8
),
772 SLE_CONDVAR(Aircraft
, previous_pos
, SLE_UINT8
, 2, SL_MAX_VERSION
),
773 SLE_CONDVAR(Aircraft
, last_direction
, SLE_UINT8
, 2, SL_MAX_VERSION
),
774 SLE_CONDVAR(Aircraft
, number_consecutive_turns
, SLE_UINT8
, 2, SL_MAX_VERSION
),
776 SLE_CONDVAR(Aircraft
, turn_counter
, SLE_UINT8
, 136, SL_MAX_VERSION
),
777 SLE_CONDVAR(Aircraft
, flags
, SLE_UINT8
, 167, SL_MAX_VERSION
),
779 SLE_CONDNULL(13, 2, 143), // old reserved space
784 static const SaveLoad _special_desc
[] = {
785 SLE_WRITEBYTE(Vehicle
, type
, VEH_EFFECT
),
787 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
789 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
790 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
792 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
793 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
794 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
795 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
796 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
797 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
799 SLE_VAR(Vehicle
, sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
800 SLE_CONDNULL(5, 0, 57),
801 SLE_VAR(Vehicle
, progress
, SLE_UINT8
),
802 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
804 SLE_VAR(EffectVehicle
, animation_state
, SLE_UINT16
),
805 SLE_VAR(EffectVehicle
, animation_substate
, SLE_UINT8
),
807 SLE_CONDVAR(Vehicle
, spritenum
, SLE_UINT8
, 2, SL_MAX_VERSION
),
809 SLE_CONDNULL(15, 2, 143), // old reserved space
814 static const SaveLoad _disaster_desc
[] = {
815 SLE_WRITEBYTE(Vehicle
, type
, VEH_DISASTER
),
817 SLE_REF(Vehicle
, next
, REF_VEHICLE_OLD
),
819 SLE_VAR(Vehicle
, subtype
, SLE_UINT8
),
820 SLE_CONDVAR(Vehicle
, tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
821 SLE_CONDVAR(Vehicle
, tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
822 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 5),
823 SLE_CONDVAR(Vehicle
, dest_tile
, SLE_UINT32
, 6, SL_MAX_VERSION
),
825 SLE_CONDVAR(Vehicle
, x_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
826 SLE_CONDVAR(Vehicle
, x_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
827 SLE_CONDVAR(Vehicle
, y_pos
, SLE_FILE_I16
| SLE_VAR_I32
, 0, 5),
828 SLE_CONDVAR(Vehicle
, y_pos
, SLE_INT32
, 6, SL_MAX_VERSION
),
829 SLE_CONDVAR(Vehicle
, z_pos
, SLE_FILE_U8
| SLE_VAR_I32
, 0, 163),
830 SLE_CONDVAR(Vehicle
, z_pos
, SLE_INT32
, 164, SL_MAX_VERSION
),
831 SLE_VAR(Vehicle
, direction
, SLE_UINT8
),
833 SLE_CONDNULL(5, 0, 57),
834 SLE_VAR(Vehicle
, owner
, SLE_UINT8
),
835 SLE_VAR(Vehicle
, vehstatus
, SLE_UINT8
),
836 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_FILE_U8
| SLE_VAR_U16
, 0, 4),
837 SLE_CONDVAR(Vehicle
, current_order
.dest
, SLE_UINT16
, 5, SL_MAX_VERSION
),
839 SLE_VAR(Vehicle
, sprite_seq
.seq
[0].sprite
, SLE_FILE_U16
| SLE_VAR_U32
),
840 SLE_CONDVAR(Vehicle
, age
, SLE_FILE_U16
| SLE_VAR_I32
, 0, 30),
841 SLE_CONDVAR(Vehicle
, age
, SLE_INT32
, 31, SL_MAX_VERSION
),
842 SLE_VAR(Vehicle
, tick_counter
, SLE_UINT8
),
844 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 190),
845 SLE_CONDVAR(DisasterVehicle
, image_override
, SLE_UINT32
, 191, SL_MAX_VERSION
),
846 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_FILE_U16
| SLE_VAR_U32
, 0, 190),
847 SLE_CONDVAR(DisasterVehicle
, big_ufo_destroyer_target
, SLE_UINT32
, 191, SL_MAX_VERSION
),
848 SLE_CONDVAR(DisasterVehicle
, flags
, SLE_UINT8
, 194, SL_MAX_VERSION
),
850 SLE_CONDNULL(16, 2, 143), // old reserved space
856 static const SaveLoad
* const _veh_descs
[] = {
866 return _veh_descs
[vt
];
869 /** Will be called when the vehicles need to be saved. */
870 static void Save_VEHS()
873 /* Write the vehicles */
874 FOR_ALL_VEHICLES(v
) {
875 SlSetArrayIndex(v
->index
);
876 SlObject(v
, GetVehicleDescription(v
->type
));
880 /** Will be called when vehicles need to be loaded. */
887 while ((index
= SlIterateArray()) != -1) {
889 VehicleType vtype
= (VehicleType
)SlReadByte();
892 case VEH_TRAIN
: v
= new (index
) Train(); break;
893 case VEH_ROAD
: v
= new (index
) RoadVehicle(); break;
894 case VEH_SHIP
: v
= new (index
) Ship(); break;
895 case VEH_AIRCRAFT
: v
= new (index
) Aircraft(); break;
896 case VEH_EFFECT
: v
= new (index
) EffectVehicle(); break;
897 case VEH_DISASTER
: v
= new (index
) DisasterVehicle(); break;
898 case VEH_INVALID
: // Savegame shouldn't contain invalid vehicles
899 default: SlErrorCorrupt("Invalid vehicle type");
902 SlObject(v
, GetVehicleDescription(vtype
));
904 if (_cargo_count
!= 0 && IsCompanyBuildableVehicleType(v
) && CargoPacket::CanAllocateItem()) {
905 /* Don't construct the packet with station here, because that'll fail with old savegames */
906 CargoPacket
*cp
= new CargoPacket(_cargo_count
, _cargo_days
, _cargo_source
, _cargo_source_xy
, _cargo_loaded_at_xy
, _cargo_feeder_share
);
910 /* Old savegames used 'last_station_visited = 0xFF' */
911 if (IsSavegameVersionBefore(5) && v
->last_station_visited
== 0xFF) {
912 v
->last_station_visited
= INVALID_STATION
;
915 if (IsSavegameVersionBefore(182)) v
->last_loading_station
= INVALID_STATION
;
917 if (IsSavegameVersionBefore(5)) {
918 /* Convert the current_order.type (which is a mix of type and flags, because
919 * in those versions, they both were 4 bits big) to type and flags */
920 v
->current_order
.flags
= GB(v
->current_order
.type
, 4, 4);
921 v
->current_order
.type
&= 0x0F;
924 /* Advanced vehicle lists got added */
925 if (IsSavegameVersionBefore(60)) v
->group_id
= DEFAULT_GROUP
;
929 static void Ptrs_VEHS()
932 FOR_ALL_VEHICLES(v
) {
933 SlObject(v
, GetVehicleDescription(v
->type
));
937 extern const ChunkHandler _veh_chunk_handlers
[] = {
938 { 'VEHS', Save_VEHS
, Load_VEHS
, Ptrs_VEHS
, NULL
, CH_SPARSE_ARRAY
| CH_LAST
},