00001
00002
00003
00004
00005
00006
00007
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
00028 enum VehStatus {
00029 VS_HIDDEN = 0x01,
00030 VS_STOPPED = 0x02,
00031 VS_UNCLICKABLE = 0x04,
00032 VS_DEFPAL = 0x08,
00033 VS_TRAIN_SLOWING = 0x10,
00034 VS_SHADOW = 0x20,
00035 VS_AIRCRAFT_BROKEN = 0x40,
00036 VS_CRASHED = 0x80,
00037 };
00038
00040 enum VehicleFlags {
00041 VF_LOADING_FINISHED,
00042 VF_CARGO_UNLOADING,
00043 VF_BUILT_AS_PROTOTYPE,
00044 VF_TIMETABLE_STARTED,
00045 VF_AUTOFILL_TIMETABLE,
00046 VF_AUTOFILL_PRES_WAIT_TIME,
00047 VF_STOP_LOADING,
00048 VF_PATHFINDER_LOST,
00049 };
00050
00052 enum NewGRFCacheValidValues {
00053 NCVV_POSITION_CONSIST_LENGTH = 0,
00054 NCVV_POSITION_SAME_ID_LENGTH = 1,
00055 NCVV_CONSIST_CARGO_INFORMATION = 2,
00056 NCVV_COMPANY_INFORMATION = 3,
00057 NCVV_END,
00058 };
00059
00061 struct NewGRFCache {
00062
00063 uint32 position_consist_length;
00064 uint32 position_same_id_length;
00065 uint32 consist_cargo_information;
00066 uint32 company_information;
00067 uint8 cache_valid;
00068 };
00069
00071 enum VisualEffect {
00072 VE_OFFSET_START = 0,
00073 VE_OFFSET_COUNT = 4,
00074 VE_OFFSET_CENTRE = 8,
00075
00076 VE_TYPE_START = 4,
00077 VE_TYPE_COUNT = 2,
00078 VE_TYPE_DEFAULT = 0,
00079 VE_TYPE_STEAM = 1,
00080 VE_TYPE_DIESEL = 2,
00081 VE_TYPE_ELECTRIC = 3,
00082
00083 VE_DISABLE_EFFECT = 6,
00084 VE_DISABLE_WAGON_POWER = 7,
00085
00086 VE_DEFAULT = 0xFF,
00087 };
00088
00094 enum GroundVehicleSubtypeFlags {
00095 GVSF_FRONT = 0,
00096 GVSF_ARTICULATED_PART = 1,
00097 GVSF_WAGON = 2,
00098 GVSF_ENGINE = 3,
00099 GVSF_FREE_WAGON = 4,
00100 GVSF_MULTIHEADED = 5,
00101 };
00102
00104 struct VehicleCache {
00105 uint16 cached_max_speed;
00106 uint16 cached_cargo_age_period;
00107
00108 byte cached_vis_effect;
00109 };
00110
00112 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00113 extern VehiclePool _vehicle_pool;
00114
00115
00116 struct SaveLoad;
00117 struct GroundVehicleCache;
00118 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00119 struct LoadgameState;
00120 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00121 extern void FixOldVehicles();
00122
00123 struct GRFFile;
00124
00126 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
00127 private:
00128 Vehicle *next;
00129 Vehicle *previous;
00130 Vehicle *first;
00131
00132 Vehicle *next_shared;
00133 Vehicle *previous_shared;
00134 public:
00135 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00136 friend void FixOldVehicles();
00137 friend void AfterLoadVehicles(bool part_of_load);
00138 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00139
00140 TileIndex tile;
00141
00147 TileIndex dest_tile;
00148
00149 Money profit_this_year;
00150 Money profit_last_year;
00151 Money value;
00152
00153 CargoPayment *cargo_payment;
00154
00155 Rect coord;
00156
00157 Vehicle *hash_viewport_next;
00158 Vehicle **hash_viewport_prev;
00159
00160 Vehicle *hash_tile_next;
00161 Vehicle **hash_tile_prev;
00162 Vehicle **hash_tile_current;
00163
00164 SpriteID colourmap;
00165
00166
00167 Year build_year;
00168 Date age;
00169 Date max_age;
00170 Date date_of_last_service;
00171 uint16 reliability;
00172 uint16 reliability_spd_dec;
00173 byte breakdown_ctr;
00174 byte breakdown_delay;
00175 byte breakdowns_since_last_service;
00176 byte breakdown_chance;
00177
00178 int32 x_pos;
00179 int32 y_pos;
00180 int32 z_pos;
00181 DirectionByte direction;
00182
00183 OwnerByte owner;
00184
00189 byte spritenum;
00190 SpriteID cur_image;
00191 byte x_extent;
00192 byte y_extent;
00193 byte z_extent;
00194 int8 x_bb_offs;
00195 int8 y_bb_offs;
00196 int8 x_offs;
00197 int8 y_offs;
00198 EngineID engine_type;
00199
00200 TextEffectID fill_percent_te_id;
00201 UnitID unitnumber;
00202
00203 uint16 cur_speed;
00204 byte subspeed;
00205 byte acceleration;
00206 uint32 motion_counter;
00207 byte progress;
00208
00209 byte random_bits;
00210 byte waiting_triggers;
00211
00212 StationID last_station_visited;
00213 StationID last_loading_station;
00214
00215 CargoID cargo_type;
00216 byte cargo_subtype;
00217 uint16 cargo_cap;
00218 uint16 refit_cap;
00219 VehicleCargoList cargo;
00220 uint16 cargo_age_counter;
00221
00222 byte day_counter;
00223 byte tick_counter;
00224 byte running_ticks;
00225
00226 byte vehstatus;
00227 Order current_order;
00228
00229 union {
00230 OrderList *list;
00231 Order *old;
00232 } orders;
00233
00234 uint16 load_unload_ticks;
00235 GroupID group_id;
00236 byte subtype;
00237
00238 NewGRFCache grf_cache;
00239 VehicleCache vcache;
00240
00241 Vehicle(VehicleType type = VEH_INVALID);
00242
00243 void PreDestructor();
00245 virtual ~Vehicle();
00246
00247 void BeginLoading();
00248 void CancelReservation(StationID next, Station *st);
00249 void LeaveStation();
00250
00251 GroundVehicleCache *GetGroundVehicleCache();
00252 const GroundVehicleCache *GetGroundVehicleCache() const;
00253
00254 uint16 &GetGroundVehicleFlags();
00255 const uint16 &GetGroundVehicleFlags() const;
00256
00257 void DeleteUnreachedImplicitOrders();
00258
00259 void HandleLoading(bool mode = false);
00260
00261 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
00262
00263 uint GetConsistTotalCapacity() const;
00264
00273 virtual void MarkDirty() {}
00274
00280 virtual void UpdateDeltaXY(Direction direction) {}
00281
00295 inline uint GetOldAdvanceSpeed(uint speed)
00296 {
00297 return (this->direction & 1) ? speed : speed * 3 / 4;
00298 }
00299
00312 static inline uint GetAdvanceSpeed(uint speed)
00313 {
00314 return speed * 3 / 4;
00315 }
00316
00324 inline uint GetAdvanceDistance()
00325 {
00326 return (this->direction & 1) ? 192 : 256;
00327 }
00328
00333 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00334
00338 virtual void PlayLeaveStationSound() const {}
00339
00343 virtual bool IsPrimaryVehicle() const { return false; }
00344
00345 const Engine *GetEngine() const;
00346
00352 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00353
00354 const GRFFile *GetGRF() const;
00355 uint32 GetGRFID() const;
00356
00361 inline void InvalidateNewGRFCache()
00362 {
00363 this->grf_cache.cache_valid = 0;
00364 }
00365
00370 inline void InvalidateNewGRFCacheOfChain()
00371 {
00372 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00373 u->InvalidateNewGRFCache();
00374 }
00375 }
00376
00381 inline bool IsGroundVehicle() const
00382 {
00383 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00384 }
00385
00390 virtual int GetDisplaySpeed() const { return 0; }
00391
00396 virtual int GetDisplayMaxSpeed() const { return 0; }
00397
00402 virtual int GetCurrentMaxSpeed() const { return 0; }
00403
00408 virtual Money GetRunningCost() const { return 0; }
00409
00414 virtual bool IsInDepot() const { return false; }
00415
00420 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00421
00426 bool IsStoppedInDepot() const
00427 {
00428 assert(this == this->First());
00429
00430 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00431 return this->IsChainInDepot();
00432 }
00433
00438 virtual bool Tick() { return true; };
00439
00443 virtual void OnNewDay() {};
00444
00450 virtual uint Crash(bool flooded = false);
00451
00464 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00465
00470 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00471
00476 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00477
00482 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00483
00484 void SetNext(Vehicle *next);
00485
00491 inline Vehicle *Next() const { return this->next; }
00492
00498 inline Vehicle *Previous() const { return this->previous; }
00499
00504 inline Vehicle *First() const { return this->first; }
00505
00510 inline Vehicle *Last()
00511 {
00512 Vehicle *v = this;
00513 while (v->Next() != NULL) v = v->Next();
00514 return v;
00515 }
00516
00521 inline const Vehicle *Last() const
00522 {
00523 const Vehicle *v = this;
00524 while (v->Next() != NULL) v = v->Next();
00525 return v;
00526 }
00527
00533 inline Vehicle *Move(int n)
00534 {
00535 Vehicle *v = this;
00536 if (n < 0) {
00537 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00538 } else {
00539 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00540 }
00541 return v;
00542 }
00543
00549 inline const Vehicle *Move(int n) const
00550 {
00551 const Vehicle *v = this;
00552 if (n < 0) {
00553 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00554 } else {
00555 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00556 }
00557 return v;
00558 }
00559
00564 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00565
00566 void AddToShared(Vehicle *shared_chain);
00567 void RemoveFromShared();
00568
00573 inline Vehicle *NextShared() const { return this->next_shared; }
00574
00579 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00580
00585 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00586
00591 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00592
00597 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00598
00603 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00604
00609 inline StationID GetNextStoppingStation() const
00610 {
00611 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
00612 }
00613
00614 void RefreshNextHopsStats();
00615
00622 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00623 {
00624 this->CopyConsistPropertiesFrom(src);
00625
00626 this->unitnumber = src->unitnumber;
00627
00628 this->current_order = src->current_order;
00629 this->dest_tile = src->dest_tile;
00630
00631 this->profit_this_year = src->profit_this_year;
00632 this->profit_last_year = src->profit_last_year;
00633 }
00634
00635
00636 bool HandleBreakdown();
00637
00638 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
00639
00640 bool NeedsServicing() const;
00641 bool NeedsAutomaticServicing() const;
00642
00650 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00651
00660 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00661
00662 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00663
00664 void UpdateVisualEffect(bool allow_power_change = true);
00665 void ShowVisualEffect() const;
00666
00667 private:
00672 void SkipToNextRealOrderIndex()
00673 {
00674 if (this->GetNumManualOrders() > 0) {
00675
00676 do {
00677 this->cur_real_order_index++;
00678 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00679 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00680 } else {
00681 this->cur_real_order_index = 0;
00682 }
00683 }
00684
00685 public:
00691 void IncrementImplicitOrderIndex()
00692 {
00693 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00694
00695 this->SkipToNextRealOrderIndex();
00696 }
00697
00698 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00699
00700
00701 do {
00702 this->cur_implicit_order_index++;
00703 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00704 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00705
00706 InvalidateVehicleOrder(this, 0);
00707 }
00708
00715 void IncrementRealOrderIndex()
00716 {
00717 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00718
00719 this->IncrementImplicitOrderIndex();
00720 } else {
00721
00722 this->SkipToNextRealOrderIndex();
00723 InvalidateVehicleOrder(this, 0);
00724 }
00725 }
00726
00730 void UpdateRealOrderIndex()
00731 {
00732
00733 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00734
00735 if (this->GetNumManualOrders() > 0) {
00736
00737 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00738 this->cur_real_order_index++;
00739 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00740 }
00741 } else {
00742 this->cur_real_order_index = 0;
00743 }
00744 }
00745
00751 inline Order *GetOrder(int index) const
00752 {
00753 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00754 }
00755
00760 inline Order *GetLastOrder() const
00761 {
00762 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00763 }
00764
00765 bool IsEngineCountable() const;
00766 bool HasEngineType() const;
00767 bool HasDepotOrder() const;
00768 void HandlePathfindingResult(bool path_found);
00769
00774 inline bool IsFrontEngine() const
00775 {
00776 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00777 }
00778
00783 inline bool IsArticulatedPart() const
00784 {
00785 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00786 }
00787
00792 inline bool HasArticulatedPart() const
00793 {
00794 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00795 }
00796
00802 inline Vehicle *GetNextArticulatedPart() const
00803 {
00804 assert(this->HasArticulatedPart());
00805 return this->Next();
00806 }
00807
00812 inline Vehicle *GetFirstEnginePart()
00813 {
00814 Vehicle *v = this;
00815 while (v->IsArticulatedPart()) v = v->Previous();
00816 return v;
00817 }
00818
00823 inline const Vehicle *GetFirstEnginePart() const
00824 {
00825 const Vehicle *v = this;
00826 while (v->IsArticulatedPart()) v = v->Previous();
00827 return v;
00828 }
00829
00834 inline Vehicle *GetLastEnginePart()
00835 {
00836 Vehicle *v = this;
00837 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00838 return v;
00839 }
00840
00845 inline Vehicle *GetNextVehicle() const
00846 {
00847 const Vehicle *v = this;
00848 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00849
00850
00851 return v->Next();
00852 }
00853
00858 inline Vehicle *GetPrevVehicle() const
00859 {
00860 Vehicle *v = this->Previous();
00861 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00862
00863 return v;
00864 }
00865 };
00866
00872 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00873
00878 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00879
00884 template <class T, VehicleType Type>
00885 struct SpecializedVehicle : public Vehicle {
00886 static const VehicleType EXPECTED_TYPE = Type;
00887
00888 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00889
00893 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00894
00899 inline T *First() const { return (T *)this->Vehicle::First(); }
00900
00905 inline T *Last() { return (T *)this->Vehicle::Last(); }
00906
00911 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00912
00917 inline T *Next() const { return (T *)this->Vehicle::Next(); }
00918
00923 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00924
00930 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00931
00937 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00938
00943 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00944
00949 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00950
00955 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00956
00961 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00962
00967 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00968
00974 static inline bool IsValidID(size_t index)
00975 {
00976 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00977 }
00978
00983 static inline T *Get(size_t index)
00984 {
00985 return (T *)Vehicle::Get(index);
00986 }
00987
00992 static inline T *GetIfValid(size_t index)
00993 {
00994 return IsValidID(index) ? Get(index) : NULL;
00995 }
00996
01002 static inline T *From(Vehicle *v)
01003 {
01004 assert(v->type == Type);
01005 return (T *)v;
01006 }
01007
01013 static inline const T *From(const Vehicle *v)
01014 {
01015 assert(v->type == Type);
01016 return (const T *)v;
01017 }
01018
01024 inline void UpdateViewport(bool force_update, bool update_delta)
01025 {
01026 extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
01027
01028
01029
01030 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
01031 SpriteID old_image = this->cur_image;
01032 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
01033 if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
01034 }
01035 };
01036
01042 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01043
01047 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01048 SpriteID image_override;
01049 VehicleID big_ufo_destroyer_target;
01050
01052 DisasterVehicle() : SpecializedVehicleBase() {}
01054 virtual ~DisasterVehicle() {}
01055
01056 void UpdateDeltaXY(Direction direction);
01057 bool Tick();
01058 };
01059
01064 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01065
01067 struct FreeUnitIDGenerator {
01068 bool *cache;
01069 UnitID maxid;
01070 UnitID curid;
01071
01072 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01073 UnitID NextID();
01074
01076 ~FreeUnitIDGenerator() { free(this->cache); }
01077 };
01078
01080 static const int32 INVALID_COORD = 0x7fffffff;
01081
01082 #endif