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 26864 2014-09-20 15:46:44Z rubidium $ */
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 <list>
27 #include <map>
28
30 enum VehStatus {
31 VS_HIDDEN = 0x01,
32 VS_STOPPED = 0x02,
33 VS_UNCLICKABLE = 0x04,
34 VS_DEFPAL = 0x08,
35 VS_TRAIN_SLOWING = 0x10,
36 VS_SHADOW = 0x20,
37 VS_AIRCRAFT_BROKEN = 0x40,
38 VS_CRASHED = 0x80,
39 };
40
42 enum VehicleFlags {
43 VF_LOADING_FINISHED,
44 VF_CARGO_UNLOADING,
45 VF_BUILT_AS_PROTOTYPE,
46 VF_TIMETABLE_STARTED,
47 VF_AUTOFILL_TIMETABLE,
48 VF_AUTOFILL_PRES_WAIT_TIME,
49 VF_STOP_LOADING,
50 VF_PATHFINDER_LOST,
51 VF_SERVINT_IS_CUSTOM,
52 VF_SERVINT_IS_PERCENT,
53 };
54
56 enum NewGRFCacheValidValues {
57 NCVV_POSITION_CONSIST_LENGTH = 0,
58 NCVV_POSITION_SAME_ID_LENGTH = 1,
59 NCVV_CONSIST_CARGO_INFORMATION = 2,
60 NCVV_COMPANY_INFORMATION = 3,
61 NCVV_POSITION_IN_VEHICLE = 4,
62 NCVV_END,
63 };
64
66 struct NewGRFCache {
67 /* Values calculated when they are requested for the first time after invalidating the NewGRF cache. */
68 uint32 position_consist_length;
69 uint32 position_same_id_length;
70 uint32 consist_cargo_information;
71 uint32 company_information;
72 uint32 position_in_vehicle;
73 uint8 cache_valid;
74 };
75
77 enum VisualEffect {
78 VE_OFFSET_START = 0,
79 VE_OFFSET_COUNT = 4,
80 VE_OFFSET_CENTRE = 8,
81
82 VE_TYPE_START = 4,
83 VE_TYPE_COUNT = 2,
84 VE_TYPE_DEFAULT = 0,
85 VE_TYPE_STEAM = 1,
86 VE_TYPE_DIESEL = 2,
87 VE_TYPE_ELECTRIC = 3,
88
89 VE_DISABLE_EFFECT = 6,
90 VE_ADVANCED_EFFECT = VE_DISABLE_EFFECT,
91 VE_DISABLE_WAGON_POWER = 7,
92
93 VE_DEFAULT = 0xFF,
94 };
95
97 enum VisualEffectSpawnModel {
98 VESM_NONE = 0,
99 VESM_STEAM,
100 VESM_DIESEL,
101 VESM_ELECTRIC,
102
103 VESM_END
104 };
105
111 enum GroundVehicleSubtypeFlags {
112 GVSF_FRONT = 0,
113 GVSF_ARTICULATED_PART = 1,
114 GVSF_WAGON = 2,
115 GVSF_ENGINE = 3,
116 GVSF_FREE_WAGON = 4,
117 GVSF_MULTIHEADED = 5,
118 };
119
121 struct VehicleCache {
122 uint16 cached_max_speed;
123 uint16 cached_cargo_age_period;
124
125 byte cached_vis_effect;
126 };
127
129 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
130 extern VehiclePool _vehicle_pool;
131
132 /* Some declarations of functions, so we can make them friendly */
133 struct SaveLoad;
134 struct GroundVehicleCache;
135 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
136 struct LoadgameState;
137 extern bool LoadOldVehicle(LoadgameState *ls, int num);
138 extern void FixOldVehicles();
139
140 struct GRFFile;
141
145 struct RefitDesc {
146 CargoID cargo;
147 uint16 capacity;
148 uint16 remaining;
149 RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) :
150 cargo(cargo), capacity(capacity), remaining(remaining) {}
151 };
152
154 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
155 private:
156 typedef std::list<RefitDesc> RefitList;
157 typedef std::map<CargoID, uint> CapacitiesMap;
158
159 Vehicle *next;
160 Vehicle *previous;
161 Vehicle *first;
162
163 Vehicle *next_shared;
164 Vehicle *previous_shared;
165
166 public:
167 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
168 friend void FixOldVehicles();
169 friend void AfterLoadVehicles(bool part_of_load);
170 friend bool LoadOldVehicle(LoadgameState *ls, int num);
171
172 TileIndex tile;
173
179 TileIndex dest_tile;
180
181 Money profit_this_year;
182 Money profit_last_year;
183 Money value;
184
185 CargoPayment *cargo_payment;
186
187 Rect coord;
188
189 Vehicle *hash_viewport_next;
190 Vehicle **hash_viewport_prev;
191
192 Vehicle *hash_tile_next;
193 Vehicle **hash_tile_prev;
194 Vehicle **hash_tile_current;
195
196 SpriteID colourmap;
197
198 /* Related to age and service time */
199 Year build_year;
200 Date age;
201 Date max_age;
202 Date date_of_last_service;
203 uint16 reliability;
204 uint16 reliability_spd_dec;
205 byte breakdown_ctr;
206 byte breakdown_delay;
207 byte breakdowns_since_last_service;
208 byte breakdown_chance;
209
210 int32 x_pos;
211 int32 y_pos;
212 int32 z_pos;
213 DirectionByte direction;
214
215 OwnerByte owner;
216
221 byte spritenum;
222 SpriteID cur_image;
223 byte x_extent;
224 byte y_extent;
225 byte z_extent;
226 int8 x_bb_offs;
227 int8 y_bb_offs;
228 int8 x_offs;
229 int8 y_offs;
230 EngineID engine_type;
231
232 TextEffectID fill_percent_te_id;
233 UnitID unitnumber;
234
235 uint16 cur_speed;
236 byte subspeed;
237 byte acceleration;
238 uint32 motion_counter;
239 byte progress;
240
241 byte random_bits;
242 byte waiting_triggers;
243
244 StationID last_station_visited;
245 StationID last_loading_station;
246
247 CargoID cargo_type;
248 byte cargo_subtype;
249 uint16 cargo_cap;
250 uint16 refit_cap;
251 VehicleCargoList cargo;
252 uint16 cargo_age_counter;
253
254 byte day_counter;
255 byte tick_counter;
256 byte running_ticks;
257
258 byte vehstatus;
259 Order current_order;
260
261 union {
262 OrderList *list;
263 Order *old;
264 } orders;
265
266 uint16 load_unload_ticks;
267 GroupID group_id;
268 byte subtype;
269
270 NewGRFCache grf_cache;
271 VehicleCache vcache;
272
273 Vehicle(VehicleType type = VEH_INVALID);
274
275 void PreDestructor();
277 virtual ~Vehicle();
278
279 void BeginLoading();
280 void CancelReservation(StationID next, Station *st);
281 void LeaveStation();
282
283 GroundVehicleCache *GetGroundVehicleCache();
284 const GroundVehicleCache *GetGroundVehicleCache() const;
285
286 uint16 &GetGroundVehicleFlags();
287 const uint16 &GetGroundVehicleFlags() const;
288
289 void DeleteUnreachedImplicitOrders();
290
291 void HandleLoading(bool mode = false);
292
293 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
294
295 uint GetConsistTotalCapacity() const;
296
305 virtual void MarkDirty() {}
306
312 virtual void UpdateDeltaXY(Direction direction) {}
313
327 inline uint GetOldAdvanceSpeed(uint speed)
328 {
329 return (this->direction & 1) ? speed : speed * 3 / 4;
330 }
331
344 static inline uint GetAdvanceSpeed(uint speed)
345 {
346 return speed * 3 / 4;
347 }
348
356 inline uint GetAdvanceDistance()
357 {
358 return (this->direction & 1) ? 192 : 256;
359 }
360
365 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
366
370 virtual void PlayLeaveStationSound() const {}
371
375 virtual bool IsPrimaryVehicle() const { return false; }
376
377 const Engine *GetEngine() const;
378
384 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
385
386 const GRFFile *GetGRF() const;
387 uint32 GetGRFID() const;
388
393 inline void InvalidateNewGRFCache()
394 {
395 this->grf_cache.cache_valid = 0;
396 }
397
402 inline void InvalidateNewGRFCacheOfChain()
403 {
404 for (Vehicle *u = this; u != NULL; u = u->Next()) {
405 u->InvalidateNewGRFCache();
406 }
407 }
408
413 inline bool IsGroundVehicle() const
414 {
415 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
416 }
417
422 virtual int GetDisplaySpeed() const { return 0; }
423
428 virtual int GetDisplayMaxSpeed() const { return 0; }
429
434 virtual int GetCurrentMaxSpeed() const { return 0; }
435
440 virtual Money GetRunningCost() const { return 0; }
441
446 virtual bool IsInDepot() const { return false; }
447
452 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
453
458 bool IsStoppedInDepot() const
459 {
460 assert(this == this->First());
461 /* Free wagons have no VS_STOPPED state */
462 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
463 return this->IsChainInDepot();
464 }
465
470 virtual bool Tick() { return true; };
471
475 virtual void OnNewDay() {};
476
482 virtual uint Crash(bool flooded = false);
483
496 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
497
502 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
503
508 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
509
514 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
515
516 void SetNext(Vehicle *next);
517
523 inline Vehicle *Next() const { return this->next; }
524
530 inline Vehicle *Previous() const { return this->previous; }
531
536 inline Vehicle *First() const { return this->first; }
537
542 inline Vehicle *Last()
543 {
544 Vehicle *v = this;
545 while (v->Next() != NULL) v = v->Next();
546 return v;
547 }
548
553 inline const Vehicle *Last() const
554 {
555 const Vehicle *v = this;
556 while (v->Next() != NULL) v = v->Next();
557 return v;
558 }
559
565 inline Vehicle *Move(int n)
566 {
567 Vehicle *v = this;
568 if (n < 0) {
569 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
570 } else {
571 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
572 }
573 return v;
574 }
575
581 inline const Vehicle *Move(int n) const
582 {
583 const Vehicle *v = this;
584 if (n < 0) {
585 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
586 } else {
587 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
588 }
589 return v;
590 }
591
596 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
597
598 void AddToShared(Vehicle *shared_chain);
599 void RemoveFromShared();
600
605 inline Vehicle *NextShared() const { return this->next_shared; }
606
611 inline Vehicle *PreviousShared() const { return this->previous_shared; }
612
617 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
618
623 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
624
629 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
630
635 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
636
641 inline StationIDStack GetNextStoppingStation() const
642 {
643 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
644 }
645
646 void ResetRefitCaps();
647
654 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
655 {
656 this->CopyConsistPropertiesFrom(src);
657
658 this->unitnumber = src->unitnumber;
659
660 this->current_order = src->current_order;
661 this->dest_tile = src->dest_tile;
662
663 this->profit_this_year = src->profit_this_year;
664 this->profit_last_year = src->profit_last_year;
665 }
666
667
668 bool HandleBreakdown();
669
670 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
671
672 bool NeedsServicing() const;
673 bool NeedsAutomaticServicing() const;
674
682 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
683
692 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
693
694 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
695
696 void UpdateVisualEffect(bool allow_power_change = true);
697 void ShowVisualEffect() const;
698
699 void UpdatePosition();
700 void UpdateViewport(bool dirty);
701 void UpdatePositionAndViewport();
702 void MarkAllViewportsDirty() const;
703
704 inline uint16 GetServiceInterval() const { return this->service_interval; }
705
706 inline void SetServiceInterval(uint16 interval) { this->service_interval = interval; }
707
708 inline bool ServiceIntervalIsCustom() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); }
709
710 inline bool ServiceIntervalIsPercent() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); }
711
712 inline void SetServiceIntervalIsCustom(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_CUSTOM, 1, on); }
713
714 inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); }
715
716 private:
721 void SkipToNextRealOrderIndex()
722 {
723 if (this->GetNumManualOrders() > 0) {
724 /* Advance to next real order */
725 do {
726 this->cur_real_order_index++;
727 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
728 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
729 } else {
730 this->cur_real_order_index = 0;
731 }
732 }
733
734 public:
740 void IncrementImplicitOrderIndex()
741 {
742 if (this->cur_implicit_order_index == this->cur_real_order_index) {
743 /* Increment real order index as well */
744 this->SkipToNextRealOrderIndex();
745 }
746
747 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
748
749 /* Advance to next implicit order */
750 do {
751 this->cur_implicit_order_index++;
752 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
753 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
754
755 InvalidateVehicleOrder(this, 0);
756 }
757
764 void IncrementRealOrderIndex()
765 {
766 if (this->cur_implicit_order_index == this->cur_real_order_index) {
767 /* Increment both real and implicit order */
768 this->IncrementImplicitOrderIndex();
769 } else {
770 /* Increment real order only */
771 this->SkipToNextRealOrderIndex();
772 InvalidateVehicleOrder(this, 0);
773 }
774 }
775
779 void UpdateRealOrderIndex()
780 {
781 /* Make sure the index is valid */
782 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
783
784 if (this->GetNumManualOrders() > 0) {
785 /* Advance to next real order */
786 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
787 this->cur_real_order_index++;
788 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
789 }
790 } else {
791 this->cur_real_order_index = 0;
792 }
793 }
794
800 inline Order *GetOrder(int index) const
801 {
802 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
803 }
804
809 inline Order *GetLastOrder() const
810 {
811 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
812 }
813
814 bool IsEngineCountable() const;
815 bool HasEngineType() const;
816 bool HasDepotOrder() const;
817 void HandlePathfindingResult(bool path_found);
818
823 inline bool IsFrontEngine() const
824 {
825 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
826 }
827
832 inline bool IsArticulatedPart() const
833 {
834 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
835 }
836
841 inline bool HasArticulatedPart() const
842 {
843 return this->Next() != NULL && this->Next()->IsArticulatedPart();
844 }
845
851 inline Vehicle *GetNextArticulatedPart() const
852 {
853 assert(this->HasArticulatedPart());
854 return this->Next();
855 }
856
861 inline Vehicle *GetFirstEnginePart()
862 {
863 Vehicle *v = this;
864 while (v->IsArticulatedPart()) v = v->Previous();
865 return v;
866 }
867
872 inline const Vehicle *GetFirstEnginePart() const
873 {
874 const Vehicle *v = this;
875 while (v->IsArticulatedPart()) v = v->Previous();
876 return v;
877 }
878
883 inline Vehicle *GetLastEnginePart()
884 {
885 Vehicle *v = this;
886 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
887 return v;
888 }
889
894 inline Vehicle *GetNextVehicle() const
895 {
896 const Vehicle *v = this;
897 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
898
899 /* v now contains the last articulated part in the engine */
900 return v->Next();
901 }
902
907 inline Vehicle *GetPrevVehicle() const
908 {
909 Vehicle *v = this->Previous();
910 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
911
912 return v;
913 }
914 };
915
921 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
922
927 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
928
933 template <class T, VehicleType Type>
934 struct SpecializedVehicle : public Vehicle {
935 static const VehicleType EXPECTED_TYPE = Type;
936
937 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
938
942 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
943
948 inline T *First() const { return (T *)this->Vehicle::First(); }
949
954 inline T *Last() { return (T *)this->Vehicle::Last(); }
955
960 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
961
966 inline T *Next() const { return (T *)this->Vehicle::Next(); }
967
972 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
973
979 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
980
986 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
987
992 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
993
998 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
999
1004 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
1005
1010 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
1011
1016 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
1017
1023 static inline bool IsValidID(size_t index)
1024 {
1025 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
1026 }
1027
1032 static inline T *Get(size_t index)
1033 {
1034 return (T *)Vehicle::Get(index);
1035 }
1036
1041 static inline T *GetIfValid(size_t index)
1042 {
1043 return IsValidID(index) ? Get(index) : NULL;
1044 }
1045
1051 static inline T *From(Vehicle *v)
1052 {
1053 assert(v->type == Type);
1054 return (T *)v;
1055 }
1056
1062 static inline const T *From(const Vehicle *v)
1063 {
1064 assert(v->type == Type);
1065 return (const T *)v;
1066 }
1067
1073 inline void UpdateViewport(bool force_update, bool update_delta)
1074 {
1075 /* Explicitly choose method to call to prevent vtable dereference -
1076 * it gives ~3% runtime improvements in games with many vehicles */
1077 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
1078 SpriteID old_image = this->cur_image;
1079 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
1080 if (force_update || this->cur_image != old_image) this->Vehicle::UpdateViewport(true);
1081 }
1082 };
1083
1089 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
1090
1092 struct FreeUnitIDGenerator {
1093 bool *cache;
1094 UnitID maxid;
1095 UnitID curid;
1096
1097 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
1098 UnitID NextID();
1099
1101 ~FreeUnitIDGenerator() { free(this->cache); }
1102 };
1103
1105 static const int32 INVALID_COORD = 0x7fffffff;
1106
1107 #endif /* VEHICLE_BASE_H */