00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #ifndef GROUND_VEHICLE_HPP
00013 #define GROUND_VEHICLE_HPP
00014
00015 #include "vehicle_base.h"
00016 #include "landscape.h"
00017
00019 enum AccelStatus {
00020 AS_ACCEL,
00021 AS_BRAKE
00022 };
00023
00028 struct GroundVehicleCache {
00029
00030 uint32 cached_weight;
00031 uint32 cached_slope_resistance;
00032 uint32 cached_max_te;
00033 uint16 cached_axle_resistance;
00034
00035
00036 uint16 cached_max_track_speed;
00037 uint32 cached_power;
00038 uint32 cached_air_drag;
00039
00040
00041 uint16 cached_total_length;
00042 EngineID first_engine;
00043 uint8 cached_veh_length;
00044 };
00045
00047 enum GroundVehicleFlags {
00048 GVF_GOINGUP_BIT = 0,
00049 GVF_GOINGDOWN_BIT = 1,
00050 };
00051
00073 template <class T, VehicleType Type>
00074 struct GroundVehicle : public SpecializedVehicle<T, Type> {
00075 GroundVehicleCache gcache;
00076 uint16 gv_flags;
00077
00078 typedef GroundVehicle<T, Type> GroundVehicleBase;
00079
00083 GroundVehicle() : SpecializedVehicle<T, Type>() {}
00084
00085 void PowerChanged();
00086 void CargoChanged();
00087 int GetAcceleration() const;
00088
00094 uint Crash(bool flooded)
00095 {
00096
00097 for (T *v = T::From(this); v != NULL; v = v->Next()) {
00098 ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00099 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00100 }
00101 return this->Vehicle::Crash(flooded);
00102 }
00103
00108 FORCEINLINE int32 GetSlopeResistance() const
00109 {
00110 int32 incl = 0;
00111
00112 for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00113 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00114 incl += u->gcache.cached_slope_resistance;
00115 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00116 incl -= u->gcache.cached_slope_resistance;
00117 }
00118 }
00119
00120 return incl;
00121 }
00122
00129 FORCEINLINE void UpdateZPositionAndInclination()
00130 {
00131 this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00132 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00133 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00134
00135 if (T::From(this)->TileMayHaveSlopedTrack()) {
00136
00137
00138
00139
00140 byte middle_z = GetSlopeZ((this->x_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE, (this->y_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE);
00141
00142 if (middle_z != this->z_pos) {
00143 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00144 }
00145 }
00146 }
00147
00154 FORCEINLINE void UpdateZPosition()
00155 {
00156 #if 0
00157
00158
00159 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00160 switch (this->direction) {
00161 case DIR_NE:
00162 this->z_pos += (this->x_pos & 1); break;
00163 case DIR_SW:
00164 this->z_pos += (this->x_pos & 1) ^ 1; break;
00165 case DIR_NW:
00166 this->z_pos += (this->y_pos & 1); break;
00167 case DIR_SE:
00168 this->z_pos += (this->y_pos & 1) ^ 1; break;
00169 default: break;
00170 }
00171 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00172 switch (this->direction) {
00173 case DIR_NE:
00174 this->z_pos -= (this->x_pos & 1); break;
00175 case DIR_SW:
00176 this->z_pos -= (this->x_pos & 1) ^ 1; break;
00177 case DIR_NW:
00178 this->z_pos -= (this->y_pos & 1); break;
00179 case DIR_SE:
00180 this->z_pos -= (this->y_pos & 1) ^ 1; break;
00181 default: break;
00182 }
00183 }
00184
00185
00186
00187 #endif
00188
00189
00190
00191
00192
00193
00194 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00195 if (T::From(this)->HasToUseGetSlopeZ()) {
00196
00197 this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00198 return;
00199 }
00200
00201 DiagDirection dir = DirToDiagDir(this->direction);
00202
00203 int8 x_pos = this->x_pos;
00204 int8 y_pos = this->y_pos;
00205
00206 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00207
00208 d &= 1;
00209
00210 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00211
00212
00213
00214 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00215 }
00216
00217 assert(this->z_pos == GetSlopeZ(this->x_pos, this->y_pos));
00218 }
00219
00226 FORCEINLINE byte UpdateInclination(bool new_tile, bool turned)
00227 {
00228 byte old_z = this->z_pos;
00229
00230 if (new_tile) {
00231 this->UpdateZPositionAndInclination();
00232 } else {
00233 this->UpdateZPosition();
00234 }
00235
00236 this->UpdateViewport(true, turned);
00237 return old_z;
00238 }
00239
00244 enum GroundVehicleSubtypeFlags {
00245 GVSF_FRONT = 0,
00246 GVSF_ARTICULATED_PART = 1,
00247 GVSF_WAGON = 2,
00248 GVSF_ENGINE = 3,
00249 GVSF_FREE_WAGON = 4,
00250 GVSF_MULTIHEADED = 5,
00251 };
00252
00256 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00257
00261 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00262
00266 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00267
00271 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00272
00276 FORCEINLINE void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00277
00281 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00282
00286 FORCEINLINE void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00287
00291 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00292
00296 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00297
00301 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00302
00306 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00307
00311 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00312
00317 FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, GVSF_FRONT); }
00318
00323 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00324
00329 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00330
00335 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00336
00341 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00342
00347 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00348
00353 FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, GVSF_ARTICULATED_PART); }
00354
00359 FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
00360 };
00361
00362 #endif