bjarni@2676: /* $Id$ */ bjarni@2676: rubidium@10429: /** @file train.h Base for the train class. */ belugas@6918: bjarni@2676: #ifndef TRAIN_H bjarni@2676: #define TRAIN_H bjarni@2676: bjarni@2676: #include "stdafx.h" rubidium@8640: #include "core/bitmath_func.hpp" rubidium@8640: #include "vehicle_base.h" bjarni@2676: bjarni@2676: smatz@9346: /** enum to handle train subtypes bjarni@2676: * Do not access it directly unless you have to. Use the access functions below bjarni@2676: * This is an enum to tell what bit to access as it is a bitmask bjarni@2676: */ rubidium@6574: enum TrainSubtype { smatz@9108: TS_FRONT = 0, ///< Leading engine of a train smatz@9108: TS_ARTICULATED_PART = 1, ///< Articulated part of an engine smatz@9108: TS_WAGON = 2, ///< Wagon smatz@9108: TS_ENGINE = 3, ///< Engine, that can be front engines, but might be placed behind another engine smatz@9108: TS_FREE_WAGON = 4, ///< First in a wagon chain (in depot) smatz@9108: TS_MULTIHEADED = 5, ///< Engine is a multiheaded rubidium@6574: }; bjarni@2676: bjarni@2676: bjarni@2676: /** Check if a vehicle is front engine bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is a front engine bjarni@2676: */ bjarni@2676: static inline bool IsFrontEngine(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_FRONT); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set front engine state bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetFrontEngine(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_FRONT); bjarni@2676: } bjarni@2676: bjarni@2676: /** Remove the front engine state bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearFrontEngine(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_FRONT); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if a vehicle is an articulated part of an engine bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is an articulated part bjarni@2676: */ bjarni@2676: static inline bool IsArticulatedPart(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_ARTICULATED_PART); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set a vehicle to be an articulated part bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetArticulatedPart(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_ARTICULATED_PART); bjarni@2676: } bjarni@2676: bjarni@2676: /** Clear a vehicle from being an articulated part bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearArticulatedPart(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_ARTICULATED_PART); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if a vehicle is a wagon bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is a wagon bjarni@2676: */ bjarni@2676: static inline bool IsTrainWagon(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set a vehicle to be a wagon bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetTrainWagon(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Clear wagon property bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearTrainWagon(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if a vehicle is an engine (can be first in a train) bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is an engine bjarni@2676: */ bjarni@2676: static inline bool IsTrainEngine(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_ENGINE); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set engine status bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetTrainEngine(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_ENGINE); bjarni@2676: } bjarni@2676: bjarni@2676: /** Clear engine status bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearTrainEngine(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_ENGINE); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if a vehicle is a free wagon (got no engine in front of it) bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is a free wagon bjarni@2676: */ bjarni@2676: static inline bool IsFreeWagon(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_FREE_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set if a vehicle is a free wagon bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetFreeWagon(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_FREE_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Clear a vehicle from being a free wagon bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearFreeWagon(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_FREE_WAGON); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if a vehicle is a multiheaded engine bjarni@2676: * @param v vehicle to check bjarni@2676: * @return Returns true if vehicle is a multiheaded engine bjarni@2676: */ bjarni@2676: static inline bool IsMultiheaded(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: return HasBit(v->subtype, TS_MULTIHEADED); bjarni@2676: } bjarni@2676: bjarni@2676: /** Set if a vehicle is a multiheaded engine bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void SetMultiheaded(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: SetBit(v->subtype, TS_MULTIHEADED); bjarni@2676: } bjarni@2676: bjarni@2676: /** Clear multiheaded engine property bjarni@2676: * @param v vehicle to change bjarni@2676: */ bjarni@2676: static inline void ClearMultiheaded(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); smatz@9108: ClrBit(v->subtype, TS_MULTIHEADED); bjarni@2676: } bjarni@2676: bjarni@2676: /** Check if an engine has an articulated part. bjarni@2676: * @param v Vehicle. bjarni@2676: * @return True if the engine has an articulated part. bjarni@2676: */ bjarni@2676: static inline bool EngineHasArticPart(const Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); rubidium@7988: return (v->Next() != NULL && IsArticulatedPart(v->Next())); bjarni@2676: } bjarni@2676: truelight@4384: /** truelight@4384: * Get the next part of a multi-part engine. truelight@4384: * Will only work on a multi-part engine (EngineHasArticPart(v) == true), truelight@4384: * Result is undefined for normal engine. truelight@4384: */ truelight@4384: static inline Vehicle *GetNextArticPart(const Vehicle *v) truelight@4384: { truelight@4384: assert(EngineHasArticPart(v)); rubidium@7988: return v->Next(); truelight@4384: } truelight@4384: bjarni@2676: /** Get the last part of a multi-part engine. bjarni@2676: * @param v Vehicle. bjarni@2676: * @return Last part of the engine. bjarni@2676: */ bjarni@2676: static inline Vehicle *GetLastEnginePart(Vehicle *v) bjarni@2676: { maedhros@7267: assert(v->type == VEH_TRAIN); truelight@4384: while (EngineHasArticPart(v)) v = GetNextArticPart(v); bjarni@2676: return v; bjarni@2676: } bjarni@2676: bjarni@8022: /** Tell if we are dealing with the rear end of a multiheaded engine. bjarni@8022: * @param v Vehicle. bjarni@8022: * @return True if the engine is the rear part of a dualheaded engine. bjarni@8022: */ bjarni@8022: static inline bool IsRearDualheaded(const Vehicle *v) bjarni@8022: { bjarni@8022: assert(v->type == VEH_TRAIN); bjarni@8022: return (IsMultiheaded(v) && !IsTrainEngine(v)); bjarni@8022: } bjarni@8022: truelight@4384: /** Get the next real (non-articulated part) vehicle in the consist. truelight@4384: * @param v Vehicle. truelight@4384: * @return Next vehicle in the consist. truelight@4384: */ truelight@4384: static inline Vehicle *GetNextVehicle(const Vehicle *v) truelight@4384: { maedhros@7267: assert(v->type == VEH_TRAIN); truelight@4384: while (EngineHasArticPart(v)) v = GetNextArticPart(v); truelight@4384: truelight@4384: /* v now contains the last artic part in the engine */ rubidium@7988: return v->Next(); truelight@4384: } truelight@4384: bjarni@8023: /** Get the next real (non-articulated part and non rear part of dualheaded engine) vehicle in the consist. bjarni@8023: * @param v Vehicle. bjarni@8023: * @return Next vehicle in the consist. bjarni@8023: */ bjarni@8023: static inline Vehicle *GetNextUnit(Vehicle *v) bjarni@8023: { bjarni@8023: assert(v->type == VEH_TRAIN); bjarni@8023: v = GetNextVehicle(v); bjarni@8023: if (v != NULL && IsRearDualheaded(v)) v = v->Next(); bjarni@8023: bjarni@8023: return v; bjarni@8023: } bjarni@8023: rubidium@6573: void ConvertOldMultiheadToNew(); rubidium@6573: void ConnectMultiheadedTrains(); peter1138@4737: uint CountArticulatedParts(EngineID engine_type); bjarni@2855: bjarni@6030: void CcBuildLoco(bool success, TileIndex tile, uint32 p1, uint32 p2); bjarni@6030: void CcBuildWagon(bool success, TileIndex tile, uint32 p1, uint32 p2); bjarni@4640: peter1138@5316: byte FreightWagonMult(CargoID cargo); peter1138@5163: rubidium@7986: int CheckTrainInDepot(const Vehicle *v, bool needs_to_be_stopped); rubidium@7986: int CheckTrainStoppedInDepot(const Vehicle *v); smatz@9192: void UpdateTrainAcceleration(Vehicle* v); rubidium@7986: rubidium@7048: /** rubidium@7048: * This class 'wraps' Vehicle; you do not actually instantiate this class. rubidium@7048: * You create a Vehicle using AllocateVehicle, so it is added to the pool rubidium@7048: * and you reinitialize that to a Train using: rubidium@7048: * v = new (v) Train(); rubidium@7048: * rubidium@7048: * As side-effect the vehicle type is set correctly. rubidium@7048: */ rubidium@7048: struct Train : public Vehicle { rubidium@7048: /** Initializes the Vehicle to a train */ rubidium@7048: Train() { this->type = VEH_TRAIN; } rubidium@7048: rubidium@7048: /** We want to 'destruct' the right class. */ rubidium@7908: virtual ~Train() { this->PreDestructor(); } rubidium@7048: rubidium@7059: const char *GetTypeString() const { return "train"; } rubidium@7049: void MarkDirty(); rubidium@7054: void UpdateDeltaXY(Direction direction); rubidium@7059: ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; } rubidium@7089: void PlayLeaveStationSound() const; maedhros@7269: bool IsPrimaryVehicle() const { return IsFrontEngine(this); } peter1138@10293: SpriteID GetImage(Direction direction) const; rubidium@8029: int GetDisplaySpeed() const { return this->u.rail.last_speed * 10 / 16; } rubidium@7980: int GetDisplayMaxSpeed() const { return this->u.rail.cached_max_speed * 10 / 16; } rubidium@7984: Money GetRunningCost() const; rubidium@7986: bool IsInDepot() const { return CheckTrainInDepot(this, false) != -1; } rubidium@7986: bool IsStoppedInDepot() const { return CheckTrainStoppedInDepot(this) >= 0; } rubidium@7631: void Tick(); glx@8963: void OnNewDay(); rubidium@9323: TileIndex GetOrderStationLocation(StationID station); rubidium@10126: bool FindClosestDepot(TileIndex *location, DestinationID *destination, bool *reverse); rubidium@7048: }; rubidium@7048: bjarni@2676: #endif /* TRAIN_H */