OpenTTD
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,
36  VS_SHADOW = 0x20,
38  VS_CRASHED = 0x80,
39 };
40 
53 };
54 
63 };
64 
66 struct NewGRFCache {
67  /* Values calculated when they are requested for the first time after invalidating the NewGRF cache. */
73  uint8 cache_valid;
74 };
75 
81 
88 
92 
93  VE_DEFAULT = 0xFF,
94 };
95 
98  VESM_NONE = 0,
102 
103  VESM_END
104 };
105 
118 };
119 
121 struct VehicleCache {
124 
126 };
127 
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 {
147  uint16 capacity;
148  uint16 remaining;
149  RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) :
150  cargo(cargo), capacity(capacity), remaining(remaining) {}
151 };
152 
155 private:
156  typedef std::list<RefitDesc> RefitList;
157  typedef std::map<CargoID, uint> CapacitiesMap;
158 
162 
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 
173 
180 
184 
186 
188 
191 
195 
197 
198  /* Related to age and service time */
203  uint16 reliability;
209 
210  int32 x_pos;
211  int32 y_pos;
212  int32 z_pos;
214 
216 
221  byte spritenum;
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;
231 
232  TextEffectID fill_percent_te_id;
234 
235  uint16 cur_speed;
236  byte subspeed;
238  uint32 motion_counter;
239  byte progress;
240 
241  byte random_bits;
243 
246 
249  uint16 cargo_cap;
250  uint16 refit_cap;
253 
254  byte day_counter;
257 
258  byte vehstatus;
260 
261  union {
264  } orders;
265 
268  byte subtype;
269 
272 
274 
275  void PreDestructor();
277  virtual ~Vehicle();
278 
279  void BeginLoading();
280  void CancelReservation(StationID next, Station *st);
281  void LeaveStation();
282 
285 
286  uint16 &GetGroundVehicleFlags();
287  const uint16 &GetGroundVehicleFlags() const;
288 
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 
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 
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 
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 
695 
696  void UpdateVisualEffect(bool allow_power_change = true);
697  void ShowVisualEffect() const;
698 
699  void UpdatePosition();
700  void UpdateViewport(bool dirty);
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:
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:
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 
765  {
766  if (this->cur_implicit_order_index == this->cur_real_order_index) {
767  /* Increment both real and implicit order */
769  } else {
770  /* Increment real order only */
771  this->SkipToNextRealOrderIndex();
772  InvalidateVehicleOrder(this, 0);
773  }
774  }
775 
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 
852  {
853  assert(this->HasArticulatedPart());
854  return this->Next();
855  }
856 
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 
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 
938 
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 
1093  bool *cache;
1096 
1098  UnitID NextID();
1099 
1102 };
1103 
1105 static const int32 INVALID_COORD = 0x7fffffff;
1106 
1107 #endif /* VEHICLE_BASE_H */