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 VF_SERVINT_IS_CUSTOM,
00050 VF_SERVINT_IS_PERCENT,
00051 };
00052
00054 enum NewGRFCacheValidValues {
00055 NCVV_POSITION_CONSIST_LENGTH = 0,
00056 NCVV_POSITION_SAME_ID_LENGTH = 1,
00057 NCVV_CONSIST_CARGO_INFORMATION = 2,
00058 NCVV_COMPANY_INFORMATION = 3,
00059 NCVV_END,
00060 };
00061
00063 struct NewGRFCache {
00064
00065 uint32 position_consist_length;
00066 uint32 position_same_id_length;
00067 uint32 consist_cargo_information;
00068 uint32 company_information;
00069 uint8 cache_valid;
00070 };
00071
00073 enum VisualEffect {
00074 VE_OFFSET_START = 0,
00075 VE_OFFSET_COUNT = 4,
00076 VE_OFFSET_CENTRE = 8,
00077
00078 VE_TYPE_START = 4,
00079 VE_TYPE_COUNT = 2,
00080 VE_TYPE_DEFAULT = 0,
00081 VE_TYPE_STEAM = 1,
00082 VE_TYPE_DIESEL = 2,
00083 VE_TYPE_ELECTRIC = 3,
00084
00085 VE_DISABLE_EFFECT = 6,
00086 VE_DISABLE_WAGON_POWER = 7,
00087
00088 VE_DEFAULT = 0xFF,
00089 };
00090
00096 enum GroundVehicleSubtypeFlags {
00097 GVSF_FRONT = 0,
00098 GVSF_ARTICULATED_PART = 1,
00099 GVSF_WAGON = 2,
00100 GVSF_ENGINE = 3,
00101 GVSF_FREE_WAGON = 4,
00102 GVSF_MULTIHEADED = 5,
00103 };
00104
00106 struct VehicleCache {
00107 uint16 cached_max_speed;
00108 uint16 cached_cargo_age_period;
00109
00110 byte cached_vis_effect;
00111 };
00112
00114 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00115 extern VehiclePool _vehicle_pool;
00116
00117
00118 struct SaveLoad;
00119 struct GroundVehicleCache;
00120 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00121 struct LoadgameState;
00122 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00123 extern void FixOldVehicles();
00124
00125 struct GRFFile;
00126
00128 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle, BaseConsist {
00129 private:
00130 Vehicle *next;
00131 Vehicle *previous;
00132 Vehicle *first;
00133
00134 Vehicle *next_shared;
00135 Vehicle *previous_shared;
00136 public:
00137 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00138 friend void FixOldVehicles();
00139 friend void AfterLoadVehicles(bool part_of_load);
00140 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00141
00142 TileIndex tile;
00143
00149 TileIndex dest_tile;
00150
00151 Money profit_this_year;
00152 Money profit_last_year;
00153 Money value;
00154
00155 CargoPayment *cargo_payment;
00156
00157 Rect coord;
00158
00159 Vehicle *hash_viewport_next;
00160 Vehicle **hash_viewport_prev;
00161
00162 Vehicle *hash_tile_next;
00163 Vehicle **hash_tile_prev;
00164 Vehicle **hash_tile_current;
00165
00166 SpriteID colourmap;
00167
00168
00169 Year build_year;
00170 Date age;
00171 Date max_age;
00172 Date date_of_last_service;
00173 uint16 reliability;
00174 uint16 reliability_spd_dec;
00175 byte breakdown_ctr;
00176 byte breakdown_delay;
00177 byte breakdowns_since_last_service;
00178 byte breakdown_chance;
00179
00180 int32 x_pos;
00181 int32 y_pos;
00182 int32 z_pos;
00183 DirectionByte direction;
00184
00185 OwnerByte owner;
00186
00191 byte spritenum;
00192 SpriteID cur_image;
00193 byte x_extent;
00194 byte y_extent;
00195 byte z_extent;
00196 int8 x_bb_offs;
00197 int8 y_bb_offs;
00198 int8 x_offs;
00199 int8 y_offs;
00200 EngineID engine_type;
00201
00202 TextEffectID fill_percent_te_id;
00203 UnitID unitnumber;
00204
00205 uint16 cur_speed;
00206 byte subspeed;
00207 byte acceleration;
00208 uint32 motion_counter;
00209 byte progress;
00210
00211 byte random_bits;
00212 byte waiting_triggers;
00213
00214 StationID last_station_visited;
00215 StationID last_loading_station;
00216
00217 CargoID cargo_type;
00218 byte cargo_subtype;
00219 uint16 cargo_cap;
00220 uint16 refit_cap;
00221 VehicleCargoList cargo;
00222 uint16 cargo_age_counter;
00223
00224 byte day_counter;
00225 byte tick_counter;
00226 byte running_ticks;
00227
00228 byte vehstatus;
00229 Order current_order;
00230
00231 union {
00232 OrderList *list;
00233 Order *old;
00234 } orders;
00235
00236 uint16 load_unload_ticks;
00237 GroupID group_id;
00238 byte subtype;
00239
00240 NewGRFCache grf_cache;
00241 VehicleCache vcache;
00242
00243 Vehicle(VehicleType type = VEH_INVALID);
00244
00245 void PreDestructor();
00247 virtual ~Vehicle();
00248
00249 void BeginLoading();
00250 void CancelReservation(StationID next, Station *st);
00251 void LeaveStation();
00252
00253 GroundVehicleCache *GetGroundVehicleCache();
00254 const GroundVehicleCache *GetGroundVehicleCache() const;
00255
00256 uint16 &GetGroundVehicleFlags();
00257 const uint16 &GetGroundVehicleFlags() const;
00258
00259 void DeleteUnreachedImplicitOrders();
00260
00261 void HandleLoading(bool mode = false);
00262
00263 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
00264
00265 uint GetConsistTotalCapacity() const;
00266
00275 virtual void MarkDirty() {}
00276
00282 virtual void UpdateDeltaXY(Direction direction) {}
00283
00297 inline uint GetOldAdvanceSpeed(uint speed)
00298 {
00299 return (this->direction & 1) ? speed : speed * 3 / 4;
00300 }
00301
00314 static inline uint GetAdvanceSpeed(uint speed)
00315 {
00316 return speed * 3 / 4;
00317 }
00318
00326 inline uint GetAdvanceDistance()
00327 {
00328 return (this->direction & 1) ? 192 : 256;
00329 }
00330
00335 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00336
00340 virtual void PlayLeaveStationSound() const {}
00341
00345 virtual bool IsPrimaryVehicle() const { return false; }
00346
00347 const Engine *GetEngine() const;
00348
00354 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00355
00356 const GRFFile *GetGRF() const;
00357 uint32 GetGRFID() const;
00358
00363 inline void InvalidateNewGRFCache()
00364 {
00365 this->grf_cache.cache_valid = 0;
00366 }
00367
00372 inline void InvalidateNewGRFCacheOfChain()
00373 {
00374 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00375 u->InvalidateNewGRFCache();
00376 }
00377 }
00378
00383 inline bool IsGroundVehicle() const
00384 {
00385 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00386 }
00387
00392 virtual int GetDisplaySpeed() const { return 0; }
00393
00398 virtual int GetDisplayMaxSpeed() const { return 0; }
00399
00404 virtual int GetCurrentMaxSpeed() const { return 0; }
00405
00410 virtual Money GetRunningCost() const { return 0; }
00411
00416 virtual bool IsInDepot() const { return false; }
00417
00422 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00423
00428 bool IsStoppedInDepot() const
00429 {
00430 assert(this == this->First());
00431
00432 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00433 return this->IsChainInDepot();
00434 }
00435
00440 virtual bool Tick() { return true; };
00441
00445 virtual void OnNewDay() {};
00446
00452 virtual uint Crash(bool flooded = false);
00453
00466 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00467
00472 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00473
00478 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00479
00484 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00485
00486 void SetNext(Vehicle *next);
00487
00493 inline Vehicle *Next() const { return this->next; }
00494
00500 inline Vehicle *Previous() const { return this->previous; }
00501
00506 inline Vehicle *First() const { return this->first; }
00507
00512 inline Vehicle *Last()
00513 {
00514 Vehicle *v = this;
00515 while (v->Next() != NULL) v = v->Next();
00516 return v;
00517 }
00518
00523 inline const Vehicle *Last() const
00524 {
00525 const Vehicle *v = this;
00526 while (v->Next() != NULL) v = v->Next();
00527 return v;
00528 }
00529
00535 inline Vehicle *Move(int n)
00536 {
00537 Vehicle *v = this;
00538 if (n < 0) {
00539 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00540 } else {
00541 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00542 }
00543 return v;
00544 }
00545
00551 inline const Vehicle *Move(int n) const
00552 {
00553 const Vehicle *v = this;
00554 if (n < 0) {
00555 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00556 } else {
00557 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00558 }
00559 return v;
00560 }
00561
00566 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00567
00568 void AddToShared(Vehicle *shared_chain);
00569 void RemoveFromShared();
00570
00575 inline Vehicle *NextShared() const { return this->next_shared; }
00576
00581 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00582
00587 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00588
00593 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00594
00599 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00600
00605 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00606
00611 inline StationID GetNextStoppingStation() const
00612 {
00613 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
00614 }
00615
00616 void ResetRefitCaps();
00617
00618 void RefreshNextHopsStats();
00619
00626 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00627 {
00628 this->CopyConsistPropertiesFrom(src);
00629
00630 this->unitnumber = src->unitnumber;
00631
00632 this->current_order = src->current_order;
00633 this->dest_tile = src->dest_tile;
00634
00635 this->profit_this_year = src->profit_this_year;
00636 this->profit_last_year = src->profit_last_year;
00637 }
00638
00639
00640 bool HandleBreakdown();
00641
00642 bool NeedsAutorenewing(const Company *c, bool use_renew_setting = true) const;
00643
00644 bool NeedsServicing() const;
00645 bool NeedsAutomaticServicing() const;
00646
00654 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00655
00664 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00665
00666 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00667
00668 void UpdateVisualEffect(bool allow_power_change = true);
00669 void ShowVisualEffect() const;
00670
00671 inline uint16 GetServiceInterval() const { return this->service_interval; }
00672
00673 inline void SetServiceInterval(uint16 interval) { this->service_interval = interval; }
00674
00675 inline bool ServiceIntervalIsCustom() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_CUSTOM); }
00676
00677 inline bool ServiceIntervalIsPercent() const { return HasBit(this->vehicle_flags, VF_SERVINT_IS_PERCENT); }
00678
00679 inline void SetServiceIntervalIsCustom(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_CUSTOM, 1, on); }
00680
00681 inline void SetServiceIntervalIsPercent(bool on) { SB(this->vehicle_flags, VF_SERVINT_IS_PERCENT, 1, on); }
00682
00683 private:
00688 void SkipToNextRealOrderIndex()
00689 {
00690 if (this->GetNumManualOrders() > 0) {
00691
00692 do {
00693 this->cur_real_order_index++;
00694 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00695 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00696 } else {
00697 this->cur_real_order_index = 0;
00698 }
00699 }
00700
00701 public:
00707 void IncrementImplicitOrderIndex()
00708 {
00709 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00710
00711 this->SkipToNextRealOrderIndex();
00712 }
00713
00714 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00715
00716
00717 do {
00718 this->cur_implicit_order_index++;
00719 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00720 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00721
00722 InvalidateVehicleOrder(this, 0);
00723 }
00724
00731 void IncrementRealOrderIndex()
00732 {
00733 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00734
00735 this->IncrementImplicitOrderIndex();
00736 } else {
00737
00738 this->SkipToNextRealOrderIndex();
00739 InvalidateVehicleOrder(this, 0);
00740 }
00741 }
00742
00746 void UpdateRealOrderIndex()
00747 {
00748
00749 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00750
00751 if (this->GetNumManualOrders() > 0) {
00752
00753 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00754 this->cur_real_order_index++;
00755 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00756 }
00757 } else {
00758 this->cur_real_order_index = 0;
00759 }
00760 }
00761
00767 inline Order *GetOrder(int index) const
00768 {
00769 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00770 }
00771
00776 inline Order *GetLastOrder() const
00777 {
00778 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00779 }
00780
00781 bool IsEngineCountable() const;
00782 bool HasEngineType() const;
00783 bool HasDepotOrder() const;
00784 void HandlePathfindingResult(bool path_found);
00785
00790 inline bool IsFrontEngine() const
00791 {
00792 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00793 }
00794
00799 inline bool IsArticulatedPart() const
00800 {
00801 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00802 }
00803
00808 inline bool HasArticulatedPart() const
00809 {
00810 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00811 }
00812
00818 inline Vehicle *GetNextArticulatedPart() const
00819 {
00820 assert(this->HasArticulatedPart());
00821 return this->Next();
00822 }
00823
00828 inline Vehicle *GetFirstEnginePart()
00829 {
00830 Vehicle *v = this;
00831 while (v->IsArticulatedPart()) v = v->Previous();
00832 return v;
00833 }
00834
00839 inline const Vehicle *GetFirstEnginePart() const
00840 {
00841 const Vehicle *v = this;
00842 while (v->IsArticulatedPart()) v = v->Previous();
00843 return v;
00844 }
00845
00850 inline Vehicle *GetLastEnginePart()
00851 {
00852 Vehicle *v = this;
00853 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00854 return v;
00855 }
00856
00861 inline Vehicle *GetNextVehicle() const
00862 {
00863 const Vehicle *v = this;
00864 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00865
00866
00867 return v->Next();
00868 }
00869
00874 inline Vehicle *GetPrevVehicle() const
00875 {
00876 Vehicle *v = this->Previous();
00877 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00878
00879 return v;
00880 }
00881 };
00882
00888 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00889
00894 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00895
00900 template <class T, VehicleType Type>
00901 struct SpecializedVehicle : public Vehicle {
00902 static const VehicleType EXPECTED_TYPE = Type;
00903
00904 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00905
00909 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00910
00915 inline T *First() const { return (T *)this->Vehicle::First(); }
00916
00921 inline T *Last() { return (T *)this->Vehicle::Last(); }
00922
00927 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00928
00933 inline T *Next() const { return (T *)this->Vehicle::Next(); }
00934
00939 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00940
00946 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00947
00953 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00954
00959 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00960
00965 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00966
00971 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00972
00977 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00978
00983 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00984
00990 static inline bool IsValidID(size_t index)
00991 {
00992 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00993 }
00994
00999 static inline T *Get(size_t index)
01000 {
01001 return (T *)Vehicle::Get(index);
01002 }
01003
01008 static inline T *GetIfValid(size_t index)
01009 {
01010 return IsValidID(index) ? Get(index) : NULL;
01011 }
01012
01018 static inline T *From(Vehicle *v)
01019 {
01020 assert(v->type == Type);
01021 return (T *)v;
01022 }
01023
01029 static inline const T *From(const Vehicle *v)
01030 {
01031 assert(v->type == Type);
01032 return (const T *)v;
01033 }
01034
01040 inline void UpdateViewport(bool force_update, bool update_delta)
01041 {
01042 extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
01043
01044
01045
01046 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
01047 SpriteID old_image = this->cur_image;
01048 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
01049 if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
01050 }
01051 };
01052
01058 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01059
01063 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01064 SpriteID image_override;
01065 VehicleID big_ufo_destroyer_target;
01066
01068 DisasterVehicle() : SpecializedVehicleBase() {}
01070 virtual ~DisasterVehicle() {}
01071
01072 void UpdateDeltaXY(Direction direction);
01073 bool Tick();
01074 };
01075
01080 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01081
01083 struct FreeUnitIDGenerator {
01084 bool *cache;
01085 UnitID maxid;
01086 UnitID curid;
01087
01088 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01089 UnitID NextID();
01090
01092 ~FreeUnitIDGenerator() { free(this->cache); }
01093 };
01094
01096 static const int32 INVALID_COORD = 0x7fffffff;
01097
01098 #endif