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 uint16 cached_cargo_age_period;
00105
00106 byte cached_vis_effect;
00107 };
00108
00110 typedef Pool<Vehicle, VehicleID, 512, 0xFF000> VehiclePool;
00111 extern VehiclePool _vehicle_pool;
00112
00113
00114 struct SaveLoad;
00115 struct GroundVehicleCache;
00116 extern const SaveLoad *GetVehicleDescription(VehicleType vt);
00117 struct LoadgameState;
00118 extern bool LoadOldVehicle(LoadgameState *ls, int num);
00119 extern void FixOldVehicles();
00120
00121 struct GRFFile;
00122
00124 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle {
00125 private:
00126 Vehicle *next;
00127 Vehicle *previous;
00128 Vehicle *first;
00129
00130 Vehicle *next_shared;
00131 Vehicle *previous_shared;
00132 public:
00133 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00134 friend void FixOldVehicles();
00135 friend void AfterLoadVehicles(bool part_of_load);
00136 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00137
00138 char *name;
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
00156 uint32 current_order_time;
00157 int32 lateness_counter;
00158 Date timetable_start;
00159
00160 Rect coord;
00161
00162 Vehicle *hash_viewport_next;
00163 Vehicle **hash_viewport_prev;
00164
00165 Vehicle *hash_tile_next;
00166 Vehicle **hash_tile_prev;
00167 Vehicle **hash_tile_current;
00168
00169 SpriteID colourmap;
00170
00171
00172 Year build_year;
00173 Date age;
00174 Date max_age;
00175 Date date_of_last_service;
00176 Date service_interval;
00177 uint16 reliability;
00178 uint16 reliability_spd_dec;
00179 byte breakdown_ctr;
00180 byte breakdown_delay;
00181 byte breakdowns_since_last_service;
00182 byte breakdown_chance;
00183
00184 int32 x_pos;
00185 int32 y_pos;
00186 int32 z_pos;
00187 DirectionByte direction;
00188
00189 OwnerByte owner;
00190
00195 byte spritenum;
00196 SpriteID cur_image;
00197 byte x_extent;
00198 byte y_extent;
00199 byte z_extent;
00200 int8 x_bb_offs;
00201 int8 y_bb_offs;
00202 int8 x_offs;
00203 int8 y_offs;
00204 EngineID engine_type;
00205
00206 TextEffectID fill_percent_te_id;
00207 UnitID unitnumber;
00208
00209 uint16 cur_speed;
00210 byte subspeed;
00211 byte acceleration;
00212 uint32 motion_counter;
00213 byte progress;
00214
00215 byte random_bits;
00216 byte waiting_triggers;
00217
00218 StationID last_station_visited;
00219
00220 CargoID cargo_type;
00221 byte cargo_subtype;
00222 uint16 cargo_cap;
00223 VehicleCargoList cargo;
00224 uint16 cargo_age_counter;
00225
00226 byte day_counter;
00227 byte tick_counter;
00228 byte running_ticks;
00229
00230 byte vehstatus;
00231 Order current_order;
00232 VehicleOrderID cur_real_order_index;
00233 VehicleOrderID cur_implicit_order_index;
00234
00235 union {
00236 OrderList *list;
00237 Order *old;
00238 } orders;
00239
00240 byte vehicle_flags;
00241
00242 uint16 load_unload_ticks;
00243 GroupID group_id;
00244 byte subtype;
00245
00246 NewGRFCache grf_cache;
00247 VehicleCache vcache;
00248
00249 Vehicle(VehicleType type = VEH_INVALID);
00250
00251 void PreDestructor();
00253 virtual ~Vehicle();
00254
00255 void BeginLoading();
00256 void LeaveStation();
00257
00258 GroundVehicleCache *GetGroundVehicleCache();
00259 const GroundVehicleCache *GetGroundVehicleCache() const;
00260
00261 uint16 &GetGroundVehicleFlags();
00262 const uint16 &GetGroundVehicleFlags() const;
00263
00264 void DeleteUnreachedImplicitOrders();
00265
00266 void HandleLoading(bool mode = false);
00267
00276 virtual void MarkDirty() {}
00277
00283 virtual void UpdateDeltaXY(Direction direction) {}
00284
00298 inline uint GetOldAdvanceSpeed(uint speed)
00299 {
00300 return (this->direction & 1) ? speed : speed * 3 / 4;
00301 }
00302
00315 static inline uint GetAdvanceSpeed(uint speed)
00316 {
00317 return speed * 3 / 4;
00318 }
00319
00327 inline uint GetAdvanceDistance()
00328 {
00329 return (this->direction & 1) ? 192 : 256;
00330 }
00331
00336 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00337
00341 virtual void PlayLeaveStationSound() const {}
00342
00346 virtual bool IsPrimaryVehicle() const { return false; }
00347
00348 const Engine *GetEngine() const;
00349
00355 virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; }
00356
00357 const GRFFile *GetGRF() const;
00358 uint32 GetGRFID() const;
00359
00364 inline void InvalidateNewGRFCache()
00365 {
00366 this->grf_cache.cache_valid = 0;
00367 }
00368
00373 inline void InvalidateNewGRFCacheOfChain()
00374 {
00375 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00376 u->InvalidateNewGRFCache();
00377 }
00378 }
00379
00384 inline bool IsGroundVehicle() const
00385 {
00386 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00387 }
00388
00393 virtual int GetDisplaySpeed() const { return 0; }
00394
00399 virtual int GetDisplayMaxSpeed() const { return 0; }
00400
00405 virtual Money GetRunningCost() const { return 0; }
00406
00411 virtual bool IsInDepot() const { return false; }
00412
00417 virtual bool IsChainInDepot() const { return this->IsInDepot(); }
00418
00423 bool IsStoppedInDepot() const
00424 {
00425 assert(this == this->First());
00426
00427 if (this->IsPrimaryVehicle() && !(this->vehstatus & VS_STOPPED)) return false;
00428 return this->IsChainInDepot();
00429 }
00430
00435 virtual bool Tick() { return true; };
00436
00440 virtual void OnNewDay() {};
00441
00447 virtual uint Crash(bool flooded = false);
00448
00461 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00462
00467 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00468
00473 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00474
00479 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00480
00481 void SetNext(Vehicle *next);
00482
00488 inline Vehicle *Next() const { return this->next; }
00489
00495 inline Vehicle *Previous() const { return this->previous; }
00496
00501 inline Vehicle *First() const { return this->first; }
00502
00507 inline Vehicle *Last()
00508 {
00509 Vehicle *v = this;
00510 while (v->Next() != NULL) v = v->Next();
00511 return v;
00512 }
00513
00518 inline const Vehicle *Last() const
00519 {
00520 const Vehicle *v = this;
00521 while (v->Next() != NULL) v = v->Next();
00522 return v;
00523 }
00524
00530 inline Vehicle *Move(int n)
00531 {
00532 Vehicle *v = this;
00533 if (n < 0) {
00534 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00535 } else {
00536 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00537 }
00538 return v;
00539 }
00540
00546 inline const Vehicle *Move(int n) const
00547 {
00548 const Vehicle *v = this;
00549 if (n < 0) {
00550 for (int i = 0; i != n && v != NULL; i--) v = v->Previous();
00551 } else {
00552 for (int i = 0; i != n && v != NULL; i++) v = v->Next();
00553 }
00554 return v;
00555 }
00556
00561 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00562
00563 void AddToShared(Vehicle *shared_chain);
00564 void RemoveFromShared();
00565
00570 inline Vehicle *NextShared() const { return this->next_shared; }
00571
00576 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00577
00582 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00583
00588 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00589
00594 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00595
00600 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00601
00608 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00609 {
00610 this->unitnumber = src->unitnumber;
00611
00612 this->cur_real_order_index = src->cur_real_order_index;
00613 this->cur_implicit_order_index = src->cur_implicit_order_index;
00614 this->current_order = src->current_order;
00615 this->dest_tile = src->dest_tile;
00616
00617 this->profit_this_year = src->profit_this_year;
00618 this->profit_last_year = src->profit_last_year;
00619
00620 this->current_order_time = src->current_order_time;
00621 this->lateness_counter = src->lateness_counter;
00622 this->timetable_start = src->timetable_start;
00623
00624 if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
00625 if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00626 if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00627
00628 this->service_interval = src->service_interval;
00629 }
00630
00631
00632 bool HandleBreakdown();
00633
00634 bool NeedsAutorenewing(const Company *c) const;
00635
00636 bool NeedsServicing() const;
00637 bool NeedsAutomaticServicing() const;
00638
00646 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00647
00656 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00657
00658 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00659
00660 void UpdateVisualEffect(bool allow_power_change = true);
00661 void ShowVisualEffect() const;
00662
00663 private:
00668 void SkipToNextRealOrderIndex()
00669 {
00670 if (this->GetNumManualOrders() > 0) {
00671
00672 do {
00673 this->cur_real_order_index++;
00674 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00675 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00676 } else {
00677 this->cur_real_order_index = 0;
00678 }
00679 }
00680
00681 public:
00687 void IncrementImplicitOrderIndex()
00688 {
00689 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00690
00691 this->SkipToNextRealOrderIndex();
00692 }
00693
00694 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00695
00696
00697 do {
00698 this->cur_implicit_order_index++;
00699 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00700 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00701
00702 InvalidateVehicleOrder(this, 0);
00703 }
00704
00711 void IncrementRealOrderIndex()
00712 {
00713 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00714
00715 this->IncrementImplicitOrderIndex();
00716 } else {
00717
00718 this->SkipToNextRealOrderIndex();
00719 InvalidateVehicleOrder(this, 0);
00720 }
00721 }
00722
00726 void UpdateRealOrderIndex()
00727 {
00728
00729 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00730
00731 if (this->GetNumManualOrders() > 0) {
00732
00733 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00734 this->cur_real_order_index++;
00735 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00736 }
00737 } else {
00738 this->cur_real_order_index = 0;
00739 }
00740 }
00741
00747 inline Order *GetOrder(int index) const
00748 {
00749 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00750 }
00751
00756 inline Order *GetLastOrder() const
00757 {
00758 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00759 }
00760
00761 bool IsEngineCountable() const;
00762 bool HasEngineType() const;
00763 bool HasDepotOrder() const;
00764 void HandlePathfindingResult(bool path_found);
00765
00770 inline bool IsFrontEngine() const
00771 {
00772 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00773 }
00774
00779 inline bool IsArticulatedPart() const
00780 {
00781 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00782 }
00783
00788 inline bool HasArticulatedPart() const
00789 {
00790 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00791 }
00792
00798 inline Vehicle *GetNextArticulatedPart() const
00799 {
00800 assert(this->HasArticulatedPart());
00801 return this->Next();
00802 }
00803
00808 inline Vehicle *GetFirstEnginePart()
00809 {
00810 Vehicle *v = this;
00811 while (v->IsArticulatedPart()) v = v->Previous();
00812 return v;
00813 }
00814
00819 inline const Vehicle *GetFirstEnginePart() const
00820 {
00821 const Vehicle *v = this;
00822 while (v->IsArticulatedPart()) v = v->Previous();
00823 return v;
00824 }
00825
00830 inline Vehicle *GetLastEnginePart()
00831 {
00832 Vehicle *v = this;
00833 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00834 return v;
00835 }
00836
00841 inline Vehicle *GetNextVehicle() const
00842 {
00843 const Vehicle *v = this;
00844 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00845
00846
00847 return v->Next();
00848 }
00849
00854 inline Vehicle *GetPrevVehicle() const
00855 {
00856 Vehicle *v = this->Previous();
00857 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00858
00859 return v;
00860 }
00861 };
00862
00868 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00869
00874 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00875
00880 template <class T, VehicleType Type>
00881 struct SpecializedVehicle : public Vehicle {
00882 static const VehicleType EXPECTED_TYPE = Type;
00883
00884 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00885
00889 inline SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00890
00895 inline T *First() const { return (T *)this->Vehicle::First(); }
00896
00901 inline T *Last() { return (T *)this->Vehicle::Last(); }
00902
00907 inline const T *Last() const { return (const T *)this->Vehicle::Last(); }
00908
00913 inline T *Next() const { return (T *)this->Vehicle::Next(); }
00914
00919 inline T *Previous() const { return (T *)this->Vehicle::Previous(); }
00920
00926 inline T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00927
00933 inline T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00934
00939 inline T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00940
00945 inline const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00946
00951 inline T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00952
00957 inline T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00958
00963 inline T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00964
00970 static inline bool IsValidID(size_t index)
00971 {
00972 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00973 }
00974
00979 static inline T *Get(size_t index)
00980 {
00981 return (T *)Vehicle::Get(index);
00982 }
00983
00988 static inline T *GetIfValid(size_t index)
00989 {
00990 return IsValidID(index) ? Get(index) : NULL;
00991 }
00992
00998 static inline T *From(Vehicle *v)
00999 {
01000 assert(v->type == Type);
01001 return (T *)v;
01002 }
01003
01009 static inline const T *From(const Vehicle *v)
01010 {
01011 assert(v->type == Type);
01012 return (const T *)v;
01013 }
01014
01020 inline void UpdateViewport(bool force_update, bool update_delta)
01021 {
01022 extern void VehicleUpdateViewport(Vehicle *v, bool dirty);
01023
01024
01025
01026 if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction);
01027 SpriteID old_image = this->cur_image;
01028 this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP);
01029 if (force_update || this->cur_image != old_image) VehicleUpdateViewport(this, true);
01030 }
01031 };
01032
01038 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01039
01043 struct DisasterVehicle FINAL : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01044 SpriteID image_override;
01045 VehicleID big_ufo_destroyer_target;
01046
01048 DisasterVehicle() : SpecializedVehicleBase() {}
01050 virtual ~DisasterVehicle() {}
01051
01052 void UpdateDeltaXY(Direction direction);
01053 bool Tick();
01054 };
01055
01060 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01061
01063 struct FreeUnitIDGenerator {
01064 bool *cache;
01065 UnitID maxid;
01066 UnitID curid;
01067
01068 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01069 UnitID NextID();
01070
01072 ~FreeUnitIDGenerator() { free(this->cache); }
01073 };
01074
01076 static const int32 INVALID_COORD = 0x7fffffff;
01077
01078 #endif