vehicle_base.h

Go to the documentation of this file.
00001 /* $Id: vehicle_base.h 26157 2013-12-13 20:21:04Z frosch $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #ifndef VEHICLE_BASE_H
00013 #define VEHICLE_BASE_H
00014 
00015 #include "core/smallmap_type.hpp"
00016 #include "track_type.h"
00017 #include "command_type.h"
00018 #include "order_base.h"
00019 #include "cargopacket.h"
00020 #include "texteff.hpp"
00021 #include "engine_type.h"
00022 #include "order_func.h"
00023 #include "transport_type.h"
00024 #include "group_type.h"
00025 #include "base_consist.h"
00026 #include <list>
00027 #include <map>
00028 
00030 enum VehStatus {
00031   VS_HIDDEN          = 0x01, 
00032   VS_STOPPED         = 0x02, 
00033   VS_UNCLICKABLE     = 0x04, 
00034   VS_DEFPAL          = 0x08, 
00035   VS_TRAIN_SLOWING   = 0x10, 
00036   VS_SHADOW          = 0x20, 
00037   VS_AIRCRAFT_BROKEN = 0x40, 
00038   VS_CRASHED         = 0x80, 
00039 };
00040 
00042 enum VehicleFlags {
00043   VF_LOADING_FINISHED,        
00044   VF_CARGO_UNLOADING,         
00045   VF_BUILT_AS_PROTOTYPE,      
00046   VF_TIMETABLE_STARTED,       
00047   VF_AUTOFILL_TIMETABLE,      
00048   VF_AUTOFILL_PRES_WAIT_TIME, 
00049   VF_STOP_LOADING,            
00050   VF_PATHFINDER_LOST,         
00051   VF_SERVINT_IS_CUSTOM,       
00052   VF_SERVINT_IS_PERCENT,      
00053 };
00054 
00056 enum NewGRFCacheValidValues {
00057   NCVV_POSITION_CONSIST_LENGTH   = 0, 
00058   NCVV_POSITION_SAME_ID_LENGTH   = 1, 
00059   NCVV_CONSIST_CARGO_INFORMATION = 2, 
00060   NCVV_COMPANY_INFORMATION       = 3, 
00061   NCVV_POSITION_IN_VEHICLE       = 4, 
00062   NCVV_END,                           
00063 };
00064 
00066 struct NewGRFCache {
00067   /* Values calculated when they are requested for the first time after invalidating the NewGRF cache. */
00068   uint32 position_consist_length;   
00069   uint32 position_same_id_length;   
00070   uint32 consist_cargo_information; 
00071   uint32 company_information;       
00072   uint32 position_in_vehicle;       
00073   uint8  cache_valid;               
00074 };
00075 
00077 enum VisualEffect {
00078   VE_OFFSET_START        = 0, 
00079   VE_OFFSET_COUNT        = 4, 
00080   VE_OFFSET_CENTRE       = 8, 
00081 
00082   VE_TYPE_START          = 4, 
00083   VE_TYPE_COUNT          = 2, 
00084   VE_TYPE_DEFAULT        = 0, 
00085   VE_TYPE_STEAM          = 1, 
00086   VE_TYPE_DIESEL         = 2, 
00087   VE_TYPE_ELECTRIC       = 3, 
00088 
00089   VE_DISABLE_EFFECT      = 6, 
00090   VE_DISABLE_WAGON_POWER = 7, 
00091 
00092   VE_DEFAULT = 0xFF,          
00093 };
00094 
00100 enum GroundVehicleSubtypeFlags {
00101   GVSF_FRONT            = 0, 
00102   GVSF_ARTICULATED_PART = 1, 
00103   GVSF_WAGON            = 2, 
00104   GVSF_ENGINE           = 3, 
00105   GVSF_FREE_WAGON       = 4, 
00106   GVSF_MULTIHEADED      = 5, 
00107 };
00108 
00110 struct VehicleCache {
00111   uint16 cached_max_speed;        
00112   uint16 cached_cargo_age_period; 
00113 
00114   byte cached_vis_effect;  
00115 };
00116 
00118 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00119 extern VehiclePool _vehicle_pool;
00120 
00121 /* Some declarations of functions, so we can make them friendly */
00122 struct SaveLoad;
00123 struct GroundVehicleCache;
00124 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00125 struct LoadgameState;
00126 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00127 extern void FixOldVehicles();
00128 
00129 struct GRFFile;
00130 
00134 struct RefitDesc {
00135   CargoID cargo;    
00136   uint16 capacity;  
00137   uint16 remaining; 
00138   RefitDesc(CargoID cargo, uint16 capacity, uint16 remaining) :
00139       cargo(cargo), capacity(capacity), remaining(remaining) {}
00140 };
00141 
00143 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
00144 private:
00145   typedef std::list<RefitDesc> RefitList;
00146   typedef std::map<CargoID, uint> CapacitiesMap;
00147 
00148   Vehicle *next;                      
00149   Vehicle *previous;                  
00150   Vehicle *first;                     
00151 
00152   Vehicle *next_shared;               
00153   Vehicle *previous_shared;           
00154 
00155 public:
00156   friend const SaveLoad *GetVehicleDescription(VehicleType vt); 
00157   friend void FixOldVehicles();
00158   friend void AfterLoadVehicles(bool part_of_load);             
00159   friend bool LoadOldVehicle(LoadgameState *ls, int num);       
00160 
00161   TileIndex tile;                     
00162 
00168   TileIndex dest_tile;
00169 
00170   Money profit_this_year;             
00171   Money profit_last_year;             
00172   Money value;                        
00173 
00174   CargoPayment *cargo_payment;        
00175 
00176   Rect coord;                         
00177 
00178   Vehicle *hash_viewport_next;        
00179   Vehicle **hash_viewport_prev;       
00180 
00181   Vehicle *hash_tile_next;            
00182   Vehicle **hash_tile_prev;           
00183   Vehicle **hash_tile_current;        
00184 
00185   SpriteID colourmap;                 
00186 
00187   /* Related to age and service time */
00188   Year build_year;                    
00189   Date age;                           
00190   Date max_age;                       
00191   Date date_of_last_service;          
00192   uint16 reliability;                 
00193   uint16 reliability_spd_dec;         
00194   byte breakdown_ctr;                 
00195   byte breakdown_delay;               
00196   byte breakdowns_since_last_service; 
00197   byte breakdown_chance;              
00198 
00199   int32 x_pos;                        
00200   int32 y_pos;                        
00201   int32 z_pos;                        
00202   DirectionByte direction;            
00203 
00204   OwnerByte owner;                    
00205 
00210   byte spritenum;
00211   SpriteID cur_image;                 
00212   byte x_extent;                      
00213   byte y_extent;                      
00214   byte z_extent;                      
00215   int8 x_bb_offs;                     
00216   int8 y_bb_offs;                     
00217   int8 x_offs;                        
00218   int8 y_offs;                        
00219   EngineID engine_type;               
00220 
00221   TextEffectID fill_percent_te_id;    
00222   UnitID unitnumber;                  
00223 
00224   uint16 cur_speed;                   
00225   byte subspeed;                      
00226   byte acceleration;                  
00227   uint32 motion_counter;              
00228   byte progress;                      
00229 
00230   byte random_bits;                   
00231   byte waiting_triggers;              
00232 
00233   StationID last_station_visited;     
00234   StationID last_loading_station;     
00235 
00236   CargoID cargo_type;                 
00237   byte cargo_subtype;                 
00238   uint16 cargo_cap;                   
00239   uint16 refit_cap;                   
00240   VehicleCargoList cargo;             
00241   uint16 cargo_age_counter;           
00242 
00243   byte day_counter;                   
00244   byte tick_counter;                  
00245   byte running_ticks;                 
00246 
00247   byte vehstatus;                     
00248   Order current_order;                
00249 
00250   union {
00251     OrderList *list;            
00252     Order     *old;             
00253   } orders;                           
00254 
00255   uint16 load_unload_ticks;           
00256   GroupID group_id;                   
00257   byte subtype;                       
00258 
00259   NewGRFCache grf_cache;              
00260   VehicleCache vcache;                
00261 
00262   Vehicle(VehicleType type = VEH_INVALID);
00263 
00264   void PreDestructor();
00266   virtual ~Vehicle();
00267 
00268   void BeginLoading();
00269   void CancelReservation(StationID next, Station *st);
00270   void LeaveStation();
00271 
00272   GroundVehicleCache *GetGroundVehicleCache();
00273   const GroundVehicleCache *GetGroundVehicleCache() const;
00274 
00275   uint16 &GetGroundVehicleFlags();
00276   const uint16 &GetGroundVehicleFlags() const;
00277 
00278   void DeleteUnreachedImplicitOrders();
00279 
00280   void HandleLoading(bool mode = false);
00281 
00282   void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
00283 
00284   uint GetConsistTotalCapacity() const;
00285 
00294   virtual void MarkDirty() {}
00295 
00301   virtual void UpdateDeltaXY(Direction direction) {}
00302 
00316   inline uint GetOldAdvanceSpeed(uint speed)
00317   {
00318     return (this->direction & 1) ? speed : speed * 3 / 4;
00319   }
00320 
00333   static inline uint GetAdvanceSpeed(uint speed)
00334   {
00335     return speed * 3 / 4;
00336   }
00337 
00345   inline uint GetAdvanceDistance()
00346   {
00347     return (this->direction & 1) ? 192 : 256;
00348   }
00349 
00354   virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00355 
00359   virtual void PlayLeaveStationSound() const {}
00360 
00364   virtual bool IsPrimaryVehicle() const { return false; }
00365 
00366   const Engine *GetEngine() const;
00367 
00373   virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00374 
00375   const GRFFile *GetGRF() const;
00376   uint32 GetGRFID() const;
00377 
00382   inline void InvalidateNewGRFCache()
00383   {
00384     this->grf_cache.cache_valid = 0;
00385   }
00386 
00391   inline void InvalidateNewGRFCacheOfChain()
00392   {
00393     for (Vehicle *u = this; u != NULL; u = u->Next()) {
00394       u->InvalidateNewGRFCache();
00395     }
00396   }
00397 
00402   inline bool IsGroundVehicle() const
00403   {
00404     return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00405   }
00406 
00411   virtual int GetDisplaySpeed() const { return 0; }
00412 
00417   virtual int GetDisplayMaxSpeed() const { return 0; }
00418 
00423   virtual int GetCurrentMaxSpeed() const { return 0; }
00424 
00429   virtual Money GetRunningCost() const { return 0; }
00430 
00435   virtual bool IsInDepot() const { return false; }
00436 
00441   virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00442 
00447   bool IsStoppedInDepot() const
00448   {
00449     assert(this == this->First());
00450     /* Free wagons have no VS_STOPPED state */
00451     if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00452     return this->IsChainInDepot();
00453   }
00454 
00459   virtual bool Tick() { return true; };
00460 
00464   virtual void OnNewDay() {};
00465 
00471   virtual uint Crash(bool flooded = false);
00472 
00485   virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00486 
00491   Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00492 
00497   Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00498 
00503   Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00504 
00505   void SetNext(Vehicle *next);
00506 
00512   inline Vehicle *Next() const { return this->next; }
00513 
00519   inline Vehicle *Previous() const { return this->previous; }
00520 
00525   inline Vehicle *First() const { return this->first; }
00526 
00531   inline Vehicle *Last()
00532   {
00533     Vehicle *v = this;
00534     while (v->Next() != NULL) v = v->Next();
00535     return v;
00536   }
00537 
00542   inline const Vehicle *Last() const
00543   {
00544     const Vehicle *v = this;
00545     while (v->Next() != NULL) v = v->Next();
00546     return v;
00547   }
00548 
00554   inline Vehicle *Move(int n)
00555   {
00556     Vehicle *v = this;
00557     if (n < 0) {
00558       for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00559     } else {
00560       for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00561     }
00562     return v;
00563   }
00564 
00570   inline const Vehicle *Move(int n) const
00571   {
00572     const Vehicle *v = this;
00573     if (n < 0) {
00574       for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00575     } else {
00576       for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00577     }
00578     return v;
00579   }
00580 
00585   inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00586 
00587   void AddToShared(Vehicle *shared_chain);
00588   void RemoveFromShared();
00589 
00594   inline Vehicle *NextShared() const { return this->next_shared; }
00595 
00600   inline Vehicle *PreviousShared() const { return this->previous_shared; }
00601 
00606   inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00607 
00612   inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00613 
00618   inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00619 
00624   inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00625 
00630   inline StationIDStack GetNextStoppingStation() const
00631   {
00632     return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
00633   }
00634 
00635   void ResetRefitCaps();
00636 
00643   inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00644   {
00645     this->CopyConsistPropertiesFrom(src);
00646 
00647     this->unitnumber = src->unitnumber;
00648 
00649     this->current_order = src->current_order;
00650     this->dest_tile  = src->dest_tile;
00651 
00652     this->profit_this_year = src->profit_this_year;
00653     this->profit_last_year = src->profit_last_year;
00654   }
00655 
00656 
00657   bool HandleBreakdown();
00658 
00659   bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
00660 
00661   bool NeedsServicing() const;
00662   bool NeedsAutomaticServicing() const;
00663 
00671   virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00672 
00681   virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00682 
00683   CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00684 
00685   void UpdateVisualEffect(bool allow_power_change = true);
00686   void ShowVisualEffect() const;
00687 
00688   inline uint16 GetServiceInterval() const { return this->service_interval; }
00689 
00690   inline void SetServiceInterval(uint16 interval) { this->service_interval = interval; }
00691 
00692   inline bool ServiceIntervalIsCustom() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); }
00693 
00694   inline bool ServiceIntervalIsPercent() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); }
00695 
00696   inline void SetServiceIntervalIsCustom(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_CUSTOM, 1, on); }
00697 
00698   inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); }
00699 
00700 private:
00705   void SkipToNextRealOrderIndex()
00706   {
00707     if (this->GetNumManualOrders() > 0) {
00708       /* Advance to next real order */
00709       do {
00710         this->cur_real_order_index++;
00711         if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00712       } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00713     } else {
00714       this->cur_real_order_index = 0;
00715     }
00716   }
00717 
00718 public:
00724   void IncrementImplicitOrderIndex()
00725   {
00726     if (this->cur_implicit_order_index == this->cur_real_order_index) {
00727       /* Increment real order index as well */
00728       this->SkipToNextRealOrderIndex();
00729     }
00730 
00731     assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00732 
00733     /* Advance to next implicit order */
00734     do {
00735       this->cur_implicit_order_index++;
00736       if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00737     } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00738 
00739     InvalidateVehicleOrder(this, 0);
00740   }
00741 
00748   void IncrementRealOrderIndex()
00749   {
00750     if (this->cur_implicit_order_index == this->cur_real_order_index) {
00751       /* Increment both real and implicit order */
00752       this->IncrementImplicitOrderIndex();
00753     } else {
00754       /* Increment real order only */
00755       this->SkipToNextRealOrderIndex();
00756       InvalidateVehicleOrder(this, 0);
00757     }
00758   }
00759 
00763   void UpdateRealOrderIndex()
00764   {
00765     /* Make sure the index is valid */
00766     if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00767 
00768     if (this->GetNumManualOrders() > 0) {
00769       /* Advance to next real order */
00770       while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00771         this->cur_real_order_index++;
00772         if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00773       }
00774     } else {
00775       this->cur_real_order_index = 0;
00776     }
00777   }
00778 
00784   inline Order *GetOrder(int index) const
00785   {
00786     return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00787   }
00788 
00793   inline Order *GetLastOrder() const
00794   {
00795     return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00796   }
00797 
00798   bool IsEngineCountable() const;
00799   bool HasEngineType() const;
00800   bool HasDepotOrder() const;
00801   void HandlePathfindingResult(bool path_found);
00802 
00807   inline bool IsFrontEngine() const
00808   {
00809     return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00810   }
00811 
00816   inline bool IsArticulatedPart() const
00817   {
00818     return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00819   }
00820 
00825   inline bool HasArticulatedPart() const
00826   {
00827     return this->Next() != NULL && this->Next()->IsArticulatedPart();
00828   }
00829 
00835   inline Vehicle *GetNextArticulatedPart() const
00836   {
00837     assert(this->HasArticulatedPart());
00838     return this->Next();
00839   }
00840 
00845   inline Vehicle *GetFirstEnginePart()
00846   {
00847     Vehicle *v = this;
00848     while (v->IsArticulatedPart()) v = v->Previous();
00849     return v;
00850   }
00851 
00856   inline const Vehicle *GetFirstEnginePart() const
00857   {
00858     const Vehicle *v = this;
00859     while (v->IsArticulatedPart()) v = v->Previous();
00860     return v;
00861   }
00862 
00867   inline Vehicle *GetLastEnginePart()
00868   {
00869     Vehicle *v = this;
00870     while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00871     return v;
00872   }
00873 
00878   inline Vehicle *GetNextVehicle() const
00879   {
00880     const Vehicle *v = this;
00881     while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00882 
00883     /* v now contains the last articulated part in the engine */
00884     return v->Next();
00885   }
00886 
00891   inline Vehicle *GetPrevVehicle() const
00892   {
00893     Vehicle *v = this->Previous();
00894     while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00895 
00896     return v;
00897   }
00898 };
00899 
00905 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00906 
00911 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00912 
00917 template <class T, VehicleType Type>
00918 struct SpecializedVehicle : public Vehicle {
00919   static const VehicleType EXPECTED_TYPE = Type; 
00920 
00921   typedef SpecializedVehicle<T, Type> SpecializedVehicleBase; 
00922 
00926   inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00927 
00932   inline T *First() const { return (T *)this->Vehicle::First(); }
00933 
00938   inline T *Last() { return (T *)this->Vehicle::Last(); }
00939 
00944   inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00945 
00950   inline T *Next() const { return (T *)this->Vehicle::Next(); }
00951 
00956   inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00957 
00963   inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00964 
00970   inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00971 
00976   inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00977 
00982   inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00983 
00988   inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00989 
00994   inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00995 
01000   inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
01001 
01007   static inline bool IsValidID(size_t index)
01008   {
01009     return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
01010   }
01011 
01016   static inline T *Get(size_t index)
01017   {
01018     return (T *)Vehicle::Get(index);
01019   }
01020 
01025   static inline T *GetIfValid(size_t index)
01026   {
01027     return IsValidID(index) ? Get(index) : NULL;
01028   }
01029 
01035   static inline T *From(Vehicle *v)
01036   {
01037     assert(v->type == Type);
01038     return (T *)v;
01039   }
01040 
01046   static inline const T *From(const Vehicle *v)
01047   {
01048     assert(v->type == Type);
01049     return (const T *)v;
01050   }
01051 
01057   inline void UpdateViewport(bool force_update, bool update_delta)
01058   {
01059     extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
01060 
01061     /* Explicitly choose method to call to prevent vtable dereference -
01062      * it gives ~3% runtime improvements in games with many vehicles */
01063     if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
01064     SpriteID old_image = this->cur_image;
01065     this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
01066     if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
01067   }
01068 };
01069 
01075 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01076 
01080 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01081   SpriteID image_override;            
01082   VehicleID big_ufo_destroyer_target; 
01083 
01085   DisasterVehicle() : SpecializedVehicleBase() {}
01087   virtual ~DisasterVehicle() {}
01088 
01089   void UpdateDeltaXY(Direction direction);
01090   bool Tick();
01091 };
01092 
01097 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01098 
01100 struct FreeUnitIDGenerator {
01101   bool *cache;  
01102   UnitID maxid; 
01103   UnitID curid; 
01104 
01105   FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01106   UnitID NextID();
01107 
01109   ~FreeUnitIDGenerator() { free(this->cache); }
01110 };
01111 
01113 static const int32 INVALID_COORD = 0x7fffffff;
01114 
01115 #endif /* VEHICLE_BASE_H */