00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef VEHICLE_BASE_H
00013 #define VEHICLE_BASE_H
00014
00015 #include "track_type.h"
00016 #include "command_type.h"
00017 #include "order_base.h"
00018 #include "cargopacket.h"
00019 #include "texteff.hpp"
00020 #include "engine_type.h"
00021 #include "order_func.h"
00022 #include "transport_type.h"
00023 #include "group_type.h"
00024 #include "base_consist.h"
00025
00027 enum VehStatus {
00028 VS_HIDDEN = 0x01,
00029 VS_STOPPED = 0x02,
00030 VS_UNCLICKABLE = 0x04,
00031 VS_DEFPAL = 0x08,
00032 VS_TRAIN_SLOWING = 0x10,
00033 VS_SHADOW = 0x20,
00034 VS_AIRCRAFT_BROKEN = 0x40,
00035 VS_CRASHED = 0x80,
00036 };
00037
00039 enum VehicleFlags {
00040 VF_LOADING_FINISHED,
00041 VF_CARGO_UNLOADING,
00042 VF_BUILT_AS_PROTOTYPE,
00043 VF_TIMETABLE_STARTED,
00044 VF_AUTOFILL_TIMETABLE,
00045 VF_AUTOFILL_PRES_WAIT_TIME,
00046 VF_STOP_LOADING,
00047 VF_PATHFINDER_LOST,
00048 };
00049
00051 enum NewGRFCacheValidValues {
00052 NCVV_POSITION_CONSIST_LENGTH = 0,
00053 NCVV_POSITION_SAME_ID_LENGTH = 1,
00054 NCVV_CONSIST_CARGO_INFORMATION = 2,
00055 NCVV_COMPANY_INFORMATION = 3,
00056 NCVV_END,
00057 };
00058
00060 struct NewGRFCache {
00061
00062 uint32 position_consist_length;
00063 uint32 position_same_id_length;
00064 uint32 consist_cargo_information;
00065 uint32 company_information;
00066 uint8 cache_valid;
00067 };
00068
00070 enum VisualEffect {
00071 VE_OFFSET_START = 0,
00072 VE_OFFSET_COUNT = 4,
00073 VE_OFFSET_CENTRE = 8,
00074
00075 VE_TYPE_START = 4,
00076 VE_TYPE_COUNT = 2,
00077 VE_TYPE_DEFAULT = 0,
00078 VE_TYPE_STEAM = 1,
00079 VE_TYPE_DIESEL = 2,
00080 VE_TYPE_ELECTRIC = 3,
00081
00082 VE_DISABLE_EFFECT = 6,
00083 VE_DISABLE_WAGON_POWER = 7,
00084
00085 VE_DEFAULT = 0xFF,
00086 };
00087
00093 enum GroundVehicleSubtypeFlags {
00094 GVSF_FRONT = 0,
00095 GVSF_ARTICULATED_PART = 1,
00096 GVSF_WAGON = 2,
00097 GVSF_ENGINE = 3,
00098 GVSF_FREE_WAGON = 4,
00099 GVSF_MULTIHEADED = 5,
00100 };
00101
00103 struct VehicleCache {
00104 uint16 cached_max_speed;
00105 uint16 cached_cargo_age_period;
00106
00107 byte cached_vis_effect;
00108 };
00109
00111 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00112 extern VehiclePool _vehicle_pool;
00113
00114
00115 struct SaveLoad;
00116 struct GroundVehicleCache;
00117 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00118 struct LoadgameState;
00119 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00120 extern void FixOldVehicles();
00121
00122 struct GRFFile;
00123
00125 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
00126 private:
00127 Vehicle *next;
00128 Vehicle *previous;
00129 Vehicle *first;
00130
00131 Vehicle *next_shared;
00132 Vehicle *previous_shared;
00133 public:
00134 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00135 friend void FixOldVehicles();
00136 friend void AfterLoadVehicles(bool part_of_load);
00137 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00138
00139 TileIndex tile;
00140
00146 TileIndex dest_tile;
00147
00148 Money profit_this_year;
00149 Money profit_last_year;
00150 Money value;
00151
00152 CargoPayment *cargo_payment;
00153
00154 Rect coord;
00155
00156 Vehicle *hash_viewport_next;
00157 Vehicle **hash_viewport_prev;
00158
00159 Vehicle *hash_tile_next;
00160 Vehicle **hash_tile_prev;
00161 Vehicle **hash_tile_current;
00162
00163 SpriteID colourmap;
00164
00165
00166 Year build_year;
00167 Date age;
00168 Date max_age;
00169 Date date_of_last_service;
00170 uint16 reliability;
00171 uint16 reliability_spd_dec;
00172 byte breakdown_ctr;
00173 byte breakdown_delay;
00174 byte breakdowns_since_last_service;
00175 byte breakdown_chance;
00176
00177 int32 x_pos;
00178 int32 y_pos;
00179 int32 z_pos;
00180 DirectionByte direction;
00181
00182 OwnerByte owner;
00183
00188 byte spritenum;
00189 SpriteID cur_image;
00190 byte x_extent;
00191 byte y_extent;
00192 byte z_extent;
00193 int8 x_bb_offs;
00194 int8 y_bb_offs;
00195 int8 x_offs;
00196 int8 y_offs;
00197 EngineID engine_type;
00198
00199 TextEffectID fill_percent_te_id;
00200 UnitID unitnumber;
00201
00202 uint16 cur_speed;
00203 byte subspeed;
00204 byte acceleration;
00205 uint32 motion_counter;
00206 byte progress;
00207
00208 byte random_bits;
00209 byte waiting_triggers;
00210
00211 StationID last_station_visited;
00212
00213 CargoID cargo_type;
00214 byte cargo_subtype;
00215 uint16 cargo_cap;
00216 VehicleCargoList cargo;
00217 uint16 cargo_age_counter;
00218
00219 byte day_counter;
00220 byte tick_counter;
00221 byte running_ticks;
00222
00223 byte vehstatus;
00224 Order current_order;
00225
00226 union {
00227 OrderList *list;
00228 Order *old;
00229 } orders;
00230
00231 uint16 load_unload_ticks;
00232 GroupID group_id;
00233 byte subtype;
00234
00235 NewGRFCache grf_cache;
00236 VehicleCache vcache;
00237
00238 Vehicle(VehicleType type = VEH_INVALID);
00239
00240 void PreDestructor();
00242 virtual ~Vehicle();
00243
00244 void BeginLoading();
00245 void LeaveStation();
00246
00247 GroundVehicleCache *GetGroundVehicleCache();
00248 const GroundVehicleCache *GetGroundVehicleCache() const;
00249
00250 uint16 &GetGroundVehicleFlags();
00251 const uint16 &GetGroundVehicleFlags() const;
00252
00253 void DeleteUnreachedImplicitOrders();
00254
00255 void HandleLoading(bool mode = false);
00256
00265 virtual void MarkDirty() {}
00266
00272 virtual void UpdateDeltaXY(Direction direction) {}
00273
00287 inline uint GetOldAdvanceSpeed(uint speed)
00288 {
00289 return (this->direction & 1) ? speed : speed * 3 / 4;
00290 }
00291
00304 static inline uint GetAdvanceSpeed(uint speed)
00305 {
00306 return speed * 3 / 4;
00307 }
00308
00316 inline uint GetAdvanceDistance()
00317 {
00318 return (this->direction & 1) ? 192 : 256;
00319 }
00320
00325 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00326
00330 virtual void PlayLeaveStationSound() const {}
00331
00335 virtual bool IsPrimaryVehicle() const { return false; }
00336
00337 const Engine *GetEngine() const;
00338
00344 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00345
00346 const GRFFile *GetGRF() const;
00347 uint32 GetGRFID() const;
00348
00353 inline void InvalidateNewGRFCache()
00354 {
00355 this->grf_cache.cache_valid = 0;
00356 }
00357
00362 inline void InvalidateNewGRFCacheOfChain()
00363 {
00364 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00365 u->InvalidateNewGRFCache();
00366 }
00367 }
00368
00373 inline bool IsGroundVehicle() const
00374 {
00375 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00376 }
00377
00382 virtual int GetDisplaySpeed() const { return 0; }
00383
00388 virtual int GetDisplayMaxSpeed() const { return 0; }
00389
00394 virtual int GetCurrentMaxSpeed() const { return 0; }
00395
00400 virtual Money GetRunningCost() const { return 0; }
00401
00406 virtual bool IsInDepot() const { return false; }
00407
00412 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00413
00418 bool IsStoppedInDepot() const
00419 {
00420 assert(this == this->First());
00421
00422 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00423 return this->IsChainInDepot();
00424 }
00425
00430 virtual bool Tick() { return true; };
00431
00435 virtual void OnNewDay() {};
00436
00442 virtual uint Crash(bool flooded = false);
00443
00456 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00457
00462 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00463
00468 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00469
00474 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00475
00476 void SetNext(Vehicle *next);
00477
00483 inline Vehicle *Next() const { return this->next; }
00484
00490 inline Vehicle *Previous() const { return this->previous; }
00491
00496 inline Vehicle *First() const { return this->first; }
00497
00502 inline Vehicle *Last()
00503 {
00504 Vehicle *v = this;
00505 while (v->Next() != NULL) v = v->Next();
00506 return v;
00507 }
00508
00513 inline const Vehicle *Last() const
00514 {
00515 const Vehicle *v = this;
00516 while (v->Next() != NULL) v = v->Next();
00517 return v;
00518 }
00519
00525 inline Vehicle *Move(int n)
00526 {
00527 Vehicle *v = this;
00528 if (n < 0) {
00529 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00530 } else {
00531 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00532 }
00533 return v;
00534 }
00535
00540 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00541
00542 void AddToShared(Vehicle *shared_chain);
00543 void RemoveFromShared();
00544
00549 inline Vehicle *NextShared() const { return this->next_shared; }
00550
00555 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00556
00561 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00562
00567 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00568
00573 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00574
00579 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00580
00587 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00588 {
00589 this->CopyConsistPropertiesFrom(src);
00590
00591 this->unitnumber = src->unitnumber;
00592
00593 this->current_order = src->current_order;
00594 this->dest_tile = src->dest_tile;
00595
00596 this->profit_this_year = src->profit_this_year;
00597 this->profit_last_year = src->profit_last_year;
00598 }
00599
00600
00601 bool HandleBreakdown();
00602
00603 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
00604
00605 bool NeedsServicing() const;
00606 bool NeedsAutomaticServicing() const;
00607
00615 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00616
00625 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00626
00627 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00628
00629 void UpdateVisualEffect(bool allow_power_change = true);
00630 void ShowVisualEffect() const;
00631
00632 private:
00637 void SkipToNextRealOrderIndex()
00638 {
00639 if (this->GetNumManualOrders() > 0) {
00640
00641 do {
00642 this->cur_real_order_index++;
00643 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00644 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00645 } else {
00646 this->cur_real_order_index = 0;
00647 }
00648 }
00649
00650 public:
00656 void IncrementImplicitOrderIndex()
00657 {
00658 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00659
00660 this->SkipToNextRealOrderIndex();
00661 }
00662
00663 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00664
00665
00666 do {
00667 this->cur_implicit_order_index++;
00668 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00669 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00670
00671 InvalidateVehicleOrder(this, 0);
00672 }
00673
00680 void IncrementRealOrderIndex()
00681 {
00682 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00683
00684 this->IncrementImplicitOrderIndex();
00685 } else {
00686
00687 this->SkipToNextRealOrderIndex();
00688 InvalidateVehicleOrder(this, 0);
00689 }
00690 }
00691
00695 void UpdateRealOrderIndex()
00696 {
00697
00698 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00699
00700 if (this->GetNumManualOrders() > 0) {
00701
00702 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00703 this->cur_real_order_index++;
00704 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00705 }
00706 } else {
00707 this->cur_real_order_index = 0;
00708 }
00709 }
00710
00716 inline Order *GetOrder(int index) const
00717 {
00718 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00719 }
00720
00725 inline Order *GetLastOrder() const
00726 {
00727 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00728 }
00729
00730 bool IsEngineCountable() const;
00731 bool HasEngineType() const;
00732 bool HasDepotOrder() const;
00733 void HandlePathfindingResult(bool path_found);
00734
00739 inline bool IsFrontEngine() const
00740 {
00741 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00742 }
00743
00748 inline bool IsArticulatedPart() const
00749 {
00750 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00751 }
00752
00757 inline bool HasArticulatedPart() const
00758 {
00759 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00760 }
00761
00767 inline Vehicle *GetNextArticulatedPart() const
00768 {
00769 assert(this->HasArticulatedPart());
00770 return this->Next();
00771 }
00772
00777 inline Vehicle *GetFirstEnginePart()
00778 {
00779 Vehicle *v = this;
00780 while (v->IsArticulatedPart()) v = v->Previous();
00781 return v;
00782 }
00783
00788 inline const Vehicle *GetFirstEnginePart() const
00789 {
00790 const Vehicle *v = this;
00791 while (v->IsArticulatedPart()) v = v->Previous();
00792 return v;
00793 }
00794
00799 inline Vehicle *GetLastEnginePart()
00800 {
00801 Vehicle *v = this;
00802 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00803 return v;
00804 }
00805
00810 inline Vehicle *GetNextVehicle() const
00811 {
00812 const Vehicle *v = this;
00813 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00814
00815
00816 return v->Next();
00817 }
00818
00823 inline Vehicle *GetPrevVehicle() const
00824 {
00825 Vehicle *v = this->Previous();
00826 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00827
00828 return v;
00829 }
00830 };
00831
00837 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00838
00843 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00844
00849 template <class T, VehicleType Type>
00850 struct SpecializedVehicle : public Vehicle {
00851 static const VehicleType EXPECTED_TYPE = Type;
00852
00853 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00854
00858 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00859
00864 inline T *First() const { return (T *)this->Vehicle::First(); }
00865
00870 inline T *Last() { return (T *)this->Vehicle::Last(); }
00871
00876 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00877
00882 inline T *Next() const { return (T *)this->Vehicle::Next(); }
00883
00888 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00889
00895 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00896
00902 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00903
00908 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00909
00914 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00915
00920 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00921
00926 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00927
00932 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00933
00939 static inline bool IsValidID(size_t index)
00940 {
00941 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00942 }
00943
00948 static inline T *Get(size_t index)
00949 {
00950 return (T *)Vehicle::Get(index);
00951 }
00952
00957 static inline T *GetIfValid(size_t index)
00958 {
00959 return IsValidID(index) ? Get(index) : NULL;
00960 }
00961
00967 static inline T *From(Vehicle *v)
00968 {
00969 assert(v->type == Type);
00970 return (T *)v;
00971 }
00972
00978 static inline const T *From(const Vehicle *v)
00979 {
00980 assert(v->type == Type);
00981 return (const T *)v;
00982 }
00983
00989 inline void UpdateViewport(bool force_update, bool update_delta)
00990 {
00991 extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
00992
00993
00994
00995 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
00996 SpriteID old_image = this->cur_image;
00997 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
00998 if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
00999 }
01000 };
01001
01007 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01008
01012 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01013 SpriteID image_override;
01014 VehicleID big_ufo_destroyer_target;
01015
01017 DisasterVehicle() : SpecializedVehicleBase() {}
01019 virtual ~DisasterVehicle() {}
01020
01021 void UpdateDeltaXY(Direction direction);
01022 bool Tick();
01023 };
01024
01029 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01030
01032 struct FreeUnitIDGenerator {
01033 bool *cache;
01034 UnitID maxid;
01035 UnitID curid;
01036
01037 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01038 UnitID NextID();
01039
01041 ~FreeUnitIDGenerator() { free(this->cache); }
01042 };
01043
01045 static const int32 INVALID_COORD = 0x7fffffff;
01046
01047 #endif