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 "vehicle_gui.h"
00017 #include "landscape.h"
00018 #include "window_func.h"
00019
00021 enum AccelStatus {
00022 AS_ACCEL,
00023 AS_BRAKE
00024 };
00025
00030 struct GroundVehicleCache {
00031
00032 uint32 cached_weight;
00033 uint32 cached_slope_resistance;
00034 uint32 cached_max_te;
00035 uint16 cached_axle_resistance;
00036
00037
00038 uint16 cached_max_track_speed;
00039 uint32 cached_power;
00040 uint32 cached_air_drag;
00041
00042
00043 uint16 cached_total_length;
00044 EngineID first_engine;
00045 uint8 cached_veh_length;
00046
00047
00048 uint16 last_speed;
00049 };
00050
00052 enum GroundVehicleFlags {
00053 GVF_GOINGUP_BIT = 0,
00054 GVF_GOINGDOWN_BIT = 1,
00055 GVF_SUPPRESS_IMPLICIT_ORDERS = 2,
00056 };
00057
00079 template <class T, VehicleType Type>
00080 struct GroundVehicle : public SpecializedVehicle<T, Type> {
00081 GroundVehicleCache gcache;
00082 uint16 gv_flags;
00083
00084 typedef GroundVehicle<T, Type> GroundVehicleBase;
00085
00089 GroundVehicle() : SpecializedVehicle<T, Type>() {}
00090
00091 void PowerChanged();
00092 void CargoChanged();
00093 void CalculatePower(uint32& power, uint32& max_te, bool breakdowns) const;
00094 int GetAcceleration();
00095
00101 uint Crash(bool flooded)
00102 {
00103
00104 for (T *v = T::From(this); v != NULL; v = v->Next()) {
00105 ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00106 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00107 }
00108 return this->Vehicle::Crash(flooded);
00109 }
00110
00115 FORCEINLINE int32 GetSlopeResistance() const
00116 {
00117 int32 incl = 0;
00118
00119 for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00120 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00121 incl += u->gcache.cached_slope_resistance;
00122 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00123 incl -= u->gcache.cached_slope_resistance;
00124 }
00125 }
00126
00127 return incl;
00128 }
00129
00136 FORCEINLINE void UpdateZPositionAndInclination()
00137 {
00138 this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00139 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00140 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00141
00142 if (T::From(this)->TileMayHaveSlopedTrack()) {
00143
00144
00145
00146
00147 int middle_z = GetSlopeZ((this->x_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE, (this->y_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE);
00148
00149 if (middle_z != this->z_pos) {
00150 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00151 }
00152 }
00153 }
00154
00159 FORCEINLINE void UpdateZPosition()
00160 {
00161
00162 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00163 this->z_pos = (int)GetSlopeZ(this->x_pos, this->y_pos);
00164 } else {
00165
00166 assert(this->z_pos == (int)GetSlopeZ(this->x_pos, this->y_pos));
00167 }
00168 }
00169
00176 FORCEINLINE int32 UpdateInclination(bool new_tile, bool turned)
00177 {
00178 int32 old_z = this->z_pos;
00179
00180 if (new_tile) {
00181 this->UpdateZPositionAndInclination();
00182 } else {
00183 this->UpdateZPosition();
00184 }
00185
00186 this->UpdateViewport(true, turned);
00187 return old_z;
00188 }
00189
00193 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00194
00198 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00199
00203 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00204
00208 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00209
00213 FORCEINLINE void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00214
00218 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00219
00223 FORCEINLINE void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00224
00228 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00229
00233 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00234
00238 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00239
00243 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00244
00248 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00249
00254 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00255
00260 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00261
00266 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00267
00272 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00273
00278 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00279
00285 FORCEINLINE void SetLastSpeed()
00286 {
00287 if (this->cur_speed != this->gcache.last_speed) {
00288 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
00289 this->gcache.last_speed = this->cur_speed;
00290 }
00291 }
00292
00293 protected:
00307 FORCEINLINE uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
00308 {
00309 uint spd = this->subspeed + accel;
00310 this->subspeed = (byte)spd;
00311
00312
00313
00314 int tempmax = ((this->breakdown_ctr == 1) ? this->cur_speed : max_speed);
00315
00316 if (this->breakdown_ctr == 1) {
00317 if (this->breakdown_type == BREAKDOWN_LOW_POWER) {
00318 if((this->tick_counter & 0x7) == 0) {
00319 if(this->cur_speed > (this->breakdown_severity * max_speed) >> 8) {
00320 tempmax = this->cur_speed - (this->cur_speed / 10) - 1;
00321 } else {
00322 tempmax = (this->breakdown_severity * max_speed) >> 8;
00323 }
00324 }
00325 }
00326
00327 if(this->breakdown_type == BREAKDOWN_LOW_SPEED)
00328 tempmax = min(max_speed, this->breakdown_severity);
00329 }
00330
00331 if (this->cur_speed > max_speed) {
00332 tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
00333 }
00334
00335
00336
00337
00338
00339
00340 this->cur_speed = spd = max(min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
00341
00342 int scaled_spd = this->GetAdvanceSpeed(spd);
00343
00344 scaled_spd += this->progress;
00345 this->progress = 0;
00346 return scaled_spd;
00347 }
00348 };
00349
00350 #endif