Update: Translations from eints
[openttd-github.git] / src / saveload / vehicle_sl.cpp
blob4e42de39622ad93a8053b07f752a8864cb07272f
1 /*
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/>.
6 */
8 /** @file vehicle_sl.cpp Code handling saving and loading of vehicles */
10 #include "../stdafx.h"
12 #include "saveload.h"
13 #include "compat/vehicle_sl_compat.h"
15 #include "../vehicle_func.h"
16 #include "../train.h"
17 #include "../roadveh.h"
18 #include "../ship.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"
30 /**
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()) {
61 if (!u->IsEngine()) {
62 /* we got a rear car without a front car. We will convert it to a front one */
63 u->SetEngine();
64 u->spritenum--;
67 /* Find a matching back part */
68 EngineID eid = u->engine_type;
69 Train *w;
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 */
75 if (w->IsEngine()) {
76 w->ClearEngine();
77 w->spritenum++;
79 break;
81 } else {
82 uint stack_pos = 0;
83 for (w = u->GetNextVehicle(); w != nullptr; w = w->GetNextVehicle()) {
84 if (w->engine_type != eid || w->other_multiheaded_part != nullptr || !w->IsMultiheaded()) continue;
86 if (w->IsEngine()) {
87 stack_pos++;
88 } else {
89 if (stack_pos == 0) break;
90 stack_pos--;
95 if (w != nullptr) {
96 w->other_multiheaded_part = u;
97 u->other_multiheaded_part = w;
98 } else {
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();
125 u->SetFrontEngine();
126 u->SetEngine();
127 break;
129 case 1: // TS_Artic_Part
130 u->subtype = 0;
131 u->SetArticulatedPart();
132 break;
134 case 2: // TS_Not_First
135 u->subtype = 0;
136 if (rvi->railveh_type == RAILVEH_WAGON) {
137 /* normal wagon */
138 u->SetWagon();
139 break;
141 if (rvi->railveh_type == RAILVEH_MULTIHEAD && rvi->image_index == u->spritenum - 1) {
142 /* rear end of a multiheaded engine */
143 u->SetMultiheaded();
144 break;
146 if (rvi->railveh_type == RAILVEH_MULTIHEAD) u->SetMultiheaded();
147 u->SetEngine();
148 break;
150 case 4: // TS_Free_Car
151 u->subtype = 0;
152 u->SetWagon();
153 u->SetFreeWagon();
154 break;
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)
173 * skip those */
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) {
177 a->state = HANGAR;
178 continue;
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();
189 a->state = FLYING;
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 */) {
206 Vehicle *v = *iter;
207 if (v->type == VEH_AIRCRAFT && !v->current_order.IsType(OT_LOADING)) {
208 iter = st->loading_vehicles.erase(iter);
209 delete v->cargo_payment;
210 } else {
211 ++iter;
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 */
236 switch (v->type) {
237 case VEH_TRAIN:
238 case VEH_ROAD:
239 case VEH_SHIP:
240 case VEH_AIRCRAFT:
241 if (v->engine_type >= total_engines || v->type != v->GetEngine()->type) {
242 v->engine_type = first_engine[v->type];
244 break;
246 default:
247 break;
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;
263 v->first = nullptr;
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. */
269 if (part_of_load) {
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);
289 } else {
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()) {
309 u->first = v;
314 if (part_of_load) {
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. */
337 rv->subtype = 0;
338 rv->SetArticulatedPart();
339 } else {
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();
350 v->unitnumber = 0;
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;
380 } else {
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);
417 switch (v->type) {
418 case VEH_TRAIN: {
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);
424 break;
427 case VEH_ROAD: {
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) {
443 rv->CargoChanged();
446 break;
449 case VEH_SHIP:
450 Ship::From(v)->UpdateCache();
451 break;
453 default: break;
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 */
466 t->cur_speed = 0;
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))) {
472 v->cur_speed = 0;
477 for (Vehicle *v : Vehicle::Iterate()) {
478 switch (v->type) {
479 case VEH_ROAD:
480 case VEH_TRAIN:
481 case VEH_SHIP:
482 v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
483 break;
485 case VEH_AIRCRAFT:
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);
505 break;
507 case VEH_DISASTER: {
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) {
514 delete v;
515 continue;
516 } else {
517 u->disaster_vehicle = dv->index;
521 break;
524 default: break;
527 if (part_of_load && v->unitnumber != 0) {
528 Company::Get(v->owner)->freeunits[v->type].UseID(v->unitnumber);
531 v->UpdateDeltaXY();
532 v->coord.left = INVALID_COORD;
533 v->sprite_cache.old_coord.left = INVALID_COORD;
534 v->UpdatePosition();
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;
560 int done;
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
576 int l = 0;
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. */
586 int moved;
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
593 l = 0;
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);
613 if (d <= 0) {
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> {
636 public:
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> {
786 public:
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> {
821 public:
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> {
857 public:
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> {
886 public:
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> {
926 public:
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> {
971 public:
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);
1056 int index;
1058 _cargo_count = 0;
1060 while ((index = SlIterateArray()) != -1) {
1061 Vehicle *v;
1062 VehicleType vtype = (VehicleType)SlReadByte();
1064 switch (vtype) {
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");
1075 SlObject(v, slt);
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[] = {
1112 VEHS,
1115 extern const ChunkHandlerTable _veh_chunk_handlers(veh_chunk_handlers);