OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

vehicle_base.h
Go to the documentation of this file.
1 /* $Id: vehicle_base.h 27668 2016-10-16 14:59:44Z frosch $ */
2
3 /*
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/>.
8 */
9
12 #ifndef VEHICLE_BASE_H
13 #define VEHICLE_BASE_H
14
15 #include "core/smallmap_type.hpp"
16 #include "track_type.h"
17 #include "command_type.h"
18 #include "order_base.h"
19 #include "cargopacket.h"
20 #include "texteff.hpp"
21 #include "engine_type.h"
22 #include "order_func.h"
23 #include "transport_type.h"
24 #include "group_type.h"
25 #include "base_consist.h"
26 #include "network/network.h"
27 #include <list>
28 #include <map>
29
31 enum VehStatus {
32 VS_HIDDEN = 0x01,
33 VS_STOPPED = 0x02,
34 VS_UNCLICKABLE = 0x04,
35 VS_DEFPAL = 0x08,
36 VS_TRAIN_SLOWING = 0x10,
37 VS_SHADOW = 0x20,
38 VS_AIRCRAFT_BROKEN = 0x40,
39 VS_CRASHED = 0x80,
40 };
41
43 enum VehicleFlags {
44 VF_LOADING_FINISHED,
45 VF_CARGO_UNLOADING,
46 VF_BUILT_AS_PROTOTYPE,
47 VF_TIMETABLE_STARTED,
48 VF_AUTOFILL_TIMETABLE,
49 VF_AUTOFILL_PRES_WAIT_TIME,
50 VF_STOP_LOADING,
51 VF_PATHFINDER_LOST,
52 VF_SERVINT_IS_CUSTOM,
53 VF_SERVINT_IS_PERCENT,
54 };
55
57 enum NewGRFCacheValidValues {
58 NCVV_POSITION_CONSIST_LENGTH = 0,
59 NCVV_POSITION_SAME_ID_LENGTH = 1,
60 NCVV_CONSIST_CARGO_INFORMATION = 2,
61 NCVV_COMPANY_INFORMATION = 3,
62 NCVV_POSITION_IN_VEHICLE = 4,
63 NCVV_END,
64 };
65
67 struct NewGRFCache {
68 /* Values calculated when they are requested for the first time after invalidating the NewGRF cache. */
69 uint32 position_consist_length;
70 uint32 position_same_id_length;
71 uint32 consist_cargo_information;
72 uint32 company_information;
73 uint32 position_in_vehicle;
74 uint8 cache_valid;
75 };
76
78 enum VisualEffect {
79 VE_OFFSET_START = 0,
80 VE_OFFSET_COUNT = 4,
81 VE_OFFSET_CENTRE = 8,
82
83 VE_TYPE_START = 4,
84 VE_TYPE_COUNT = 2,
85 VE_TYPE_DEFAULT = 0,
86 VE_TYPE_STEAM = 1,
87 VE_TYPE_DIESEL = 2,
88 VE_TYPE_ELECTRIC = 3,
89
90 VE_DISABLE_EFFECT = 6,
91 VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT,
92 VE_DISABLE_WAGON_POWER = 7,
93
94 VE_DEFAULT = 0xFF,
95 };
96
98 enum VisualEffectSpawnModel {
99 VESM_NONE = 0,
100 VESM_STEAM,
101 VESM_DIESEL,
102 VESM_ELECTRIC,
103
104 VESM_END
105 };
106
112 enum GroundVehicleSubtypeFlags {
113 GVSF_FRONT = 0,
114 GVSF_ARTICULATED_PART = 1,
115 GVSF_WAGON = 2,
116 GVSF_ENGINE = 3,
117 GVSF_FREE_WAGON = 4,
118 GVSF_MULTIHEADED = 5,
119 };
120
122 struct VehicleCache {
123 uint16 cached_max_speed;
124 uint16 cached_cargo_age_period;
125
126 byte cached_vis_effect;
127 };
128
130 struct VehicleSpriteSeq {
131 PalSpriteID seq[4];
132 uint count;
133
134 bool operator==(const VehicleSpriteSeq &other) const
135 {
136 return this->count == other.count && MemCmpT<PalSpriteID>(this->seq, other.seq, this->count) == 0;
137 }
138
139 bool operator!=(const VehicleSpriteSeq &other) const
140 {
141 return !this->operator==(other);
142 }
143
147 bool IsValid() const
148 {
149 return this->count != 0;
150 }
151
155 void Clear()
156 {
157 this->count = 0;
158 }
159
163 void Set(SpriteID sprite)
164 {
165 this->count = 1;
166 this->seq[0].sprite = sprite;
167 this->seq[0].pal = 0;
168 }
169
173 void CopyWithoutPalette(const VehicleSpriteSeq &src)
174 {
175 this->count = src.count;
176 for (uint i = 0; i < src.count; ++i) {
177 this->seq[i].sprite = src.seq[i].sprite;
178 this->seq[i].pal = 0;
179 }
180 }
181
182 void GetBounds(Rect *bounds) const;
183 void Draw(int x, int y, PaletteID default_pal, bool force_pal) const;
184 };
185
187 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
188 extern VehiclePool _vehicle_pool;
189
190 /* Some declarations of functions, so we can make them friendly */
191 struct SaveLoad;
192 struct GroundVehicleCache;
193 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
194 struct LoadgameState;
195 extern bool LoadOldVehicle(LoadgameState *ls, int num);
196 extern void FixOldVehicles();
197
198 struct GRFFile;
199
203 struct RefitDesc {
204 CargoID cargo;
205 uint16 capacity;
206 uint16 remaining;
207 RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) :
208 cargo(cargo), capacity(capacity), remaining(remaining) {}
209 };
210
212 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
213 private:
214 typedef std::list<RefitDesc> RefitList;
215 typedef std::map<CargoID, uint> CapacitiesMap;
216
217 Vehicle *next;
218 Vehicle *previous;
219 Vehicle *first;
220
221 Vehicle *next_shared;
222 Vehicle *previous_shared;
223
224 public:
225 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
226 friend void FixOldVehicles();
227 friend void AfterLoadVehicles(bool part_of_load);
228 friend bool LoadOldVehicle(LoadgameState *ls, int num);
229
230 TileIndex tile;
231
237 TileIndex dest_tile;
238
239 Money profit_this_year;
240 Money profit_last_year;
241 Money value;
242
243 CargoPayment *cargo_payment;
244
245 Rect coord;
246
247 Vehicle *hash_viewport_next;
248 Vehicle **hash_viewport_prev;
249
250 Vehicle *hash_tile_next;
251 Vehicle **hash_tile_prev;
252 Vehicle **hash_tile_current;
253
254 SpriteID colourmap;
255
256 /* Related to age and service time */
257 Year build_year;
258 Date age;
259 Date max_age;
260 Date date_of_last_service;
261 uint16 reliability;
262 uint16 reliability_spd_dec;
263 byte breakdown_ctr;
264 byte breakdown_delay;
265 byte breakdowns_since_last_service;
266 byte breakdown_chance;
267
268 int32 x_pos;
269 int32 y_pos;
270 int32 z_pos;
271 DirectionByte direction;
272
273 OwnerByte owner;
274
279 byte spritenum;
280 VehicleSpriteSeq sprite_seq;
281 byte x_extent;
282 byte y_extent;
283 byte z_extent;
284 int8 x_bb_offs;
285 int8 y_bb_offs;
286 int8 x_offs;
287 int8 y_offs;
288 EngineID engine_type;
289
290 TextEffectID fill_percent_te_id;
291 UnitID unitnumber;
292
293 uint16 cur_speed;
294 byte subspeed;
295 byte acceleration;
296 uint32 motion_counter;
297 byte progress;
298
299 byte random_bits;
300 byte waiting_triggers;
301
302 StationID last_station_visited;
303 StationID last_loading_station;
304
305 CargoID cargo_type;
306 byte cargo_subtype;
307 uint16 cargo_cap;
308 uint16 refit_cap;
309 VehicleCargoList cargo;
310 uint16 cargo_age_counter;
311
312 byte day_counter;
313 byte tick_counter;
314 byte running_ticks;
315
316 byte vehstatus;
317 Order current_order;
318
319 union {
320 OrderList *list;
321 Order *old;
322 } orders;
323
324 uint16 load_unload_ticks;
325 GroupID group_id;
326 byte subtype;
327
328 NewGRFCache grf_cache;
329 VehicleCache vcache;
330
331 Vehicle(VehicleType type = VEH_INVALID);
332
333 void PreDestructor();
335 virtual ~Vehicle();
336
337 void BeginLoading();
338 void CancelReservation(StationID next, Station *st);
339 void LeaveStation();
340
341 GroundVehicleCache *GetGroundVehicleCache();
342 const GroundVehicleCache *GetGroundVehicleCache() const;
343
344 uint16 &GetGroundVehicleFlags();
345 const uint16 &GetGroundVehicleFlags() const;
346
347 void DeleteUnreachedImplicitOrders();
348
349 void HandleLoading(bool mode = false);
350
351 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
352
353 uint GetConsistTotalCapacity() const;
354
363 virtual void MarkDirty() {}
364
370 virtual void UpdateDeltaXY(Direction direction) {}
371
385 inline uint GetOldAdvanceSpeed(uint speed)
386 {
387 return (this->direction & 1) ? speed : speed * 3 / 4;
388 }
389
402 static inline uint GetAdvanceSpeed(uint speed)
403 {
404 return speed * 3 / 4;
405 }
406
414 inline uint GetAdvanceDistance()
415 {
416 return (this->direction & 1) ? 192 : 256;
417 }
418
423 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
424
428 virtual void PlayLeaveStationSound() const {}
429
433 virtual bool IsPrimaryVehicle() const { return false; }
434
435 const Engine *GetEngine() const;
436
442 virtual void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { result->Clear(); }
443
444 const GRFFile *GetGRF() const;
445 uint32 GetGRFID() const;
446
451 inline void InvalidateNewGRFCache()
452 {
453 this->grf_cache.cache_valid = 0;
454 }
455
460 inline void InvalidateNewGRFCacheOfChain()
461 {
462 for (Vehicle *u = this; u != NULL; u = u->Next()) {
463 u->InvalidateNewGRFCache();
464 }
465 }
466
471 inline bool IsGroundVehicle() const
472 {
473 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
474 }
475
480 virtual int GetDisplaySpeed() const { return 0; }
481
486 virtual int GetDisplayMaxSpeed() const { return 0; }
487
492 virtual int GetCurrentMaxSpeed() const { return 0; }
493
498 virtual Money GetRunningCost() const { return 0; }
499
504 virtual bool IsInDepot() const { return false; }
505
510 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
511
516 bool IsStoppedInDepot() const
517 {
518 assert(this == this->First());
519 /* Free wagons have no VS_STOPPED state */
520 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
521 return this->IsChainInDepot();
522 }
523
528 virtual bool Tick() { return true; };
529
533 virtual void OnNewDay() {};
534
540 virtual uint Crash(bool flooded = false);
541
554 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
555
560 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
561
566 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
567
572 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
573
574 void SetNext(Vehicle *next);
575
581 inline Vehicle *Next() const { return this->next; }
582
588 inline Vehicle *Previous() const { return this->previous; }
589
594 inline Vehicle *First() const { return this->first; }
595
600 inline Vehicle *Last()
601 {
602 Vehicle *v = this;
603 while (v->Next() != NULL) v = v->Next();
604 return v;
605 }
606
611 inline const Vehicle *Last() const
612 {
613 const Vehicle *v = this;
614 while (v->Next() != NULL) v = v->Next();
615 return v;
616 }
617
623 inline Vehicle *Move(int n)
624 {
625 Vehicle *v = this;
626 if (n < 0) {
627 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
628 } else {
629 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
630 }
631 return v;
632 }
633
639 inline const Vehicle *Move(int n) const
640 {
641 const Vehicle *v = this;
642 if (n < 0) {
643 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
644 } else {
645 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
646 }
647 return v;
648 }
649
654 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
655
656 void AddToShared(Vehicle *shared_chain);
657 void RemoveFromShared();
658
663 inline Vehicle *NextShared() const { return this->next_shared; }
664
669 inline Vehicle *PreviousShared() const { return this->previous_shared; }
670
675 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
676
681 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
682
687 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
688
693 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
694
699 inline StationIDStack GetNextStoppingStation() const
700 {
701 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
702 }
703
704 void ResetRefitCaps();
705
712 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
713 {
714 this->CopyConsistPropertiesFrom(src);
715
716 this->unitnumber = src->unitnumber;
717
718 this->current_order = src->current_order;
719 this->dest_tile = src->dest_tile;
720
721 this->profit_this_year = src->profit_this_year;
722 this->profit_last_year = src->profit_last_year;
723 }
724
725
726 bool HandleBreakdown();
727
728 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
729
730 bool NeedsServicing() const;
731 bool NeedsAutomaticServicing() const;
732
740 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
741
750 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
751
752 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
753
754 void UpdateVisualEffect(bool allow_power_change = true);
755 void ShowVisualEffect() const;
756
757 void UpdatePosition();
758 void UpdateViewport(bool dirty);
759 void UpdatePositionAndViewport();
760 void MarkAllViewportsDirty() const;
761
762 inline uint16 GetServiceInterval() const { return this->service_interval; }
763
764 inline void SetServiceInterval(uint16 interval) { this->service_interval = interval; }
765
766 inline bool ServiceIntervalIsCustom() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); }
767
768 inline bool ServiceIntervalIsPercent() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); }
769
770 inline void SetServiceIntervalIsCustom(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_CUSTOM, 1, on); }
771
772 inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); }
773
774 private:
779 void SkipToNextRealOrderIndex()
780 {
781 if (this->GetNumManualOrders() > 0) {
782 /* Advance to next real order */
783 do {
784 this->cur_real_order_index++;
785 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
786 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
787 } else {
788 this->cur_real_order_index = 0;
789 }
790 }
791
792 public:
798 void IncrementImplicitOrderIndex()
799 {
800 if (this->cur_implicit_order_index == this->cur_real_order_index) {
801 /* Increment real order index as well */
802 this->SkipToNextRealOrderIndex();
803 }
804
805 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
806
807 /* Advance to next implicit order */
808 do {
809 this->cur_implicit_order_index++;
810 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
811 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
812
813 InvalidateVehicleOrder(this, 0);
814 }
815
822 void IncrementRealOrderIndex()
823 {
824 if (this->cur_implicit_order_index == this->cur_real_order_index) {
825 /* Increment both real and implicit order */
826 this->IncrementImplicitOrderIndex();
827 } else {
828 /* Increment real order only */
829 this->SkipToNextRealOrderIndex();
830 InvalidateVehicleOrder(this, 0);
831 }
832 }
833
837 void UpdateRealOrderIndex()
838 {
839 /* Make sure the index is valid */
840 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
841
842 if (this->GetNumManualOrders() > 0) {
843 /* Advance to next real order */
844 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
845 this->cur_real_order_index++;
846 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
847 }
848 } else {
849 this->cur_real_order_index = 0;
850 }
851 }
852
858 inline Order *GetOrder(int index) const
859 {
860 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
861 }
862
867 inline Order *GetLastOrder() const
868 {
869 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
870 }
871
872 bool IsEngineCountable() const;
873 bool HasEngineType() const;
874 bool HasDepotOrder() const;
875 void HandlePathfindingResult(bool path_found);
876
881 inline bool IsFrontEngine() const
882 {
883 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
884 }
885
890 inline bool IsArticulatedPart() const
891 {
892 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
893 }
894
899 inline bool HasArticulatedPart() const
900 {
901 return this->Next() != NULL && this->Next()->IsArticulatedPart();
902 }
903
909 inline Vehicle *GetNextArticulatedPart() const
910 {
911 assert(this->HasArticulatedPart());
912 return this->Next();
913 }
914
919 inline Vehicle *GetFirstEnginePart()
920 {
921 Vehicle *v = this;
922 while (v->IsArticulatedPart()) v = v->Previous();
923 return v;
924 }
925
930 inline const Vehicle *GetFirstEnginePart() const
931 {
932 const Vehicle *v = this;
933 while (v->IsArticulatedPart()) v = v->Previous();
934 return v;
935 }
936
941 inline Vehicle *GetLastEnginePart()
942 {
943 Vehicle *v = this;
944 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
945 return v;
946 }
947
952 inline Vehicle *GetNextVehicle() const
953 {
954 const Vehicle *v = this;
955 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
956
957 /* v now contains the last articulated part in the engine */
958 return v->Next();
959 }
960
965 inline Vehicle *GetPrevVehicle() const
966 {
967 Vehicle *v = this->Previous();
968 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
969
970 return v;
971 }
972 };
973
979 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
980
985 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
986
991 template <class T, VehicleType Type>
992 struct SpecializedVehicle : public Vehicle {
993 static const VehicleType EXPECTED_TYPE = Type;
994
995 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
996
1000 inline SpecializedVehicle<T, Type>() : Vehicle(Type)
1001 {
1002 this->sprite_seq.count = 1;
1003 }
1004
1009 inline T *First() const { return (T *)this->Vehicle::First(); }
1010
1015 inline T *Last() { return (T *)this->Vehicle::Last(); }
1016
1021 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
1022
1027 inline T *Next() const { return (T *)this->Vehicle::Next(); }
1028
1033 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
1034
1040 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
1041
1047 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
1048
1053 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
1054
1059 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
1060
1065 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
1066
1071 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
1072
1077 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
1078
1084 static inline bool IsValidID(size_t index)
1085 {
1086 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
1087 }
1088
1093 static inline T *Get(size_t index)
1094 {
1095 return (T *)Vehicle::Get(index);
1096 }
1097
1102 static inline T *GetIfValid(size_t index)
1103 {
1104 return IsValidID(index) ? Get(index) : NULL;
1105 }
1106
1112 static inline T *From(Vehicle *v)
1113 {
1114 assert(v->type == Type);
1115 return (T *)v;
1116 }
1117
1123 static inline const T *From(const Vehicle *v)
1124 {
1125 assert(v->type == Type);
1126 return (const T *)v;
1127 }
1128
1134 inline void UpdateViewport(bool force_update, bool update_delta)
1135 {
1136 /* Skip updating sprites on dedicated servers without screen */
1137 if (_network_dedicated) return;
1138
1139 /* Explicitly choose method to call to prevent vtable dereference -
1140 * it gives ~3% runtime improvements in games with many vehicles */
1141 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
1142 VehicleSpriteSeq seq;
1143 ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP, &seq);
1144 if (force_update || this->sprite_seq != seq) {
1145 this->sprite_seq = seq;
1146 this->Vehicle::UpdateViewport(true);
1147 }
1148 }
1149 };
1150
1156 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
1157
1159 struct FreeUnitIDGenerator {
1160 bool *cache;
1161 UnitID maxid;
1162 UnitID curid;
1163
1164 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
1165 UnitID NextID();
1166
1168 ~FreeUnitIDGenerator() { free(this->cache); }
1169 };
1170
1172 static const int32 INVALID_COORD = 0x7fffffff;
1173
1174 #endif /* VEHICLE_BASE_H */