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
00135 public:
00136 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00137 friend void FixOldVehicles();
00138 friend void AfterLoadVehicles(bool part_of_load);
00139 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00140
00141 TileIndex tile;
00142
00148 TileIndex dest_tile;
00149
00150 Money profit_this_year;
00151 Money profit_last_year;
00152 Money value;
00153
00154 CargoPayment *cargo_payment;
00155
00156 Rect coord;
00157
00158 Vehicle *hash_viewport_next;
00159 Vehicle **hash_viewport_prev;
00160
00161 Vehicle *hash_tile_next;
00162 Vehicle **hash_tile_prev;
00163 Vehicle **hash_tile_current;
00164
00165 SpriteID colourmap;
00166
00167
00168 Year build_year;
00169 Date age;
00170 Date max_age;
00171 Date date_of_last_service;
00172 uint16 reliability;
00173 uint16 reliability_spd_dec;
00174 byte breakdown_ctr;
00175 byte breakdown_delay;
00176 byte breakdowns_since_last_service;
00177 byte breakdown_chance;
00178
00179 int32 x_pos;
00180 int32 y_pos;
00181 int32 z_pos;
00182 DirectionByte direction;
00183
00184 OwnerByte owner;
00185
00190 byte spritenum;
00191 SpriteID cur_image;
00192 byte x_extent;
00193 byte y_extent;
00194 byte z_extent;
00195 int8 x_bb_offs;
00196 int8 y_bb_offs;
00197 int8 x_offs;
00198 int8 y_offs;
00199 EngineID engine_type;
00200
00201 TextEffectID fill_percent_te_id;
00202 UnitID unitnumber;
00203
00204 uint16 cur_speed;
00205 byte subspeed;
00206 byte acceleration;
00207 uint32 motion_counter;
00208 byte progress;
00209
00210 byte random_bits;
00211 byte waiting_triggers;
00212
00213 StationID last_station_visited;
00214 StationID last_loading_station;
00215
00216 CargoID cargo_type;
00217 byte cargo_subtype;
00218 uint16 cargo_cap;
00219 uint16 refit_cap;
00220 VehicleCargoList cargo;
00221 uint16 cargo_age_counter;
00222
00223 byte day_counter;
00224 byte tick_counter;
00225 byte running_ticks;
00226
00227 byte vehstatus;
00228 Order current_order;
00229
00230 union {
00231 OrderList *list;
00232 Order *old;
00233 } orders;
00234
00235 uint16 load_unload_ticks;
00236 GroupID group_id;
00237 byte subtype;
00238
00239 NewGRFCache grf_cache;
00240 VehicleCache vcache;
00241
00242 Vehicle(VehicleType type = VEH_INVALID);
00243
00244 void PreDestructor();
00246 virtual ~Vehicle();
00247
00248 void BeginLoading();
00249 void CancelReservation(StationID next, Station *st);
00250 void LeaveStation();
00251
00252 GroundVehicleCache *GetGroundVehicleCache();
00253 const GroundVehicleCache *GetGroundVehicleCache() const;
00254
00255 uint16 &GetGroundVehicleFlags();
00256 const uint16 &GetGroundVehicleFlags() const;
00257
00258 void DeleteUnreachedImplicitOrders();
00259
00260 void HandleLoading(bool mode = false);
00261
00262 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
00263
00264 uint GetConsistTotalCapacity() const;
00265
00274 virtual void MarkDirty() {}
00275
00281 virtual void UpdateDeltaXY(Direction direction) {}
00282
00296 inline uint GetOldAdvanceSpeed(uint speed)
00297 {
00298 return (this->direction & 1) ? speed : speed * 3 / 4;
00299 }
00300
00313 static inline uint GetAdvanceSpeed(uint speed)
00314 {
00315 return speed * 3 / 4;
00316 }
00317
00325 inline uint GetAdvanceDistance()
00326 {
00327 return (this->direction & 1) ? 192 : 256;
00328 }
00329
00334 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00335
00339 virtual void PlayLeaveStationSound() const {}
00340
00344 virtual bool IsPrimaryVehicle() const { return false; }
00345
00346 const Engine *GetEngine() const;
00347
00353 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00354
00355 const GRFFile *GetGRF() const;
00356 uint32 GetGRFID() const;
00357
00362 inline void InvalidateNewGRFCache()
00363 {
00364 this->grf_cache.cache_valid = 0;
00365 }
00366
00371 inline void InvalidateNewGRFCacheOfChain()
00372 {
00373 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00374 u->InvalidateNewGRFCache();
00375 }
00376 }
00377
00382 inline bool IsGroundVehicle() const
00383 {
00384 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00385 }
00386
00391 virtual int GetDisplaySpeed() const { return 0; }
00392
00397 virtual int GetDisplayMaxSpeed() const { return 0; }
00398
00403 virtual int GetCurrentMaxSpeed() const { return 0; }
00404
00409 virtual Money GetRunningCost() const { return 0; }
00410
00415 virtual bool IsInDepot() const { return false; }
00416
00421 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00422
00427 bool IsStoppedInDepot() const
00428 {
00429 assert(this == this->First());
00430
00431 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00432 return this->IsChainInDepot();
00433 }
00434
00439 virtual bool Tick() { return true; };
00440
00444 virtual void OnNewDay() {};
00445
00451 virtual uint Crash(bool flooded = false);
00452
00465 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00466
00471 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00472
00477 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00478
00483 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00484
00485 void SetNext(Vehicle *next);
00486
00492 inline Vehicle *Next() const { return this->next; }
00493
00499 inline Vehicle *Previous() const { return this->previous; }
00500
00505 inline Vehicle *First() const { return this->first; }
00506
00511 inline Vehicle *Last()
00512 {
00513 Vehicle *v = this;
00514 while (v->Next() != NULL) v = v->Next();
00515 return v;
00516 }
00517
00522 inline const Vehicle *Last() const
00523 {
00524 const Vehicle *v = this;
00525 while (v->Next() != NULL) v = v->Next();
00526 return v;
00527 }
00528
00534 inline Vehicle *Move(int n)
00535 {
00536 Vehicle *v = this;
00537 if (n < 0) {
00538 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00539 } else {
00540 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00541 }
00542 return v;
00543 }
00544
00550 inline const Vehicle *Move(int n) const
00551 {
00552 const Vehicle *v = this;
00553 if (n < 0) {
00554 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00555 } else {
00556 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00557 }
00558 return v;
00559 }
00560
00565 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00566
00567 void AddToShared(Vehicle *shared_chain);
00568 void RemoveFromShared();
00569
00574 inline Vehicle *NextShared() const { return this->next_shared; }
00575
00580 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00581
00586 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00587
00592 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00593
00598 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00599
00604 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00605
00610 inline StationID GetNextStoppingStation() const
00611 {
00612 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
00613 }
00614
00615 void RefreshNextHopsStats();
00616
00623 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00624 {
00625 this->CopyConsistPropertiesFrom(src);
00626
00627 this->unitnumber = src->unitnumber;
00628
00629 this->current_order = src->current_order;
00630 this->dest_tile = src->dest_tile;
00631
00632 this->profit_this_year = src->profit_this_year;
00633 this->profit_last_year = src->profit_last_year;
00634 }
00635
00636
00637 bool HandleBreakdown();
00638
00639 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
00640
00641 bool NeedsServicing() const;
00642 bool NeedsAutomaticServicing() const;
00643
00651 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00652
00661 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00662
00663 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00664
00665 void UpdateVisualEffect(bool allow_power_change = true);
00666 void ShowVisualEffect() const;
00667
00668 private:
00673 void SkipToNextRealOrderIndex()
00674 {
00675 if (this->GetNumManualOrders() > 0) {
00676
00677 do {
00678 this->cur_real_order_index++;
00679 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00680 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00681 } else {
00682 this->cur_real_order_index = 0;
00683 }
00684 }
00685
00686 public:
00692 void IncrementImplicitOrderIndex()
00693 {
00694 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00695
00696 this->SkipToNextRealOrderIndex();
00697 }
00698
00699 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00700
00701
00702 do {
00703 this->cur_implicit_order_index++;
00704 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00705 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00706
00707 InvalidateVehicleOrder(this, 0);
00708 }
00709
00716 void IncrementRealOrderIndex()
00717 {
00718 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00719
00720 this->IncrementImplicitOrderIndex();
00721 } else {
00722
00723 this->SkipToNextRealOrderIndex();
00724 InvalidateVehicleOrder(this, 0);
00725 }
00726 }
00727
00731 void UpdateRealOrderIndex()
00732 {
00733
00734 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00735
00736 if (this->GetNumManualOrders() > 0) {
00737
00738 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00739 this->cur_real_order_index++;
00740 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00741 }
00742 } else {
00743 this->cur_real_order_index = 0;
00744 }
00745 }
00746
00752 inline Order *GetOrder(int index) const
00753 {
00754 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00755 }
00756
00761 inline Order *GetLastOrder() const
00762 {
00763 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00764 }
00765
00766 bool IsEngineCountable() const;
00767 bool HasEngineType() const;
00768 bool HasDepotOrder() const;
00769 void HandlePathfindingResult(bool path_found);
00770
00775 inline bool IsFrontEngine() const
00776 {
00777 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00778 }
00779
00784 inline bool IsArticulatedPart() const
00785 {
00786 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00787 }
00788
00793 inline bool HasArticulatedPart() const
00794 {
00795 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00796 }
00797
00803 inline Vehicle *GetNextArticulatedPart() const
00804 {
00805 assert(this->HasArticulatedPart());
00806 return this->Next();
00807 }
00808
00813 inline Vehicle *GetFirstEnginePart()
00814 {
00815 Vehicle *v = this;
00816 while (v->IsArticulatedPart()) v = v->Previous();
00817 return v;
00818 }
00819
00824 inline const Vehicle *GetFirstEnginePart() const
00825 {
00826 const Vehicle *v = this;
00827 while (v->IsArticulatedPart()) v = v->Previous();
00828 return v;
00829 }
00830
00835 inline Vehicle *GetLastEnginePart()
00836 {
00837 Vehicle *v = this;
00838 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00839 return v;
00840 }
00841
00846 inline Vehicle *GetNextVehicle() const
00847 {
00848 const Vehicle *v = this;
00849 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00850
00851
00852 return v->Next();
00853 }
00854
00859 inline Vehicle *GetPrevVehicle() const
00860 {
00861 Vehicle *v = this->Previous();
00862 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00863
00864 return v;
00865 }
00866 };
00867
00873 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00874
00879 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00880
00885 template <class T, VehicleType Type>
00886 struct SpecializedVehicle : public Vehicle {
00887 static const VehicleType EXPECTED_TYPE = Type;
00888
00889 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00890
00894 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00895
00900 inline T *First() const { return (T *)this->Vehicle::First(); }
00901
00906 inline T *Last() { return (T *)this->Vehicle::Last(); }
00907
00912 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00913
00918 inline T *Next() const { return (T *)this->Vehicle::Next(); }
00919
00924 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00925
00931 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00932
00938 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00939
00944 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00945
00950 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00951
00956 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00957
00962 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00963
00968 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00969
00975 static inline bool IsValidID(size_t index)
00976 {
00977 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00978 }
00979
00984 static inline T *Get(size_t index)
00985 {
00986 return (T *)Vehicle::Get(index);
00987 }
00988
00993 static inline T *GetIfValid(size_t index)
00994 {
00995 return IsValidID(index) ? Get(index) : NULL;
00996 }
00997
01003 static inline T *From(Vehicle *v)
01004 {
01005 assert(v->type == Type);
01006 return (T *)v;
01007 }
01008
01014 static inline const T *From(const Vehicle *v)
01015 {
01016 assert(v->type == Type);
01017 return (const T *)v;
01018 }
01019
01025 inline void UpdateViewport(bool force_update, bool update_delta)
01026 {
01027 extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
01028
01029
01030
01031 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
01032 SpriteID old_image = this->cur_image;
01033 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
01034 if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
01035 }
01036 };
01037
01043 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01044
01048 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01049 SpriteID image_override;
01050 VehicleID big_ufo_destroyer_target;
01051
01053 DisasterVehicle() : SpecializedVehicleBase() {}
01055 virtual ~DisasterVehicle() {}
01056
01057 void UpdateDeltaXY(Direction direction);
01058 bool Tick();
01059 };
01060
01065 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01066
01068 struct FreeUnitIDGenerator {
01069 bool *cache;
01070 UnitID maxid;
01071 UnitID curid;
01072
01073 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01074 UnitID NextID();
01075
01077 ~FreeUnitIDGenerator() { free(this->cache); }
01078 };
01079
01081 static const int32 INVALID_COORD = 0x7fffffff;
01082
01083 #endif