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
00027 enum VehStatus {
00028 VS_HIDDEN = 0x01,
00029 VS_STOPPED = 0x02,
00030 VS_UNCLICKABLE = 0x04,
00031 VS_DEFPAL = 0x08,
00032 VS_TRAIN_SLOWING = 0x10,
00033 VS_SHADOW = 0x20,
00034 VS_AIRCRAFT_BROKEN = 0x40,
00035 VS_CRASHED = 0x80,
00036 };
00037
00039 enum VehicleFlags {
00040 VF_LOADING_FINISHED,
00041 VF_CARGO_UNLOADING,
00042 VF_BUILT_AS_PROTOTYPE,
00043 VF_TIMETABLE_STARTED,
00044 VF_AUTOFILL_TIMETABLE,
00045 VF_AUTOFILL_PRES_WAIT_TIME,
00046 VF_STOP_LOADING,
00047 VF_PATHFINDER_LOST,
00048 };
00049
00051 enum NewGRFCacheValidValues {
00052 NCVV_POSITION_CONSIST_LENGTH = 0,
00053 NCVV_POSITION_SAME_ID_LENGTH = 1,
00054 NCVV_CONSIST_CARGO_INFORMATION = 2,
00055 NCVV_COMPANY_INFORMATION = 3,
00056 NCVV_END,
00057 };
00058
00060 struct NewGRFCache {
00061
00062 uint32 position_consist_length;
00063 uint32 position_same_id_length;
00064 uint32 consist_cargo_information;
00065 uint32 company_information;
00066 uint8 cache_valid;
00067 };
00068
00070 enum VisualEffect {
00071 VE_OFFSET_START = 0,
00072 VE_OFFSET_COUNT = 4,
00073 VE_OFFSET_CENTRE = 8,
00074
00075 VE_TYPE_START = 4,
00076 VE_TYPE_COUNT = 2,
00077 VE_TYPE_DEFAULT = 0,
00078 VE_TYPE_STEAM = 1,
00079 VE_TYPE_DIESEL = 2,
00080 VE_TYPE_ELECTRIC = 3,
00081
00082 VE_DISABLE_EFFECT = 6,
00083 VE_DISABLE_WAGON_POWER = 7,
00084
00085 VE_DEFAULT = 0xFF,
00086 };
00087
00093 enum GroundVehicleSubtypeFlags {
00094 GVSF_FRONT = 0,
00095 GVSF_ARTICULATED_PART = 1,
00096 GVSF_WAGON = 2,
00097 GVSF_ENGINE = 3,
00098 GVSF_FREE_WAGON = 4,
00099 GVSF_MULTIHEADED = 5,
00100 };
00101
00103 struct VehicleCache {
00104 uint16 cached_max_speed;
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
00122 struct Vehicle : VehiclePool::PoolItem<&_vehicle_pool>, BaseVehicle {
00123 private:
00124 Vehicle *next;
00125 Vehicle *previous;
00126 Vehicle *first;
00127
00128 Vehicle *next_shared;
00129 Vehicle *previous_shared;
00130
00131 public:
00132 friend const SaveLoad *GetVehicleDescription(VehicleType vt);
00133 friend void FixOldVehicles();
00134 friend void AfterLoadVehicles(bool part_of_load);
00135 friend bool LoadOldVehicle(LoadgameState *ls, int num);
00136
00137 char *name;
00138
00139 TileIndex tile;
00140
00146 TileIndex dest_tile;
00147
00148 Money profit_this_year;
00149 Money profit_last_year;
00150 Money value;
00151
00152 CargoPayment *cargo_payment;
00153
00154
00155 uint32 current_order_time;
00156 int32 lateness_counter;
00157 Date timetable_start;
00158
00159 Rect coord;
00160
00161 Vehicle *next_hash;
00162 Vehicle **prev_hash;
00163
00164 Vehicle *next_new_hash;
00165 Vehicle **prev_new_hash;
00166 Vehicle **old_new_hash;
00167
00168 SpriteID colourmap;
00169
00170
00171 Year build_year;
00172 Date age;
00173 Date max_age;
00174 Date date_of_last_service;
00175 Date service_interval;
00176 uint16 reliability;
00177 uint16 reliability_spd_dec;
00178 byte breakdown_ctr;
00179 byte breakdown_delay;
00180 byte breakdowns_since_last_service;
00181 byte breakdown_chance;
00182
00183 int32 x_pos;
00184 int32 y_pos;
00185 byte z_pos;
00186 DirectionByte direction;
00187
00188 OwnerByte owner;
00189 byte spritenum;
00190
00191
00192 SpriteID cur_image;
00193 byte x_extent;
00194 byte y_extent;
00195 byte z_extent;
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
00221 byte day_counter;
00222 byte tick_counter;
00223 byte running_ticks;
00224
00225 byte vehstatus;
00226 Order current_order;
00227 VehicleOrderID cur_real_order_index;
00228 VehicleOrderID cur_implicit_order_index;
00229
00230 union {
00231 OrderList *list;
00232 Order *old;
00233 } orders;
00234
00235 byte vehicle_flags;
00236
00237 uint16 load_unload_ticks;
00238 GroupID group_id;
00239 byte subtype;
00240
00241 NewGRFCache grf_cache;
00242 VehicleCache vcache;
00243
00244 Vehicle(VehicleType type = VEH_INVALID);
00245
00246 void PreDestructor();
00248 virtual ~Vehicle();
00249
00250 void BeginLoading();
00251 void CancelReservation(StationID next, Station *st);
00252 void LeaveStation();
00253
00254 GroundVehicleCache *GetGroundVehicleCache();
00255 const GroundVehicleCache *GetGroundVehicleCache() const;
00256
00257 uint16 &GetGroundVehicleFlags();
00258 const uint16 &GetGroundVehicleFlags() const;
00259
00260 void DeleteUnreachedImplicitOrders();
00261
00262 void HandleLoading(bool mode = false);
00263
00264 void GetConsistFreeCapacities(SmallMap<CargoID, uint> &capacities) const;
00265
00266 uint GetConsistTotalCapacity() const;
00267
00276 virtual void MarkDirty() {}
00277
00283 virtual void UpdateDeltaXY(Direction direction) {}
00284
00298 FORCEINLINE uint GetOldAdvanceSpeed(uint speed)
00299 {
00300 return (this->direction & 1) ? speed : speed * 3 / 4;
00301 }
00302
00315 static FORCEINLINE uint GetAdvanceSpeed(uint speed)
00316 {
00317 return speed * 3 / 4;
00318 }
00319
00327 FORCEINLINE 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
00353 virtual SpriteID GetImage(Direction direction) const { return 0; }
00354
00359 FORCEINLINE void InvalidateNewGRFCache()
00360 {
00361 this->grf_cache.cache_valid = 0;
00362 }
00363
00368 FORCEINLINE void InvalidateNewGRFCacheOfChain()
00369 {
00370 for (Vehicle *u = this; u != NULL; u = u->Next()) {
00371 u->InvalidateNewGRFCache();
00372 }
00373 }
00374
00379 FORCEINLINE bool IsGroundVehicle() const
00380 {
00381 return this->type == VEH_TRAIN || this->type == VEH_ROAD;
00382 }
00383
00388 virtual int GetDisplaySpeed() const { return 0; }
00389
00394 virtual int GetDisplayMaxSpeed() const { return 0; }
00395
00400 virtual Money GetRunningCost() const { return 0; }
00401
00406 virtual bool IsInDepot() const { return false; }
00407
00412 virtual bool IsStoppedInDepot() const { return this->IsInDepot() && (this->vehstatus & VS_STOPPED) != 0; }
00413
00418 virtual bool Tick() { return true; };
00419
00423 virtual void OnNewDay() {};
00424
00430 virtual uint Crash(bool flooded = false);
00431
00444 virtual Trackdir GetVehicleTrackdir() const { return INVALID_TRACKDIR; }
00445
00450 Money GetDisplayRunningCost() const { return (this->GetRunningCost() >> 8); }
00451
00456 Money GetDisplayProfitThisYear() const { return (this->profit_this_year >> 8); }
00457
00462 Money GetDisplayProfitLastYear() const { return (this->profit_last_year >> 8); }
00463
00464 void SetNext(Vehicle *next);
00465
00471 inline Vehicle *Next() const { return this->next; }
00472
00478 inline Vehicle *Previous() const { return this->previous; }
00479
00484 inline Vehicle *First() const { return this->first; }
00485
00490 inline Vehicle *Last()
00491 {
00492 Vehicle *v = this;
00493 while (v->Next() != NULL) v = v->Next();
00494 return v;
00495 }
00496
00501 inline const Vehicle *Last() const
00502 {
00503 const Vehicle *v = this;
00504 while (v->Next() != NULL) v = v->Next();
00505 return v;
00506 }
00507
00512 inline Order *GetFirstOrder() const { return (this->orders.list == NULL) ? NULL : this->orders.list->GetFirstOrder(); }
00513
00514 void AddToShared(Vehicle *shared_chain);
00515 void RemoveFromShared();
00516
00521 inline Vehicle *NextShared() const { return this->next_shared; }
00522
00527 inline Vehicle *PreviousShared() const { return this->previous_shared; }
00528
00533 inline Vehicle *FirstShared() const { return (this->orders.list == NULL) ? this->First() : this->orders.list->GetFirstSharedVehicle(); }
00534
00539 inline bool IsOrderListShared() const { return this->orders.list != NULL && this->orders.list->IsShared(); }
00540
00545 inline VehicleOrderID GetNumOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumOrders(); }
00546
00551 inline VehicleOrderID GetNumManualOrders() const { return (this->orders.list == NULL) ? 0 : this->orders.list->GetNumManualOrders(); }
00552
00557 inline StationID GetNextStoppingStation() const
00558 {
00559 return (this->orders.list == NULL) ? INVALID_STATION : this->orders.list->GetNextStoppingStation(this);
00560 }
00561
00562 void RefreshNextHopsStats();
00563
00570 inline void CopyVehicleConfigAndStatistics(const Vehicle *src)
00571 {
00572 this->unitnumber = src->unitnumber;
00573
00574 this->cur_real_order_index = src->cur_real_order_index;
00575 this->cur_implicit_order_index = src->cur_implicit_order_index;
00576 this->current_order = src->current_order;
00577 this->dest_tile = src->dest_tile;
00578
00579 this->profit_this_year = src->profit_this_year;
00580 this->profit_last_year = src->profit_last_year;
00581
00582 this->current_order_time = src->current_order_time;
00583 this->lateness_counter = src->lateness_counter;
00584 this->timetable_start = src->timetable_start;
00585
00586 if (HasBit(src->vehicle_flags, VF_TIMETABLE_STARTED)) SetBit(this->vehicle_flags, VF_TIMETABLE_STARTED);
00587 if (HasBit(src->vehicle_flags, VF_AUTOFILL_TIMETABLE)) SetBit(this->vehicle_flags, VF_AUTOFILL_TIMETABLE);
00588 if (HasBit(src->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) SetBit(this->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME);
00589
00590 this->service_interval = src->service_interval;
00591 }
00592
00593
00594 bool HandleBreakdown();
00595
00596 bool NeedsAutorenewing(const Company *c) const;
00597
00598 bool NeedsServicing() const;
00599 bool NeedsAutomaticServicing() const;
00600
00608 virtual TileIndex GetOrderStationLocation(StationID station) { return INVALID_TILE; }
00609
00618 virtual bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse) { return false; }
00619
00620 CommandCost SendToDepot(DoCommandFlag flags, DepotCommand command);
00621
00622 void UpdateVisualEffect(bool allow_power_change = true);
00623 void ShowVisualEffect() const;
00624
00625 private:
00630 void SkipToNextRealOrderIndex()
00631 {
00632 if (this->GetNumManualOrders() > 0) {
00633
00634 do {
00635 this->cur_real_order_index++;
00636 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00637 } while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT));
00638 } else {
00639 this->cur_real_order_index = 0;
00640 }
00641 }
00642
00643 public:
00649 void IncrementImplicitOrderIndex()
00650 {
00651 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00652
00653 this->SkipToNextRealOrderIndex();
00654 }
00655
00656 assert(this->cur_real_order_index == 0 || this->cur_real_order_index < this->GetNumOrders());
00657
00658
00659 do {
00660 this->cur_implicit_order_index++;
00661 if (this->cur_implicit_order_index >= this->GetNumOrders()) this->cur_implicit_order_index = 0;
00662 } while (this->cur_implicit_order_index != this->cur_real_order_index && !this->GetOrder(this->cur_implicit_order_index)->IsType(OT_IMPLICIT));
00663
00664 InvalidateVehicleOrder(this, 0);
00665 }
00666
00673 void IncrementRealOrderIndex()
00674 {
00675 if (this->cur_implicit_order_index == this->cur_real_order_index) {
00676
00677 this->IncrementImplicitOrderIndex();
00678 } else {
00679
00680 this->SkipToNextRealOrderIndex();
00681 InvalidateVehicleOrder(this, 0);
00682 }
00683 }
00684
00688 void UpdateRealOrderIndex()
00689 {
00690
00691 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00692
00693 if (this->GetNumManualOrders() > 0) {
00694
00695 while (this->GetOrder(this->cur_real_order_index)->IsType(OT_IMPLICIT)) {
00696 this->cur_real_order_index++;
00697 if (this->cur_real_order_index >= this->GetNumOrders()) this->cur_real_order_index = 0;
00698 }
00699 } else {
00700 this->cur_real_order_index = 0;
00701 }
00702 }
00703
00709 inline Order *GetOrder(int index) const
00710 {
00711 return (this->orders.list == NULL) ? NULL : this->orders.list->GetOrderAt(index);
00712 }
00713
00718 inline Order *GetLastOrder() const
00719 {
00720 return (this->orders.list == NULL) ? NULL : this->orders.list->GetLastOrder();
00721 }
00722
00723 bool IsEngineCountable() const;
00724 bool HasDepotOrder() const;
00725 void HandlePathfindingResult(bool path_found);
00726
00731 FORCEINLINE bool IsFrontEngine() const
00732 {
00733 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_FRONT);
00734 }
00735
00740 FORCEINLINE bool IsArticulatedPart() const
00741 {
00742 return this->IsGroundVehicle() && HasBit(this->subtype, GVSF_ARTICULATED_PART);
00743 }
00744
00749 FORCEINLINE bool HasArticulatedPart() const
00750 {
00751 return this->Next() != NULL && this->Next()->IsArticulatedPart();
00752 }
00753
00759 FORCEINLINE Vehicle *GetNextArticulatedPart() const
00760 {
00761 assert(this->HasArticulatedPart());
00762 return this->Next();
00763 }
00764
00769 FORCEINLINE Vehicle *GetFirstEnginePart()
00770 {
00771 Vehicle *v = this;
00772 while (v->IsArticulatedPart()) v = v->Previous();
00773 return v;
00774 }
00775
00780 FORCEINLINE const Vehicle *GetFirstEnginePart() const
00781 {
00782 const Vehicle *v = this;
00783 while (v->IsArticulatedPart()) v = v->Previous();
00784 return v;
00785 }
00786
00791 FORCEINLINE Vehicle *GetLastEnginePart()
00792 {
00793 Vehicle *v = this;
00794 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00795 return v;
00796 }
00797
00802 FORCEINLINE Vehicle *GetNextVehicle() const
00803 {
00804 const Vehicle *v = this;
00805 while (v->HasArticulatedPart()) v = v->GetNextArticulatedPart();
00806
00807
00808 return v->Next();
00809 }
00810
00815 FORCEINLINE Vehicle *GetPrevVehicle() const
00816 {
00817 Vehicle *v = this->Previous();
00818 while (v != NULL && v->IsArticulatedPart()) v = v->Previous();
00819
00820 return v;
00821 }
00822 };
00823
00829 #define FOR_ALL_VEHICLES_FROM(var, start) FOR_ALL_ITEMS_FROM(Vehicle, vehicle_index, var, start)
00830
00835 #define FOR_ALL_VEHICLES(var) FOR_ALL_VEHICLES_FROM(var, 0)
00836
00841 template <class T, VehicleType Type>
00842 struct SpecializedVehicle : public Vehicle {
00843 static const VehicleType EXPECTED_TYPE = Type;
00844
00845 typedef SpecializedVehicle<T, Type> SpecializedVehicleBase;
00846
00850 FORCEINLINE SpecializedVehicle<T, Type>() : Vehicle(Type) { }
00851
00856 FORCEINLINE T *First() const { return (T *)this->Vehicle::First(); }
00857
00862 FORCEINLINE T *Last() { return (T *)this->Vehicle::Last(); }
00863
00868 FORCEINLINE const T *Last() const { return (const T *)this->Vehicle::Last(); }
00869
00874 FORCEINLINE T *Next() const { return (T *)this->Vehicle::Next(); }
00875
00880 FORCEINLINE T *Previous() const { return (T *)this->Vehicle::Previous(); }
00881
00887 FORCEINLINE T *GetNextArticulatedPart() { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00888
00894 FORCEINLINE T *GetNextArticulatedPart() const { return (T *)this->Vehicle::GetNextArticulatedPart(); }
00895
00900 FORCEINLINE T *GetFirstEnginePart() { return (T *)this->Vehicle::GetFirstEnginePart(); }
00901
00906 FORCEINLINE const T *GetFirstEnginePart() const { return (const T *)this->Vehicle::GetFirstEnginePart(); }
00907
00912 FORCEINLINE T *GetLastEnginePart() { return (T *)this->Vehicle::GetLastEnginePart(); }
00913
00918 FORCEINLINE T *GetNextVehicle() const { return (T *)this->Vehicle::GetNextVehicle(); }
00919
00924 FORCEINLINE T *GetPrevVehicle() const { return (T *)this->Vehicle::GetPrevVehicle(); }
00925
00931 static FORCEINLINE bool IsValidID(size_t index)
00932 {
00933 return Vehicle::IsValidID(index) && Vehicle::Get(index)->type == Type;
00934 }
00935
00940 static FORCEINLINE T *Get(size_t index)
00941 {
00942 return (T *)Vehicle::Get(index);
00943 }
00944
00949 static FORCEINLINE T *GetIfValid(size_t index)
00950 {
00951 return IsValidID(index) ? Get(index) : NULL;
00952 }
00953
00959 static FORCEINLINE T *From(Vehicle *v)
00960 {
00961 assert(v->type == Type);
00962 return (T *)v;
00963 }
00964
00970 static FORCEINLINE const T *From(const Vehicle *v)
00971 {
00972 assert(v->type == Type);
00973 return (const T *)v;
00974 }
00975
00981 FORCEINLINE void UpdateViewport(bool moved, bool turned)
00982 {
00983 extern void VehicleMove(Vehicle *v, bool update_viewport);
00984
00985
00986
00987 if (turned) ((T *)this)->T::UpdateDeltaXY(this->direction);
00988 SpriteID old_image = this->cur_image;
00989 this->cur_image = ((T *)this)->T::GetImage(this->direction);
00990 if (moved || this->cur_image != old_image) VehicleMove(this, true);
00991 }
00992 };
00993
00999 #define FOR_ALL_VEHICLES_OF_TYPE(name, var) FOR_ALL_ITEMS_FROM(name, vehicle_index, var, 0) if (var->type == name::EXPECTED_TYPE)
01000
01004 struct DisasterVehicle : public SpecializedVehicle<DisasterVehicle, VEH_DISASTER> {
01005 SpriteID image_override;
01006 VehicleID big_ufo_destroyer_target;
01007
01009 DisasterVehicle() : SpecializedVehicleBase() {}
01011 virtual ~DisasterVehicle() {}
01012
01013 void UpdateDeltaXY(Direction direction);
01014 bool Tick();
01015 };
01016
01021 #define FOR_ALL_DISASTERVEHICLES(var) FOR_ALL_VEHICLES_OF_TYPE(DisasterVehicle, var)
01022
01024 struct FreeUnitIDGenerator {
01025 bool *cache;
01026 UnitID maxid;
01027 UnitID curid;
01028
01029 FreeUnitIDGenerator(VehicleType type, CompanyID owner);
01030 UnitID NextID();
01031
01033 ~FreeUnitIDGenerator() { free(this->cache); }
01034 };
01035
01037 static const int32 INVALID_COORD = 0x7fffffff;
01038
01039 #endif