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  */
7 
8 /** @file vehicle_sl.cpp Code handling saving and loading of vehicles */
9 
10 #include "../stdafx.h"
11 
12 #include "saveload.h"
13 #include "compat/vehicle_sl_compat.h"
14 
15 #include "../vehicle_func.h"
16 #include "../train.h"
17 #include "../roadveh.h"
18 #include "../ship.h"
19 #include "../aircraft.h"
20 #include "../station_base.h"
21 #include "../effectvehicle_base.h"
22 #include "../company_base.h"
23 #include "../company_func.h"
24 #include "../disaster_vehicle.h"
25 
26 #include <map>
27 
28 #include "../safeguards.h"
29 
30 /**
31  * Link front and rear multiheaded engines to each other
32  * This is done when loading a savegame
33  */
ConnectMultiheadedTrains()34 void ConnectMultiheadedTrains()
35 {
36 	for (Train *v : Train::Iterate()) {
37 		v->other_multiheaded_part = nullptr;
38 	}
39 
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 ..<..<..>..<..>..>..
45 			 *
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.
50 			 *
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.
53 			 */
54 
55 			bool sequential_matching = v->IsFrontEngine();
56 
57 			for (Train *u = v; u != nullptr; u = u->GetNextVehicle()) {
58 				if (u->other_multiheaded_part != nullptr) continue; // we already linked this one
59 
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--;
65 					}
66 
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;
73 
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++;
78 							}
79 							break;
80 						}
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;
85 
86 							if (w->IsEngine()) {
87 								stack_pos++;
88 							} else {
89 								if (stack_pos == 0) break;
90 								stack_pos--;
91 							}
92 						}
93 					}
94 
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();
101 					}
102 				}
103 			}
104 		}
105 	}
106 }
107 
108 /**
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
111  */
ConvertOldMultiheadToNew()112 void ConvertOldMultiheadToNew()
113 {
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
115 
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);
120 
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;
128 
129 					case 1: // TS_Artic_Part
130 						u->subtype = 0;
131 						u->SetArticulatedPart();
132 						break;
133 
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;
140 						}
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;
145 						}
146 						if (rvi->railveh_type == RAILVEH_MULTIHEAD) u->SetMultiheaded();
147 						u->SetEngine();
148 						break;
149 
150 					case 4: // TS_Free_Car
151 						u->subtype = 0;
152 						u->SetWagon();
153 						u->SetFreeWagon();
154 						break;
155 					default: SlErrorCorrupt("Invalid train subtype");
156 				}
157 			}
158 		}
159 	}
160 }
161 
162 
163 /** need to be called to load aircraft from old version */
UpdateOldAircraft()164 void UpdateOldAircraft()
165 {
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
169 	}
170 
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;
179 			}
180 
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();
188 			}
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
193 
194 			/* correct speed of helicopter-rotors */
195 			if (a->subtype == AIR_HELICOPTER) a->Next()->Next()->cur_speed = 32;
196 
197 			/* set new position x,y,z */
198 			GetAircraftFlightLevelBounds(a, &a->z_pos, nullptr);
199 			SetAircraftPosition(a, gp.x, gp.y, GetAircraftFlightLevel(a));
200 		}
201 	}
202 }
203 
204 /**
205  * Check all vehicles to ensure their engine type is valid
206  * for the currently loaded NewGRFs (that includes none...)
207  * This only makes a difference if NewGRFs are missing, otherwise
208  * all vehicles will be valid. This does not make such a game
209  * playable, it only prevents crash.
210  */
CheckValidVehicles()211 static void CheckValidVehicles()
212 {
213 	size_t total_engines = Engine::GetPoolSize();
214 	EngineID first_engine[4] = { INVALID_ENGINE, INVALID_ENGINE, INVALID_ENGINE, INVALID_ENGINE };
215 
216 	for (const Engine *e : Engine::IterateType(VEH_TRAIN)) { first_engine[VEH_TRAIN] = e->index; break; }
217 	for (const Engine *e : Engine::IterateType(VEH_ROAD)) { first_engine[VEH_ROAD] = e->index; break; }
218 	for (const Engine *e : Engine::IterateType(VEH_SHIP)) { first_engine[VEH_SHIP] = e->index; break; }
219 	for (const Engine *e : Engine::IterateType(VEH_AIRCRAFT)) { first_engine[VEH_AIRCRAFT] = e->index; break; }
220 
221 	for (Vehicle *v : Vehicle::Iterate()) {
222 		/* Test if engine types match */
223 		switch (v->type) {
224 			case VEH_TRAIN:
225 			case VEH_ROAD:
226 			case VEH_SHIP:
227 			case VEH_AIRCRAFT:
228 				if (v->engine_type >= total_engines || v->type != v->GetEngine()->type) {
229 					v->engine_type = first_engine[v->type];
230 				}
231 				break;
232 
233 			default:
234 				break;
235 		}
236 	}
237 }
238 
239 extern byte _age_cargo_skip_counter; // From misc_sl.cpp
240 
241 /** Called after load to update coordinates */
AfterLoadVehicles(bool part_of_load)242 void AfterLoadVehicles(bool part_of_load)
243 {
244 	for (Vehicle *v : Vehicle::Iterate()) {
245 		/* Reinstate the previous pointer */
246 		if (v->Next() != nullptr) v->Next()->previous = v;
247 		if (v->NextShared() != nullptr) v->NextShared()->previous_shared = v;
248 
249 		if (part_of_load) v->fill_percent_te_id = INVALID_TE_ID;
250 		v->first = nullptr;
251 		if (v->IsGroundVehicle()) v->GetGroundVehicleCache()->first_engine = INVALID_ENGINE;
252 	}
253 
254 	/* AfterLoadVehicles may also be called in case of NewGRF reload, in this
255 	 * case we may not convert orders again. */
256 	if (part_of_load) {
257 		/* Create shared vehicle chain for very old games (pre 5,2) and create
258 		 * OrderList from shared vehicle chains. For this to work correctly, the
259 		 * following conditions must be fulfilled:
260 		 * a) both next_shared and previous_shared are not set for pre 5,2 games
261 		 * b) both next_shared and previous_shared are set for later games
262 		 */
263 		std::map<Order*, OrderList*> mapping;
264 
265 		for (Vehicle *v : Vehicle::Iterate()) {
266 			if (v->orders.old != nullptr) {
267 				if (IsSavegameVersionBefore(SLV_105)) { // Pre-105 didn't save an OrderList
268 					if (mapping[v->orders.old] == nullptr) {
269 						/* This adds the whole shared vehicle chain for case b */
270 
271 						/* Creating an OrderList here is safe because the number of vehicles
272 						 * allowed in these savegames matches the number of OrderLists. As
273 						 * such each vehicle can get an OrderList and it will (still) fit. */
274 						assert(OrderList::CanAllocateItem());
275 						v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v);
276 					} else {
277 						v->orders.list = mapping[v->orders.old];
278 						/* For old games (case a) we must create the shared vehicle chain */
279 						if (IsSavegameVersionBefore(SLV_5, 2)) {
280 							v->AddToShared(v->orders.list->GetFirstSharedVehicle());
281 						}
282 					}
283 				} else { // OrderList was saved as such, only recalculate not saved values
284 					if (v->PreviousShared() == nullptr) {
285 						v->orders.list->Initialize(v->orders.list->first, v);
286 					}
287 				}
288 			}
289 		}
290 	}
291 
292 	for (Vehicle *v : Vehicle::Iterate()) {
293 		/* Fill the first pointers */
294 		if (v->Previous() == nullptr) {
295 			for (Vehicle *u = v; u != nullptr; u = u->Next()) {
296 				u->first = v;
297 			}
298 		}
299 	}
300 
301 	if (part_of_load) {
302 		if (IsSavegameVersionBefore(SLV_105)) {
303 			/* Before 105 there was no order for shared orders, thus it messed up horribly */
304 			for (Vehicle *v : Vehicle::Iterate()) {
305 				if (v->First() != v || v->orders.list != nullptr || v->previous_shared != nullptr || v->next_shared == nullptr) continue;
306 
307 				/* As above, allocating OrderList here is safe. */
308 				assert(OrderList::CanAllocateItem());
309 				v->orders.list = new OrderList(nullptr, v);
310 				for (Vehicle *u = v; u != nullptr; u = u->next_shared) {
311 					u->orders.list = v->orders.list;
312 				}
313 			}
314 		}
315 
316 		if (IsSavegameVersionBefore(SLV_157)) {
317 			/* The road vehicle subtype was converted to a flag. */
318 			for (RoadVehicle *rv : RoadVehicle::Iterate()) {
319 				if (rv->subtype == 0) {
320 					/* The road vehicle is at the front. */
321 					rv->SetFrontEngine();
322 				} else if (rv->subtype == 1) {
323 					/* The road vehicle is an articulated part. */
324 					rv->subtype = 0;
325 					rv->SetArticulatedPart();
326 				} else {
327 					SlErrorCorrupt("Invalid road vehicle subtype");
328 				}
329 			}
330 		}
331 
332 		if (IsSavegameVersionBefore(SLV_160)) {
333 			/* In some old savegames there might be some "crap" stored. */
334 			for (Vehicle *v : Vehicle::Iterate()) {
335 				if (!v->IsPrimaryVehicle() && v->type != VEH_DISASTER) {
336 					v->current_order.Free();
337 					v->unitnumber = 0;
338 				}
339 			}
340 		}
341 
342 		if (IsSavegameVersionBefore(SLV_162)) {
343 			/* Set the vehicle-local cargo age counter from the old global counter. */
344 			for (Vehicle *v : Vehicle::Iterate()) {
345 				v->cargo_age_counter = _age_cargo_skip_counter;
346 			}
347 		}
348 
349 		if (IsSavegameVersionBefore(SLV_180)) {
350 			/* Set service interval flags */
351 			for (Vehicle *v : Vehicle::Iterate()) {
352 				if (!v->IsPrimaryVehicle()) continue;
353 
354 				const Company *c = Company::Get(v->owner);
355 				int interval = CompanyServiceInterval(c, v->type);
356 
357 				v->SetServiceIntervalIsCustom(v->GetServiceInterval() != interval);
358 				v->SetServiceIntervalIsPercent(c->settings.vehicle.servint_ispercent);
359 			}
360 		}
361 
362 		if (IsSavegameVersionBefore(SLV_SHIP_ROTATION)) {
363 			/* Ship rotation added */
364 			for (Ship *s : Ship::Iterate()) {
365 				s->rotation = s->direction;
366 			}
367 		} else {
368 			for (Ship *s : Ship::Iterate()) {
369 				if (s->rotation == s->direction) continue;
370 				/* In case we are rotating on gameload, set the rotation position to
371 				 * the current position, otherwise the applied workaround offset would
372 				 * be with respect to 0,0.
373 				 */
374 				s->rotation_x_pos = s->x_pos;
375 				s->rotation_y_pos = s->y_pos;
376 			}
377 		}
378 	}
379 
380 	CheckValidVehicles();
381 
382 	for (Vehicle *v : Vehicle::Iterate()) {
383 		assert(v->first != nullptr);
384 
385 		v->trip_occupancy = CalcPercentVehicleFilled(v, nullptr);
386 
387 		switch (v->type) {
388 			case VEH_TRAIN: {
389 				Train *t = Train::From(v);
390 				if (t->IsFrontEngine() || t->IsFreeWagon()) {
391 					t->gcache.last_speed = t->cur_speed; // update displayed train speed
392 					t->ConsistChanged(CCF_SAVELOAD);
393 				}
394 				break;
395 			}
396 
397 			case VEH_ROAD: {
398 				RoadVehicle *rv = RoadVehicle::From(v);
399 				if (rv->IsFrontEngine()) {
400 					rv->gcache.last_speed = rv->cur_speed; // update displayed road vehicle speed
401 
402 					rv->roadtype = Engine::Get(rv->engine_type)->u.road.roadtype;
403 					rv->compatible_roadtypes = GetRoadTypeInfo(rv->roadtype)->powered_roadtypes;
404 					for (RoadVehicle *u = rv; u != nullptr; u = u->Next()) {
405 						u->roadtype = rv->roadtype;
406 						u->compatible_roadtypes = rv->compatible_roadtypes;
407 					}
408 
409 					RoadVehUpdateCache(rv);
410 					if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
411 						rv->CargoChanged();
412 					}
413 				}
414 				break;
415 			}
416 
417 			case VEH_SHIP:
418 				Ship::From(v)->UpdateCache();
419 				break;
420 
421 			default: break;
422 		}
423 	}
424 
425 	/* Stop non-front engines */
426 	if (part_of_load && IsSavegameVersionBefore(SLV_112)) {
427 		for (Vehicle *v : Vehicle::Iterate()) {
428 			if (v->type == VEH_TRAIN) {
429 				Train *t = Train::From(v);
430 				if (!t->IsFrontEngine()) {
431 					if (t->IsEngine()) t->vehstatus |= VS_STOPPED;
432 					/* cur_speed is now relevant for non-front parts - nonzero breaks
433 					 * moving-wagons-inside-depot- and autoreplace- code */
434 					t->cur_speed = 0;
435 				}
436 			}
437 			/* trains weren't stopping gradually in old OTTD versions (and TTO/TTD)
438 			 * other vehicle types didn't have zero speed while stopped (even in 'recent' OTTD versions) */
439 			if ((v->vehstatus & VS_STOPPED) && (v->type != VEH_TRAIN || IsSavegameVersionBefore(SLV_2, 1))) {
440 				v->cur_speed = 0;
441 			}
442 		}
443 	}
444 
445 	for (Vehicle *v : Vehicle::Iterate()) {
446 		switch (v->type) {
447 			case VEH_ROAD:
448 			case VEH_TRAIN:
449 			case VEH_SHIP:
450 				v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
451 				break;
452 
453 			case VEH_AIRCRAFT:
454 				if (Aircraft::From(v)->IsNormalAircraft()) {
455 					v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_cache.sprite_seq);
456 
457 					/* The plane's shadow will have the same image as the plane, but no colour */
458 					Vehicle *shadow = v->Next();
459 					shadow->sprite_cache.sprite_seq.CopyWithoutPalette(v->sprite_cache.sprite_seq);
460 
461 					/* In the case of a helicopter we will update the rotor sprites */
462 					if (v->subtype == AIR_HELICOPTER) {
463 						Vehicle *rotor = shadow->Next();
464 						GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_cache.sprite_seq);
465 					}
466 
467 					UpdateAircraftCache(Aircraft::From(v), true);
468 				}
469 				break;
470 			default: break;
471 		}
472 
473 		v->UpdateDeltaXY();
474 		v->coord.left = INVALID_COORD;
475 		v->sprite_cache.old_coord.left = INVALID_COORD;
476 		v->UpdatePosition();
477 		v->UpdateViewport(false);
478 	}
479 }
480 
481 bool TrainController(Train *v, Vehicle *nomove, bool reverse = true); // From train_cmd.cpp
482 void ReverseTrainDirection(Train *v);
483 void ReverseTrainSwapVeh(Train *v, int l, int r);
484 
485 /** Fixup old train spacing. */
FixupTrainLengths()486 void FixupTrainLengths()
487 {
488 	/* Vehicle center was moved from 4 units behind the front to half the length
489 	 * behind the front. Move vehicles so they end up on the same spot. */
490 	for (Vehicle *v : Vehicle::Iterate()) {
491 		if (v->type == VEH_TRAIN && v->IsPrimaryVehicle()) {
492 			/* The vehicle center is now more to the front depending on vehicle length,
493 			 * so we need to move all vehicles forward to cover the difference to the
494 			 * old center, otherwise wagon spacing in trains would be broken upon load. */
495 			for (Train *u = Train::From(v); u != nullptr; u = u->Next()) {
496 				if (u->track == TRACK_BIT_DEPOT || (u->vehstatus & VS_CRASHED)) continue;
497 
498 				Train *next = u->Next();
499 
500 				/* Try to pull the vehicle half its length forward. */
501 				int diff = (VEHICLE_LENGTH - u->gcache.cached_veh_length) / 2;
502 				int done;
503 				for (done = 0; done < diff; done++) {
504 					if (!TrainController(u, next, false)) break;
505 				}
506 
507 				if (next != nullptr && done < diff && u->IsFrontEngine()) {
508 					/* Pulling the front vehicle forwards failed, we either encountered a dead-end
509 					 * or a red signal. To fix this, we try to move the whole train the required
510 					 * space backwards and re-do the fix up of the front vehicle. */
511 
512 					/* Ignore any signals when backtracking. */
513 					TrainForceProceeding old_tfp = u->force_proceed;
514 					u->force_proceed = TFP_SIGNAL;
515 
516 					/* Swap start<>end, start+1<>end-1, ... */
517 					int r = CountVehiclesInChain(u) - 1; // number of vehicles - 1
518 					int l = 0;
519 					do ReverseTrainSwapVeh(u, l++, r--); while (l <= r);
520 
521 					/* We moved the first vehicle which is now the last. Move it back to the
522 					 * original position as we will fix up the last vehicle later in the loop. */
523 					for (int i = 0; i < done; i++) TrainController(u->Last(), nullptr);
524 
525 					/* Move the train backwards to get space for the first vehicle. As the stopping
526 					 * distance from a line end is rounded up, move the train one unit more to cater
527 					 * for front vehicles with odd lengths. */
528 					int moved;
529 					for (moved = 0; moved < diff + 1; moved++) {
530 						if (!TrainController(u, nullptr, false)) break;
531 					}
532 
533 					/* Swap start<>end, start+1<>end-1, ... again. */
534 					r = CountVehiclesInChain(u) - 1; // number of vehicles - 1
535 					l = 0;
536 					do ReverseTrainSwapVeh(u, l++, r--); while (l <= r);
537 
538 					u->force_proceed = old_tfp;
539 
540 					/* Tracks are too short to fix the train length. The player has to fix the
541 					 * train in a depot. Bail out so we don't damage the vehicle chain any more. */
542 					if (moved < diff + 1) break;
543 
544 					/* Re-do the correction for the first vehicle. */
545 					for (done = 0; done < diff; done++) TrainController(u, next, false);
546 
547 					/* We moved one unit more backwards than needed for even-length front vehicles,
548 					 * try to move that unit forward again. We don't care if this step fails. */
549 					TrainController(u, nullptr, false);
550 				}
551 
552 				/* If the next wagon is still in a depot, check if it shouldn't be outside already. */
553 				if (next != nullptr && next->track == TRACK_BIT_DEPOT) {
554 					int d = TicksToLeaveDepot(u);
555 					if (d <= 0) {
556 						/* Next vehicle should have left the depot already, show it and pull forward. */
557 						next->vehstatus &= ~VS_HIDDEN;
558 						next->track = TrackToTrackBits(GetRailDepotTrack(next->tile));
559 						for (int i = 0; i >= d; i--) TrainController(next, nullptr);
560 					}
561 				}
562 			}
563 
564 			/* Update all cached properties after moving the vehicle chain around. */
565 			Train::From(v)->ConsistChanged(CCF_TRACK);
566 		}
567 	}
568 }
569 
570 static uint8  _cargo_days;
571 static uint16 _cargo_source;
572 static uint32 _cargo_source_xy;
573 static uint16 _cargo_count;
574 static uint16 _cargo_paid_for;
575 static Money  _cargo_feeder_share;
576 static uint32 _cargo_loaded_at_xy;
577 
578 class SlVehicleCommon : public DefaultSaveLoadHandler<SlVehicleCommon, Vehicle> {
579 public:
580 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
581 	/* This table access private members of other classes; they have this
582 	 * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for
583 	 * "inline static const", so we are forced to wrap the table in a
584 	 * function. CL 19.16 is the latest for VS2017. */
585 	inline static const SaveLoad description[] = {{}};
GetDescription() const586 	SaveLoadTable GetDescription() const override {
587 #else
588 	inline
589 #endif
590 	static const SaveLoad description[] = {
591 		    SLE_VAR(Vehicle, subtype,               SLE_UINT8),
592 
593 		    SLE_REF(Vehicle, next,                  REF_VEHICLE_OLD),
594 		SLE_CONDVAR(Vehicle, name,                  SLE_NAME,                     SL_MIN_VERSION,  SLV_84),
595 		SLE_CONDSSTR(Vehicle, name,                  SLE_STR | SLF_ALLOW_CONTROL,  SLV_84, SL_MAX_VERSION),
596 		SLE_CONDVAR(Vehicle, unitnumber,            SLE_FILE_U8  | SLE_VAR_U16,   SL_MIN_VERSION,   SLV_8),
597 		SLE_CONDVAR(Vehicle, unitnumber,            SLE_UINT16,                   SLV_8, SL_MAX_VERSION),
598 		    SLE_VAR(Vehicle, owner,                 SLE_UINT8),
599 		SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
600 		SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
601 		SLE_CONDVAR(Vehicle, dest_tile,             SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
602 		SLE_CONDVAR(Vehicle, dest_tile,             SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
603 
604 		SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
605 		SLE_CONDVAR(Vehicle, x_pos,                 SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
606 		SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
607 		SLE_CONDVAR(Vehicle, y_pos,                 SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
608 		SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   SL_MIN_VERSION, SLV_164),
609 		SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  SLV_164, SL_MAX_VERSION),
610 		    SLE_VAR(Vehicle, direction,             SLE_UINT8),
611 
612 		    SLE_VAR(Vehicle, spritenum,             SLE_UINT8),
613 		    SLE_VAR(Vehicle, engine_type,           SLE_UINT16),
614 		    SLE_VAR(Vehicle, cur_speed,             SLE_UINT16),
615 		    SLE_VAR(Vehicle, subspeed,              SLE_UINT8),
616 		    SLE_VAR(Vehicle, acceleration,          SLE_UINT8),
617 		SLE_CONDVAR(Vehicle, motion_counter,        SLE_UINT32,                   SLV_VEH_MOTION_COUNTER, SL_MAX_VERSION),
618 		    SLE_VAR(Vehicle, progress,              SLE_UINT8),
619 
620 		    SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
621 		SLE_CONDVAR(Vehicle, last_station_visited,  SLE_FILE_U8  | SLE_VAR_U16,   SL_MIN_VERSION,   SLV_5),
622 		SLE_CONDVAR(Vehicle, last_station_visited,  SLE_UINT16,                   SLV_5, SL_MAX_VERSION),
623 		SLE_CONDVAR(Vehicle, last_loading_station,  SLE_UINT16,                 SLV_182, SL_MAX_VERSION),
624 
625 		    SLE_VAR(Vehicle, cargo_type,            SLE_UINT8),
626 		SLE_CONDVAR(Vehicle, cargo_subtype,         SLE_UINT8,                   SLV_35, SL_MAX_VERSION),
627 		SLEG_CONDVAR("cargo_days", _cargo_days,     SLE_UINT8,                    SL_MIN_VERSION,  SLV_68),
628 		SLEG_CONDVAR("cargo_source", _cargo_source, SLE_FILE_U8  | SLE_VAR_U16,   SL_MIN_VERSION,   SLV_7),
629 		SLEG_CONDVAR("cargo_source", _cargo_source, SLE_UINT16,                   SLV_7,  SLV_68),
630 		SLEG_CONDVAR("cargo_source_xy", _cargo_source_xy, SLE_UINT32,             SLV_44,  SLV_68),
631 		    SLE_VAR(Vehicle, cargo_cap,             SLE_UINT16),
632 		SLE_CONDVAR(Vehicle, refit_cap,             SLE_UINT16,                 SLV_182, SL_MAX_VERSION),
633 		SLEG_CONDVAR("cargo_count", _cargo_count,   SLE_UINT16,                   SL_MIN_VERSION,  SLV_68),
634 		SLE_CONDREFLIST(Vehicle, cargo.packets,     REF_CARGO_PACKET,            SLV_68, SL_MAX_VERSION),
635 		SLE_CONDARR(Vehicle, cargo.action_counts,   SLE_UINT, VehicleCargoList::NUM_MOVE_TO_ACTION, SLV_181, SL_MAX_VERSION),
636 		SLE_CONDVAR(Vehicle, cargo_age_counter,     SLE_UINT16,                 SLV_162, SL_MAX_VERSION),
637 
638 		    SLE_VAR(Vehicle, day_counter,           SLE_UINT8),
639 		    SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
640 		SLE_CONDVAR(Vehicle, running_ticks,         SLE_UINT8,                   SLV_88, SL_MAX_VERSION),
641 
642 		    SLE_VAR(Vehicle, cur_implicit_order_index,  SLE_UINT8),
643 		SLE_CONDVAR(Vehicle, cur_real_order_index,  SLE_UINT8,                  SLV_158, SL_MAX_VERSION),
644 
645 		/* This next line is for version 4 and prior compatibility.. it temporarily reads
646 		type and flags (which were both 4 bits) into type. Later on this is
647 		converted correctly */
648 		SLE_CONDVAR(Vehicle, current_order.type,    SLE_UINT8,                    SL_MIN_VERSION,   SLV_5),
649 		SLE_CONDVAR(Vehicle, current_order.dest,    SLE_FILE_U8  | SLE_VAR_U16,   SL_MIN_VERSION,   SLV_5),
650 
651 		/* Orders for version 5 and on */
652 		SLE_CONDVAR(Vehicle, current_order.type,    SLE_UINT8,                    SLV_5, SL_MAX_VERSION),
653 		SLE_CONDVAR(Vehicle, current_order.flags,   SLE_UINT8,                    SLV_5, SL_MAX_VERSION),
654 		SLE_CONDVAR(Vehicle, current_order.dest,    SLE_UINT16,                   SLV_5, SL_MAX_VERSION),
655 
656 		/* Refit in current order */
657 		SLE_CONDVAR(Vehicle, current_order.refit_cargo,   SLE_UINT8,             SLV_36, SL_MAX_VERSION),
658 
659 		/* Timetable in current order */
660 		SLE_CONDVAR(Vehicle, current_order.wait_time,     SLE_UINT16,            SLV_67, SL_MAX_VERSION),
661 		SLE_CONDVAR(Vehicle, current_order.travel_time,   SLE_UINT16,            SLV_67, SL_MAX_VERSION),
662 		SLE_CONDVAR(Vehicle, current_order.max_speed,     SLE_UINT16,           SLV_174, SL_MAX_VERSION),
663 		SLE_CONDVAR(Vehicle, timetable_start,       SLE_INT32,                  SLV_129, SL_MAX_VERSION),
664 
665 		SLE_CONDREF(Vehicle, orders,                REF_ORDER,                    SL_MIN_VERSION, SLV_105),
666 		SLE_CONDREF(Vehicle, orders,                REF_ORDERLIST,              SLV_105, SL_MAX_VERSION),
667 
668 		SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
669 		SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   SLV_31, SL_MAX_VERSION),
670 		SLE_CONDVAR(Vehicle, max_age,               SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
671 		SLE_CONDVAR(Vehicle, max_age,               SLE_INT32,                   SLV_31, SL_MAX_VERSION),
672 		SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
673 		SLE_CONDVAR(Vehicle, date_of_last_service,  SLE_INT32,                   SLV_31, SL_MAX_VERSION),
674 		SLE_CONDVAR(Vehicle, service_interval,      SLE_UINT16,                   SL_MIN_VERSION,  SLV_31),
675 		SLE_CONDVAR(Vehicle, service_interval,      SLE_FILE_U32 | SLE_VAR_U16,  SLV_31, SLV_180),
676 		SLE_CONDVAR(Vehicle, service_interval,      SLE_UINT16,                 SLV_180, SL_MAX_VERSION),
677 		    SLE_VAR(Vehicle, reliability,           SLE_UINT16),
678 		    SLE_VAR(Vehicle, reliability_spd_dec,   SLE_UINT16),
679 		    SLE_VAR(Vehicle, breakdown_ctr,         SLE_UINT8),
680 		    SLE_VAR(Vehicle, breakdown_delay,       SLE_UINT8),
681 		    SLE_VAR(Vehicle, breakdowns_since_last_service, SLE_UINT8),
682 		    SLE_VAR(Vehicle, breakdown_chance,      SLE_UINT8),
683 		SLE_CONDVAR(Vehicle, build_year,            SLE_FILE_U8 | SLE_VAR_I32,    SL_MIN_VERSION,  SLV_31),
684 		SLE_CONDVAR(Vehicle, build_year,            SLE_INT32,                   SLV_31, SL_MAX_VERSION),
685 
686 		    SLE_VAR(Vehicle, load_unload_ticks,     SLE_UINT16),
687 		SLEG_CONDVAR("cargo_paid_for", _cargo_paid_for, SLE_UINT16,              SLV_45, SL_MAX_VERSION),
688 		SLE_CONDVAR(Vehicle, vehicle_flags,         SLE_FILE_U8 | SLE_VAR_U16,   SLV_40, SLV_180),
689 		SLE_CONDVAR(Vehicle, vehicle_flags,         SLE_UINT16,                 SLV_180, SL_MAX_VERSION),
690 
691 		SLE_CONDVAR(Vehicle, profit_this_year,      SLE_FILE_I32 | SLE_VAR_I64,   SL_MIN_VERSION,  SLV_65),
692 		SLE_CONDVAR(Vehicle, profit_this_year,      SLE_INT64,                   SLV_65, SL_MAX_VERSION),
693 		SLE_CONDVAR(Vehicle, profit_last_year,      SLE_FILE_I32 | SLE_VAR_I64,   SL_MIN_VERSION,  SLV_65),
694 		SLE_CONDVAR(Vehicle, profit_last_year,      SLE_INT64,                   SLV_65, SL_MAX_VERSION),
695 		SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_FILE_I32 | SLE_VAR_I64,  SLV_51,  SLV_65),
696 		SLEG_CONDVAR("cargo_feeder_share", _cargo_feeder_share, SLE_INT64,                   SLV_65,  SLV_68),
697 		SLEG_CONDVAR("cargo_loaded_at_xy", _cargo_loaded_at_xy, SLE_UINT32,                  SLV_51,  SLV_68),
698 		SLE_CONDVAR(Vehicle, value,                 SLE_FILE_I32 | SLE_VAR_I64,   SL_MIN_VERSION,  SLV_65),
699 		SLE_CONDVAR(Vehicle, value,                 SLE_INT64,                   SLV_65, SL_MAX_VERSION),
700 
701 		SLE_CONDVAR(Vehicle, random_bits,           SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
702 		SLE_CONDVAR(Vehicle, waiting_triggers,      SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
703 
704 		SLE_CONDREF(Vehicle, next_shared,           REF_VEHICLE,                  SLV_2, SL_MAX_VERSION),
705 		SLE_CONDVAR(Vehicle, group_id,              SLE_UINT16,                  SLV_60, SL_MAX_VERSION),
706 
707 		SLE_CONDVAR(Vehicle, current_order_time,    SLE_UINT32,                  SLV_67, SL_MAX_VERSION),
708 		SLE_CONDVAR(Vehicle, lateness_counter,      SLE_INT32,                   SLV_67, SL_MAX_VERSION),
709 	};
710 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
711 		return description;
712 	}
713 #endif
714 	inline const static SaveLoadCompatTable compat_description = _vehicle_common_sl_compat;
715 
Save(Vehicle * v) const716 	void Save(Vehicle *v) const override
717 	{
718 		SlObject(v, this->GetDescription());
719 	}
720 
Load(Vehicle * v) const721 	void Load(Vehicle *v) const override
722 	{
723 		SlObject(v, this->GetLoadDescription());
724 	}
725 
FixPointers(Vehicle * v) const726 	void FixPointers(Vehicle *v) const override
727 	{
728 		SlObject(v, this->GetDescription());
729 	}
730 };
731 
732 class SlVehicleTrain : public DefaultSaveLoadHandler<SlVehicleTrain, Vehicle> {
733 public:
734 	inline static const SaveLoad description[] = {
735 		 SLEG_STRUCT("common", SlVehicleCommon),
736 		     SLE_VAR(Train, crash_anim_pos,      SLE_UINT16),
737 		     SLE_VAR(Train, force_proceed,       SLE_UINT8),
738 		     SLE_VAR(Train, railtype,            SLE_UINT8),
739 		     SLE_VAR(Train, track,               SLE_UINT8),
740 
741 		 SLE_CONDVAR(Train, flags,               SLE_FILE_U8  | SLE_VAR_U16,   SLV_2,  SLV_100),
742 		 SLE_CONDVAR(Train, flags,               SLE_UINT16,                 SLV_100, SL_MAX_VERSION),
743 		 SLE_CONDVAR(Train, wait_counter,        SLE_UINT16,                 SLV_136, SL_MAX_VERSION),
744 		 SLE_CONDVAR(Train, gv_flags,            SLE_UINT16,                 SLV_139, SL_MAX_VERSION),
745 	};
746 	inline const static SaveLoadCompatTable compat_description = _vehicle_train_sl_compat;
747 
Save(Vehicle * v) const748 	void Save(Vehicle *v) const override
749 	{
750 		if (v->type != VEH_TRAIN) return;
751 		SlObject(v, this->GetDescription());
752 	}
753 
Load(Vehicle * v) const754 	void Load(Vehicle *v) const override
755 	{
756 		if (v->type != VEH_TRAIN) return;
757 		SlObject(v, this->GetLoadDescription());
758 	}
759 
FixPointers(Vehicle * v) const760 	void FixPointers(Vehicle *v) const override
761 	{
762 		if (v->type != VEH_TRAIN) return;
763 		SlObject(v, this->GetDescription());
764 	}
765 };
766 
767 class SlVehicleRoadVeh : public DefaultSaveLoadHandler<SlVehicleRoadVeh, Vehicle> {
768 public:
769 	inline static const SaveLoad description[] = {
770 		  SLEG_STRUCT("common", SlVehicleCommon),
771 		      SLE_VAR(RoadVehicle, state,                SLE_UINT8),
772 		      SLE_VAR(RoadVehicle, frame,                SLE_UINT8),
773 		      SLE_VAR(RoadVehicle, blocked_ctr,          SLE_UINT16),
774 		      SLE_VAR(RoadVehicle, overtaking,           SLE_UINT8),
775 		      SLE_VAR(RoadVehicle, overtaking_ctr,       SLE_UINT8),
776 		      SLE_VAR(RoadVehicle, crashed_ctr,          SLE_UINT16),
777 		      SLE_VAR(RoadVehicle, reverse_ctr,          SLE_UINT8),
778 		SLE_CONDDEQUE(RoadVehicle, path.td,              SLE_UINT8,                  SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION),
779 		SLE_CONDDEQUE(RoadVehicle, path.tile,            SLE_UINT32,                 SLV_ROADVEH_PATH_CACHE, SL_MAX_VERSION),
780 		  SLE_CONDVAR(RoadVehicle, gv_flags,             SLE_UINT16,                 SLV_139, SL_MAX_VERSION),
781 	};
782 	inline const static SaveLoadCompatTable compat_description = _vehicle_roadveh_sl_compat;
783 
Save(Vehicle * v) const784 	void Save(Vehicle *v) const override
785 	{
786 		if (v->type != VEH_ROAD) return;
787 		SlObject(v, this->GetDescription());
788 	}
789 
Load(Vehicle * v) const790 	void Load(Vehicle *v) const override
791 	{
792 		if (v->type != VEH_ROAD) return;
793 		SlObject(v, this->GetLoadDescription());
794 	}
795 
FixPointers(Vehicle * v) const796 	void FixPointers(Vehicle *v) const override
797 	{
798 		if (v->type != VEH_ROAD) return;
799 		SlObject(v, this->GetDescription());
800 	}
801 };
802 
803 class SlVehicleShip : public DefaultSaveLoadHandler<SlVehicleShip, Vehicle> {
804 public:
805 	inline static const SaveLoad description[] = {
806 		  SLEG_STRUCT("common", SlVehicleCommon),
807 		      SLE_VAR(Ship, state,                     SLE_UINT8),
808 		SLE_CONDDEQUE(Ship, path,                      SLE_UINT8,                  SLV_SHIP_PATH_CACHE, SL_MAX_VERSION),
809 		  SLE_CONDVAR(Ship, rotation,                  SLE_UINT8,                  SLV_SHIP_ROTATION, SL_MAX_VERSION),
810 	};
811 	inline const static SaveLoadCompatTable compat_description = _vehicle_ship_sl_compat;
812 
Save(Vehicle * v) const813 	void Save(Vehicle *v) const override
814 	{
815 		if (v->type != VEH_SHIP) return;
816 		SlObject(v, this->GetDescription());
817 	}
818 
Load(Vehicle * v) const819 	void Load(Vehicle *v) const override
820 	{
821 		if (v->type != VEH_SHIP) return;
822 		SlObject(v, this->GetLoadDescription());
823 	}
824 
FixPointers(Vehicle * v) const825 	void FixPointers(Vehicle *v) const override
826 	{
827 		if (v->type != VEH_SHIP) return;
828 		SlObject(v, this->GetDescription());
829 	}
830 };
831 
832 class SlVehicleAircraft : public DefaultSaveLoadHandler<SlVehicleAircraft, Vehicle> {
833 public:
834 	inline static const SaveLoad description[] = {
835 		 SLEG_STRUCT("common", SlVehicleCommon),
836 		     SLE_VAR(Aircraft, crashed_counter,       SLE_UINT16),
837 		     SLE_VAR(Aircraft, pos,                   SLE_UINT8),
838 
839 		 SLE_CONDVAR(Aircraft, targetairport,         SLE_FILE_U8  | SLE_VAR_U16,   SL_MIN_VERSION, SLV_5),
840 		 SLE_CONDVAR(Aircraft, targetairport,         SLE_UINT16,                   SLV_5, SL_MAX_VERSION),
841 
842 		     SLE_VAR(Aircraft, state,                 SLE_UINT8),
843 
844 		 SLE_CONDVAR(Aircraft, previous_pos,          SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
845 		 SLE_CONDVAR(Aircraft, last_direction,        SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
846 		 SLE_CONDVAR(Aircraft, number_consecutive_turns, SLE_UINT8,                 SLV_2, SL_MAX_VERSION),
847 
848 		 SLE_CONDVAR(Aircraft, turn_counter,          SLE_UINT8,                  SLV_136, SL_MAX_VERSION),
849 		 SLE_CONDVAR(Aircraft, flags,                 SLE_UINT8,                  SLV_167, SL_MAX_VERSION),
850 	};
851 	inline const static SaveLoadCompatTable compat_description = _vehicle_aircraft_sl_compat;
852 
Save(Vehicle * v) const853 	void Save(Vehicle *v) const override
854 	{
855 		if (v->type != VEH_AIRCRAFT) return;
856 		SlObject(v, this->GetDescription());
857 	}
858 
Load(Vehicle * v) const859 	void Load(Vehicle *v) const override
860 	{
861 		if (v->type != VEH_AIRCRAFT) return;
862 		SlObject(v, this->GetLoadDescription());
863 	}
864 
FixPointers(Vehicle * v) const865 	void FixPointers(Vehicle *v) const override
866 	{
867 		if (v->type != VEH_AIRCRAFT) return;
868 		SlObject(v, this->GetDescription());
869 	}
870 };
871 
872 class SlVehicleEffect : public DefaultSaveLoadHandler<SlVehicleEffect, Vehicle> {
873 public:
874 	inline static const SaveLoad description[] = {
875 		     SLE_VAR(Vehicle, subtype,               SLE_UINT8),
876 
877 		 SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
878 		 SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
879 
880 		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
881 		 SLE_CONDVAR(Vehicle, x_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
882 		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
883 		 SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
884 		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   SL_MIN_VERSION, SLV_164),
885 		 SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  SLV_164, SL_MAX_VERSION),
886 
887 		     SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
888 		     SLE_VAR(Vehicle, progress,              SLE_UINT8),
889 		     SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
890 
891 		     SLE_VAR(EffectVehicle, animation_state,    SLE_UINT16),
892 		     SLE_VAR(EffectVehicle, animation_substate, SLE_UINT8),
893 
894 		 SLE_CONDVAR(Vehicle, spritenum,             SLE_UINT8,                    SLV_2, SL_MAX_VERSION),
895 	};
896 	inline const static SaveLoadCompatTable compat_description = _vehicle_effect_sl_compat;
897 
Save(Vehicle * v) const898 	void Save(Vehicle *v) const override
899 	{
900 		if (v->type != VEH_EFFECT) return;
901 		SlObject(v, this->GetDescription());
902 	}
903 
Load(Vehicle * v) const904 	void Load(Vehicle *v) const override
905 	{
906 		if (v->type != VEH_EFFECT) return;
907 		SlObject(v, this->GetLoadDescription());
908 	}
909 
FixPointers(Vehicle * v) const910 	void FixPointers(Vehicle *v) const override
911 	{
912 		if (v->type != VEH_EFFECT) return;
913 		SlObject(v, this->GetDescription());
914 	}
915 };
916 
917 class SlVehicleDisaster : public DefaultSaveLoadHandler<SlVehicleDisaster, Vehicle> {
918 public:
919 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
920 	/* This table access private members of other classes; they have this
921 	 * class as friend. For MSVC CL 19.15 and 19.16 this doesn't work for
922 	 * "inline static const", so we are forced to wrap the table in a
923 	 * function. CL 19.16 is the latest for VS2017. */
924 	inline static const SaveLoad description[] = {{}};
GetDescription() const925 	SaveLoadTable GetDescription() const override {
926 #else
927 	inline
928 #endif
929 	static const SaveLoad description[] = {
930 		    SLE_REF(Vehicle, next,                  REF_VEHICLE_OLD),
931 
932 		    SLE_VAR(Vehicle, subtype,               SLE_UINT8),
933 		SLE_CONDVAR(Vehicle, tile,                  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
934 		SLE_CONDVAR(Vehicle, tile,                  SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
935 		SLE_CONDVAR(Vehicle, dest_tile,             SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION,   SLV_6),
936 		SLE_CONDVAR(Vehicle, dest_tile,             SLE_UINT32,                   SLV_6, SL_MAX_VERSION),
937 
938 		SLE_CONDVAR(Vehicle, x_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
939 		SLE_CONDVAR(Vehicle, x_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
940 		SLE_CONDVAR(Vehicle, y_pos,                 SLE_FILE_I16 | SLE_VAR_I32,   SL_MIN_VERSION,   SLV_6),
941 		SLE_CONDVAR(Vehicle, y_pos,                 SLE_INT32,                    SLV_6, SL_MAX_VERSION),
942 		SLE_CONDVAR(Vehicle, z_pos,                 SLE_FILE_U8  | SLE_VAR_I32,   SL_MIN_VERSION, SLV_164),
943 		SLE_CONDVAR(Vehicle, z_pos,                 SLE_INT32,                  SLV_164, SL_MAX_VERSION),
944 		    SLE_VAR(Vehicle, direction,             SLE_UINT8),
945 
946 		    SLE_VAR(Vehicle, owner,                 SLE_UINT8),
947 		    SLE_VAR(Vehicle, vehstatus,             SLE_UINT8),
948 		SLE_CONDVAR(Vehicle, current_order.dest,    SLE_FILE_U8 | SLE_VAR_U16,    SL_MIN_VERSION,   SLV_5),
949 		SLE_CONDVAR(Vehicle, current_order.dest,    SLE_UINT16,                   SLV_5, SL_MAX_VERSION),
950 
951 		    SLE_VAR(Vehicle, sprite_cache.sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32),
952 		SLE_CONDVAR(Vehicle, age,                   SLE_FILE_U16 | SLE_VAR_I32,   SL_MIN_VERSION,  SLV_31),
953 		SLE_CONDVAR(Vehicle, age,                   SLE_INT32,                   SLV_31, SL_MAX_VERSION),
954 		    SLE_VAR(Vehicle, tick_counter,          SLE_UINT8),
955 
956 		SLE_CONDVAR(DisasterVehicle, image_override,            SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION, SLV_191),
957 		SLE_CONDVAR(DisasterVehicle, image_override,            SLE_UINT32,                 SLV_191, SL_MAX_VERSION),
958 		SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target,  SLE_FILE_U16 | SLE_VAR_U32,   SL_MIN_VERSION, SLV_191),
959 		SLE_CONDVAR(DisasterVehicle, big_ufo_destroyer_target,  SLE_UINT32,                 SLV_191, SL_MAX_VERSION),
960 		SLE_CONDVAR(DisasterVehicle, flags,                     SLE_UINT8,                  SLV_194, SL_MAX_VERSION),
961 	};
962 #if defined(_MSC_VER) && (_MSC_VER == 1915 || _MSC_VER == 1916)
963 		return description;
964 	}
965 #endif
966 	inline const static SaveLoadCompatTable compat_description = _vehicle_disaster_sl_compat;
967 
Save(Vehicle * v) const968 	void Save(Vehicle *v) const override
969 	{
970 		if (v->type != VEH_DISASTER) return;
971 		SlObject(v, this->GetDescription());
972 	}
973 
Load(Vehicle * v) const974 	void Load(Vehicle *v) const override
975 	{
976 		if (v->type != VEH_DISASTER) return;
977 		SlObject(v, this->GetLoadDescription());
978 	}
979 
FixPointers(Vehicle * v) const980 	void FixPointers(Vehicle *v) const override
981 	{
982 		if (v->type != VEH_DISASTER) return;
983 		SlObject(v, this->GetDescription());
984 	}
985 };
986 
987 const static SaveLoad _vehicle_desc[] = {
988 	SLE_SAVEBYTE(Vehicle, type),
989 	SLEG_STRUCT("train", SlVehicleTrain),
990 	SLEG_STRUCT("roadveh", SlVehicleRoadVeh),
991 	SLEG_STRUCT("ship", SlVehicleShip),
992 	SLEG_STRUCT("aircraft", SlVehicleAircraft),
993 	SLEG_STRUCT("effect", SlVehicleEffect),
994 	SLEG_STRUCT("disaster", SlVehicleDisaster),
995 };
996 
997 struct VEHSChunkHandler : ChunkHandler {
VEHSChunkHandlerVEHSChunkHandler998 	VEHSChunkHandler() : ChunkHandler('VEHS', CH_SPARSE_TABLE) {}
999 
SaveVEHSChunkHandler1000 	void Save() const override
1001 	{
1002 		SlTableHeader(_vehicle_desc);
1003 
1004 		/* Write the vehicles */
1005 		for (Vehicle *v : Vehicle::Iterate()) {
1006 			SlSetArrayIndex(v->index);
1007 			SlObject(v, _vehicle_desc);
1008 		}
1009 	}
1010 
LoadVEHSChunkHandler1011 	void Load() const override
1012 	{
1013 		const std::vector<SaveLoad> slt = SlCompatTableHeader(_vehicle_desc, _vehicle_sl_compat);
1014 
1015 		int index;
1016 
1017 		_cargo_count = 0;
1018 
1019 		while ((index = SlIterateArray()) != -1) {
1020 			Vehicle *v;
1021 			VehicleType vtype = (VehicleType)SlReadByte();
1022 
1023 			switch (vtype) {
1024 				case VEH_TRAIN:    v = new (index) Train();           break;
1025 				case VEH_ROAD:     v = new (index) RoadVehicle();     break;
1026 				case VEH_SHIP:     v = new (index) Ship();            break;
1027 				case VEH_AIRCRAFT: v = new (index) Aircraft();        break;
1028 				case VEH_EFFECT:   v = new (index) EffectVehicle();   break;
1029 				case VEH_DISASTER: v = new (index) DisasterVehicle(); break;
1030 				case VEH_INVALID: // Savegame shouldn't contain invalid vehicles
1031 				default: SlErrorCorrupt("Invalid vehicle type");
1032 			}
1033 
1034 			SlObject(v, slt);
1035 
1036 			if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) {
1037 				/* Don't construct the packet with station here, because that'll fail with old savegames */
1038 				CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_days, _cargo_source, _cargo_source_xy, _cargo_loaded_at_xy, _cargo_feeder_share);
1039 				v->cargo.Append(cp);
1040 			}
1041 
1042 			/* Old savegames used 'last_station_visited = 0xFF' */
1043 			if (IsSavegameVersionBefore(SLV_5) && v->last_station_visited == 0xFF) {
1044 				v->last_station_visited = INVALID_STATION;
1045 			}
1046 
1047 			if (IsSavegameVersionBefore(SLV_182)) v->last_loading_station = INVALID_STATION;
1048 
1049 			if (IsSavegameVersionBefore(SLV_5)) {
1050 				/* Convert the current_order.type (which is a mix of type and flags, because
1051 				 *  in those versions, they both were 4 bits big) to type and flags */
1052 				v->current_order.flags = GB(v->current_order.type, 4, 4);
1053 				v->current_order.type &= 0x0F;
1054 			}
1055 
1056 			/* Advanced vehicle lists got added */
1057 			if (IsSavegameVersionBefore(SLV_60)) v->group_id = DEFAULT_GROUP;
1058 		}
1059 	}
1060 
FixPointersVEHSChunkHandler1061 	void FixPointers() const override
1062 	{
1063 		for (Vehicle *v : Vehicle::Iterate()) {
1064 			SlObject(v, _vehicle_desc);
1065 		}
1066 	}
1067 };
1068 
1069 static const VEHSChunkHandler VEHS;
1070 static const ChunkHandlerRef veh_chunk_handlers[] = {
1071 	VEHS,
1072 };
1073 
1074 extern const ChunkHandlerTable _veh_chunk_handlers(veh_chunk_handlers);
1075