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
00026 enum VehStatus {
00027 VS_HIDDEN = 0x01,
00028 VS_STOPPED = 0x02,
00029 VS_UNCLICKABLE = 0x04,
00030 VS_DEFPAL = 0x08,
00031 VS_TRAIN_SLOWING = 0x10,
00032 VS_SHADOW = 0x20,
00033 VS_AIRCRAFT_BROKEN = 0x40,
00034 VS_CRASHED = 0x80,
00035 };
00036
00038 enum VehicleFlags {
00039 VF_LOADING_FINISHED,
00040 VF_CARGO_UNLOADING,
00041 VF_BUILT_AS_PROTOTYPE,
00042 VF_TIMETABLE_STARTED,
00043 VF_AUTOFILL_TIMETABLE,
00044 VF_AUTOFILL_PRES_WAIT_TIME,
00045 VF_STOP_LOADING,
00046 VF_PATHFINDER_LOST,
00047 };
00048
00050 enum NewGRFCacheValidValues {
00051 NCVV_POSITION_CONSIST_LENGTH = 0,
00052 NCVV_POSITION_SAME_ID_LENGTH = 1,
00053 NCVV_CONSIST_CARGO_INFORMATION = 2,
00054 NCVV_COMPANY_INFORMATION = 3,
00055 NCVV_END,
00056 };
00057
00059 struct NewGRFCache {
00060
00061 uint32 position_consist_length;
00062 uint32 position_same_id_length;
00063 uint32 consist_cargo_information;
00064 uint32 company_information;
00065 uint8 cache_valid;
00066 };
00067
00069 enum VisualEffect {
00070 VE_OFFSET_START = 0,
00071 VE_OFFSET_COUNT = 4,
00072 VE_OFFSET_CENTRE = 8,
00073
00074 VE_TYPE_START = 4,
00075 VE_TYPE_COUNT = 2,
00076 VE_TYPE_DEFAULT = 0,
00077 VE_TYPE_STEAM = 1,
00078 VE_TYPE_DIESEL = 2,
00079 VE_TYPE_ELECTRIC = 3,
00080
00081 VE_DISABLE_EFFECT = 6,
00082 VE_DISABLE_WAGON_POWER = 7,
00083
00084 VE_DEFAULT = 0xFF,
00085 };
00086
00092 enum GroundVehicleSubtypeFlags {
00093 GVSF_FRONT = 0,
00094 GVSF_ARTICULATED_PART = 1,
00095 GVSF_WAGON = 2,
00096 GVSF_ENGINE = 3,
00097 GVSF_FREE_WAGON = 4,
00098 GVSF_MULTIHEADED = 5,
00099 };
00100
00102 struct VehicleCache {
00103 uint16 cached_max_speed;
00104
00105 byte cached_vis_effect;
00106 };
00107
00109 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00110 extern VehiclePool _vehicle_pool;
00111
00112
00113 struct SaveLoad;
00114 struct GroundVehicleCache;
00115 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00116 struct LoadgameState;
00117 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00118 extern void FixOldVehicles();
00119
00121 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle {
00122 private:
00123 Vehicle *next;
00124 Vehicle *previous;
00125 Vehicle *first;
00126
00127 Vehicle *next_shared;
00128 Vehicle *previous_shared;
00129 public:
00130 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00131 friend void FixOldVehicles();
00132 friend void AfterLoadVehicles(bool part_of_load);
00133 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00134
00135 char *name;
00136
00137 TileIndex tile;
00138
00144 TileIndex dest_tile;
00145
00146 Money profit_this_year;
00147 Money profit_last_year;
00148 Money value;
00149
00150 CargoPayment *cargo_payment;
00151
00152
00153 uint32 current_order_time;
00154 int32 lateness_counter;
00155 Date timetable_start;
00156
00157 Rect coord;
00158
00159 Vehicle *next_hash;
00160 Vehicle **prev_hash;
00161
00162 Vehicle *next_new_hash;
00163 Vehicle **prev_new_hash;
00164 Vehicle **old_new_hash;
00165
00166 SpriteID colourmap;
00167
00168
00169 Year build_year;
00170 Date age;
00171 Date max_age;
00172 Date date_of_last_service;
00173 Date service_interval;
00174 uint16 reliability;
00175 uint16 reliability_spd_dec;
00176 byte breakdown_ctr;
00177 byte breakdown_delay;
00178 byte breakdowns_since_last_service;
00179 byte breakdown_chance;
00180
00181 int32 x_pos;
00182 int32 y_pos;
00183 byte z_pos;
00184 DirectionByte direction;
00185
00186 OwnerByte owner;
00187 byte spritenum;
00188
00189
00190 SpriteID cur_image;
00191 byte x_extent;
00192 byte y_extent;
00193 byte z_extent;
00194 int8 x_offs;
00195 int8 y_offs;
00196 EngineID engine_type;
00197
00198 TextEffectID fill_percent_te_id;
00199 UnitID unitnumber;
00200
00201 uint16 cur_speed;
00202 byte subspeed;
00203 byte acceleration;
00204 uint32 motion_counter;
00205 byte progress;
00206
00207 byte random_bits;
00208 byte waiting_triggers;
00209
00210 StationID last_station_visited;
00211
00212 CargoID cargo_type;
00213 byte cargo_subtype;
00214 uint16 cargo_cap;
00215 VehicleCargoList cargo;
00216
00217 byte day_counter;
00218 byte tick_counter;
00219 byte running_ticks;
00220
00221 byte vehstatus;
00222 Order current_order;
00223 VehicleOrderID cur_real_order_index;
00224 VehicleOrderID cur_implicit_order_index;
00225
00226 union {
00227 OrderList *list;
00228 Order *old;
00229 } orders;
00230
00231 byte vehicle_flags;
00232
00233 uint16 load_unload_ticks;
00234 GroupID group_id;
00235 byte subtype;
00236
00237 NewGRFCache grf_cache;
00238 VehicleCache vcache;
00239
00240 Vehicle(VehicleType type = VEH_INVALID);
00241
00242 void PreDestructor();
00244 virtual ~Vehicle();
00245
00246 void BeginLoading();
00247 void LeaveStation();
00248
00249 GroundVehicleCache *GetGroundVehicleCache();
00250 const GroundVehicleCache *GetGroundVehicleCache() const;
00251
00252 uint16 &GetGroundVehicleFlags();
00253 const uint16 &GetGroundVehicleFlags() const;
00254
00255 void DeleteUnreachedImplicitOrders();
00256
00257 void HandleLoading(bool mode = false);
00258
00267 virtual void MarkDirty() {}
00268
00274 virtual void UpdateDeltaXY(Direction direction) {}
00275
00289 FORCEINLINE uint GetOldAdvanceSpeed(uint speed)
00290 {
00291 return (this->direction & 1) ? speed : speed * 3 / 4;
00292 }
00293
00306 static FORCEINLINE uint GetAdvanceSpeed(uint speed)
00307 {
00308 return speed * 3 / 4;
00309 }
00310
00318 FORCEINLINE uint GetAdvanceDistance()
00319 {
00320 return (this->direction & 1) ? 192 : 256;
00321 }
00322
00327 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00328
00332 virtual void PlayLeaveStationSound() const {}
00333
00337 virtual bool IsPrimaryVehicle() const { return false; }
00338
00344 virtual SpriteID GetImage(Direction direction) const { return 0; }
00345
00350 FORCEINLINE void InvalidateNewGRFCache()
00351 {
00352 this->grf_cache.cache_valid = 0;
00353 }
00354
00359 FORCEINLINE void InvalidateNewGRFCacheOfChain()
00360 {
00361 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00362 u->InvalidateNewGRFCache();
00363 }
00364 }
00365
00370 FORCEINLINE bool IsGroundVehicle() const
00371 {
00372 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00373 }
00374
00379 virtual int GetDisplaySpeed() const { return 0; }
00380
00385 virtual int GetDisplayMaxSpeed() const { return 0; }
00386
00391 virtual Money GetRunningCost() const { return 0; }
00392
00397 virtual bool IsInDepot() const { return false; }
00398
00403 virtual bool IsStoppedInDepot() const { return this->IsInDepot() && (this->vehstatus & VS_STOPPED) != 0; }
00404
00409 virtual bool Tick() { return true; };
00410
00414 virtual void OnNewDay() {};
00415
00421 virtual uint Crash(bool flooded = false);
00422
00435 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00436
00441 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00442
00447 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00448
00453 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00454
00455 void SetNext(Vehicle *next);
00456
00462 inline Vehicle *Next() const { return this->next; }
00463
00469 inline Vehicle *Previous() const { return this->previous; }
00470
00475 inline Vehicle *First() const { return this->first; }
00476
00481 inline Vehicle *Last()
00482 {
00483 Vehicle *v = this;
00484 while (v->Next() != NULL) v = v->Next();
00485 return v;
00486 }
00487
00492 inline const Vehicle *Last() const
00493 {
00494 const Vehicle *v = this;
00495 while (v->Next() != NULL) v = v->Next();
00496 return v;
00497 }
00498
00503 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00504
00505 void AddToShared(Vehicle *shared_chain);
00506 void RemoveFromShared();
00507
00512 inline Vehicle *NextShared() const { return this->next_shared; }
00513
00518 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00519
00524 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00525
00530 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00531
00536 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00537
00542 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00543
00550 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00551 {
00552 this->unitnumber = src->unitnumber;
00553
00554 this->cur_real_order_index = src->cur_real_order_index;
00555 this->cur_implicit_order_index = src->cur_implicit_order_index;
00556 this->current_order = src->current_order;
00557 this->dest_tile = src->dest_tile;
00558
00559 this->profit_this_year = src->profit_this_year;
00560 this->profit_last_year = src->profit_last_year;
00561
00562 this->current_order_time = src->current_order_time;
00563 this->lateness_counter = src->lateness_counter;
00564 this->timetable_start = src->timetable_start;
00565
00566 if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
00567 if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00568 if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00569
00570 this->service_interval = src->service_interval;
00571 }
00572
00573
00574 bool HandleBreakdown();
00575
00576 bool NeedsAutorenewing(const Company *c) const;
00577
00578 bool NeedsServicing() const;
00579 bool NeedsAutomaticServicing() const;
00580
00588 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00589
00598 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00599
00600 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00601
00602 void UpdateVisualEffect(bool allow_power_change = true);
00603 void ShowVisualEffect() const;
00604
00605 private:
00610 void SkipToNextRealOrderIndex()
00611 {
00612 if (this->GetNumManualOrders() > 0) {
00613
00614 do {
00615 this->cur_real_order_index++;
00616 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00617 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00618 } else {
00619 this->cur_real_order_index = 0;
00620 }
00621 }
00622
00623 public:
00629 void IncrementImplicitOrderIndex()
00630 {
00631 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00632
00633 this->SkipToNextRealOrderIndex();
00634 }
00635
00636 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00637
00638
00639 do {
00640 this->cur_implicit_order_index++;
00641 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00642 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00643
00644 InvalidateVehicleOrder(this, 0);
00645 }
00646
00653 void IncrementRealOrderIndex()
00654 {
00655 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00656
00657 this->IncrementImplicitOrderIndex();
00658 } else {
00659
00660 this->SkipToNextRealOrderIndex();
00661 InvalidateVehicleOrder(this, 0);
00662 }
00663 }
00664
00668 void UpdateRealOrderIndex()
00669 {
00670
00671 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00672
00673 if (this->GetNumManualOrders() > 0) {
00674
00675 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00676 this->cur_real_order_index++;
00677 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00678 }
00679 } else {
00680 this->cur_real_order_index = 0;
00681 }
00682 }
00683
00689 inline Order *GetOrder(int index) const
00690 {
00691 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00692 }
00693
00698 inline Order *GetLastOrder() const
00699 {
00700 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00701 }
00702
00703 bool IsEngineCountable() const;
00704 bool HasEngineType() const;
00705 bool HasDepotOrder() const;
00706 void HandlePathfindingResult(bool path_found);
00707
00712 FORCEINLINE bool IsFrontEngine() const
00713 {
00714 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00715 }
00716
00721 FORCEINLINE bool IsArticulatedPart() const
00722 {
00723 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00724 }
00725
00730 FORCEINLINE bool HasArticulatedPart() const
00731 {
00732 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00733 }
00734
00740 FORCEINLINE Vehicle *GetNextArticulatedPart() const
00741 {
00742 assert(this->HasArticulatedPart());
00743 return this->Next();
00744 }
00745
00750 FORCEINLINE Vehicle *GetFirstEnginePart()
00751 {
00752 Vehicle *v = this;
00753 while (v->IsArticulatedPart()) v = v->Previous();
00754 return v;
00755 }
00756
00761 FORCEINLINE const Vehicle *GetFirstEnginePart() const
00762 {
00763 const Vehicle *v = this;
00764 while (v->IsArticulatedPart()) v = v->Previous();
00765 return v;
00766 }
00767
00772 FORCEINLINE Vehicle *GetLastEnginePart()
00773 {
00774 Vehicle *v = this;
00775 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00776 return v;
00777 }
00778
00783 FORCEINLINE Vehicle *GetNextVehicle() const
00784 {
00785 const Vehicle *v = this;
00786 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00787
00788
00789 return v->Next();
00790 }
00791
00796 FORCEINLINE Vehicle *GetPrevVehicle() const
00797 {
00798 Vehicle *v = this->Previous();
00799 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00800
00801 return v;
00802 }
00803 };
00804
00810 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00811
00816 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00817
00822 template <class T, VehicleType Type>
00823 struct SpecializedVehicle : public Vehicle {
00824 static const VehicleType EXPECTED_TYPE = Type;
00825
00826 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00827
00831 FORCEINLINE SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00832
00837 FORCEINLINE T *First() const { return (T *)this->Vehicle::First(); }
00838
00843 FORCEINLINE T *Last() { return (T *)this->Vehicle::Last(); }
00844
00849 FORCEINLINE const T *Last() const { return (const T *)this->Vehicle::Last(); }
00850
00855 FORCEINLINE T *Next() const { return (T *)this->Vehicle::Next(); }
00856
00861 FORCEINLINE T *Previous() const { return (T *)this->Vehicle::Previous(); }
00862
00868 FORCEINLINE T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00869
00875 FORCEINLINE T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00876
00881 FORCEINLINE T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00882
00887 FORCEINLINE const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00888
00893 FORCEINLINE T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00894
00899 FORCEINLINE T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00900
00905 FORCEINLINE T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00906
00912 static FORCEINLINE bool IsValidID(size_t index)
00913 {
00914 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00915 }
00916
00921 static FORCEINLINE T *Get(size_t index)
00922 {
00923 return (T *)Vehicle::Get(index);
00924 }
00925
00930 static FORCEINLINE T *GetIfValid(size_t index)
00931 {
00932 return IsValidID(index) ? Get(index) : NULL;
00933 }
00934
00940 static FORCEINLINE T *From(Vehicle *v)
00941 {
00942 assert(v->type == Type);
00943 return (T *)v;
00944 }
00945
00951 static FORCEINLINE const T *From(const Vehicle *v)
00952 {
00953 assert(v->type == Type);
00954 return (const T *)v;
00955 }
00956
00962 FORCEINLINE void UpdateViewport(bool moved, bool turned)
00963 {
00964 extern void VehicleMove(Vehicle *v, bool update_viewport);
00965
00966
00967
00968 if (turned) ((T *)this)->T::UpdateDeltaXY(this->direction);
00969 SpriteID old_image = this->cur_image;
00970 this->cur_image = ((T *)this)->T::GetImage(this->direction);
00971 if (moved || this->cur_image != old_image) VehicleMove(this, true);
00972 }
00973 };
00974
00980 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
00981
00985 struct DisasterVehicle : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
00986 SpriteID image_override;
00987 VehicleID big_ufo_destroyer_target;
00988
00990 DisasterVehicle() : SpecializedVehicleBase() {}
00992 virtual ~DisasterVehicle() {}
00993
00994 void UpdateDeltaXY(Direction direction);
00995 bool Tick();
00996 };
00997
01002 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01003
01005 struct FreeUnitIDGenerator {
01006 bool *cache;
01007 UnitID maxid;
01008 UnitID curid;
01009
01010 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01011 UnitID NextID();
01012
01014 ~FreeUnitIDGenerator() { free(this->cache); }
01015 };
01016
01018 static const int32 INVALID_COORD = 0x7fffffff;
01019
01020 #endif