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_auto_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 void DeleteUnreachedAutoOrders();
00253
00254 void HandleLoading(bool mode = false);
00255
00264 virtual void MarkDirty() {}
00265
00271 virtual void UpdateDeltaXY(Direction direction) {}
00272
00286 FORCEINLINE uint GetOldAdvanceSpeed(uint speed)
00287 {
00288 return (this->direction & 1) ? speed : speed * 3 / 4;
00289 }
00290
00303 static FORCEINLINE uint GetAdvanceSpeed(uint speed)
00304 {
00305 return speed * 3 / 4;
00306 }
00307
00315 FORCEINLINE uint GetAdvanceDistance()
00316 {
00317 return (this->direction & 1) ? 192 : 256;
00318 }
00319
00324 virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
00325
00329 virtual void PlayLeaveStationSound() const {}
00330
00334 virtual bool IsPrimaryVehicle() const { return false; }
00335
00341 virtual SpriteID GetImage(Direction direction) const { return 0; }
00342
00347 FORCEINLINE void InvalidateNewGRFCache()
00348 {
00349 this->grf_cache.cache_valid = 0;
00350 }
00351
00356 FORCEINLINE void InvalidateNewGRFCacheOfChain()
00357 {
00358 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00359 u->InvalidateNewGRFCache();
00360 }
00361 }
00362
00367 FORCEINLINE bool IsGroundVehicle() const
00368 {
00369 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00370 }
00371
00376 virtual int GetDisplaySpeed() const { return 0; }
00377
00382 virtual int GetDisplayMaxSpeed() const { return 0; }
00383
00388 virtual Money GetRunningCost() const { return 0; }
00389
00394 virtual bool IsInDepot() const { return false; }
00395
00400 virtual bool IsStoppedInDepot() const { return this->IsInDepot() && (this->vehstatus & VS_STOPPED) != 0; }
00401
00406 virtual bool Tick() { return true; };
00407
00411 virtual void OnNewDay() {};
00412
00418 virtual uint Crash(bool flooded = false);
00419
00432 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00433
00438 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00439
00444 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00445
00450 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00451
00452 void SetNext(Vehicle *next);
00453
00459 inline Vehicle *Next() const { return this->next; }
00460
00466 inline Vehicle *Previous() const { return this->previous; }
00467
00472 inline Vehicle *First() const { return this->first; }
00473
00478 inline Vehicle *Last()
00479 {
00480 Vehicle *v = this;
00481 while (v->Next() != NULL) v = v->Next();
00482 return v;
00483 }
00484
00489 inline const Vehicle *Last() const
00490 {
00491 const Vehicle *v = this;
00492 while (v->Next() != NULL) v = v->Next();
00493 return v;
00494 }
00495
00500 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00501
00502 void AddToShared(Vehicle *shared_chain);
00503 void RemoveFromShared();
00504
00509 inline Vehicle *NextShared() const { return this->next_shared; }
00510
00515 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00516
00521 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00522
00527 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00528
00533 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00534
00539 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00540
00547 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00548 {
00549 this->unitnumber = src->unitnumber;
00550
00551 this->cur_real_order_index = src->cur_real_order_index;
00552 this->cur_auto_order_index = src->cur_auto_order_index;
00553 this->current_order = src->current_order;
00554 this->dest_tile = src->dest_tile;
00555
00556 this->profit_this_year = src->profit_this_year;
00557 this->profit_last_year = src->profit_last_year;
00558
00559 this->current_order_time = src->current_order_time;
00560 this->lateness_counter = src->lateness_counter;
00561 this->timetable_start = src->timetable_start;
00562
00563 if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
00564 if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00565 if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00566
00567 this->service_interval = src->service_interval;
00568 }
00569
00570
00571 bool HandleBreakdown();
00572
00573 bool NeedsAutorenewing(const Company *c) const;
00574
00575 bool NeedsServicing() const;
00576 bool NeedsAutomaticServicing() const;
00577
00585 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00586
00595 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00596
00597 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00598
00599 void UpdateVisualEffect(bool allow_power_change = true);
00600 void ShowVisualEffect() const;
00601
00602 private:
00607 void SkipToNextRealOrderIndex()
00608 {
00609 if (this->GetNumManualOrders() > 0) {
00610
00611 do {
00612 this->cur_real_order_index++;
00613 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00614 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_AUTOMATIC));
00615 } else {
00616 this->cur_real_order_index = 0;
00617 }
00618 }
00619
00620 public:
00626 void IncrementAutoOrderIndex()
00627 {
00628 if (this->cur_auto_order_index == this->cur_real_order_index) {
00629
00630 this->SkipToNextRealOrderIndex();
00631 }
00632
00633 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00634
00635
00636 do {
00637 this->cur_auto_order_index++;
00638 if (this->cur_auto_order_index >= this->GetNumOrders()) this->cur_auto_order_index = 0;
00639 } while (this->cur_auto_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_auto_order_index)->IsType(OT_AUTOMATIC));
00640
00641 InvalidateVehicleOrder(this, 0);
00642 }
00643
00650 void IncrementRealOrderIndex()
00651 {
00652 if (this->cur_auto_order_index == this->cur_real_order_index) {
00653
00654 this->IncrementAutoOrderIndex();
00655 } else {
00656
00657 this->SkipToNextRealOrderIndex();
00658 InvalidateVehicleOrder(this, 0);
00659 }
00660 }
00661
00665 void UpdateRealOrderIndex()
00666 {
00667
00668 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00669
00670 if (this->GetNumManualOrders() > 0) {
00671
00672 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_AUTOMATIC)) {
00673 this->cur_real_order_index++;
00674 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00675 }
00676 } else {
00677 this->cur_real_order_index = 0;
00678 }
00679 }
00680
00686 inline Order *GetOrder(int index) const
00687 {
00688 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00689 }
00690
00695 inline Order *GetLastOrder() const
00696 {
00697 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00698 }
00699
00700 bool IsEngineCountable() const;
00701 bool HasDepotOrder() const;
00702 void HandlePathfindingResult(bool path_found);
00703
00708 FORCEINLINE bool IsFrontEngine() const
00709 {
00710 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00711 }
00712
00717 FORCEINLINE bool IsArticulatedPart() const
00718 {
00719 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00720 }
00721
00726 FORCEINLINE bool HasArticulatedPart() const
00727 {
00728 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00729 }
00730
00736 FORCEINLINE Vehicle *GetNextArticulatedPart() const
00737 {
00738 assert(this->HasArticulatedPart());
00739 return this->Next();
00740 }
00741
00746 FORCEINLINE Vehicle *GetFirstEnginePart()
00747 {
00748 Vehicle *v = this;
00749 while (v->IsArticulatedPart()) v = v->Previous();
00750 return v;
00751 }
00752
00757 FORCEINLINE const Vehicle *GetFirstEnginePart() const
00758 {
00759 const Vehicle *v = this;
00760 while (v->IsArticulatedPart()) v = v->Previous();
00761 return v;
00762 }
00763
00768 FORCEINLINE Vehicle *GetLastEnginePart()
00769 {
00770 Vehicle *v = this;
00771 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00772 return v;
00773 }
00774
00779 FORCEINLINE Vehicle *GetNextVehicle() const
00780 {
00781 const Vehicle *v = this;
00782 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00783
00784
00785 return v->Next();
00786 }
00787
00792 FORCEINLINE Vehicle *GetPrevVehicle() const
00793 {
00794 Vehicle *v = this->Previous();
00795 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00796
00797 return v;
00798 }
00799 };
00800
00806 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00807
00812 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00813
00818 template <class T, VehicleType Type>
00819 struct SpecializedVehicle : public Vehicle {
00820 static const VehicleType EXPECTED_TYPE = Type;
00821
00822 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00823
00827 FORCEINLINE SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00828
00833 FORCEINLINE T *First() const { return (T *)this->Vehicle::First(); }
00834
00839 FORCEINLINE T *Last() { return (T *)this->Vehicle::Last(); }
00840
00845 FORCEINLINE const T *Last() const { return (const T *)this->Vehicle::Last(); }
00846
00851 FORCEINLINE T *Next() const { return (T *)this->Vehicle::Next(); }
00852
00857 FORCEINLINE T *Previous() const { return (T *)this->Vehicle::Previous(); }
00858
00864 FORCEINLINE T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00865
00871 FORCEINLINE T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00872
00877 FORCEINLINE T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00878
00883 FORCEINLINE const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00884
00889 FORCEINLINE T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00890
00895 FORCEINLINE T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00896
00901 FORCEINLINE T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00902
00908 static FORCEINLINE bool IsValidID(size_t index)
00909 {
00910 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00911 }
00912
00917 static FORCEINLINE T *Get(size_t index)
00918 {
00919 return (T *)Vehicle::Get(index);
00920 }
00921
00926 static FORCEINLINE T *GetIfValid(size_t index)
00927 {
00928 return IsValidID(index) ? Get(index) : NULL;
00929 }
00930
00936 static FORCEINLINE T *From(Vehicle *v)
00937 {
00938 assert(v->type == Type);
00939 return (T *)v;
00940 }
00941
00947 static FORCEINLINE const T *From(const Vehicle *v)
00948 {
00949 assert(v->type == Type);
00950 return (const T *)v;
00951 }
00952
00958 FORCEINLINE void UpdateViewport(bool moved, bool turned)
00959 {
00960 extern void VehicleMove(Vehicle *v, bool update_viewport);
00961
00962
00963
00964 if (turned) ((T *)this)->T::UpdateDeltaXY(this->direction);
00965 SpriteID old_image = this->cur_image;
00966 this->cur_image = ((T *)this)->T::GetImage(this->direction);
00967 if (moved || this->cur_image != old_image) VehicleMove(this, true);
00968 }
00969 };
00970
00976 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
00977
00981 struct DisasterVehicle : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
00982 SpriteID image_override;
00983 VehicleID big_ufo_destroyer_target;
00984
00986 DisasterVehicle() : SpecializedVehicleBase() {}
00988 virtual ~DisasterVehicle() {}
00989
00990 void UpdateDeltaXY(Direction direction);
00991 bool Tick();
00992 };
00993
00998 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
00999
01001 struct FreeUnitIDGenerator {
01002 bool *cache;
01003 UnitID maxid;
01004 UnitID curid;
01005
01006 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01007 UnitID NextID();
01008
01010 ~FreeUnitIDGenerator() { free(this->cache); }
01011 };
01012
01014 static const int32 INVALID_COORD = 0x7fffffff;
01015
01016 #endif