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 };
00056
00078 template <class T, VehicleType Type>
00079 struct GroundVehicle : public SpecializedVehicle<T, Type> {
00080 GroundVehicleCache gcache;
00081 uint16 gv_flags;
00082
00083 typedef GroundVehicle<T, Type> GroundVehicleBase;
00084
00088 GroundVehicle() : SpecializedVehicle<T, Type>() {}
00089
00090 void PowerChanged();
00091 void CargoChanged();
00092 int GetAcceleration() const;
00093
00099 uint Crash(bool flooded)
00100 {
00101
00102 for (T *v = T::From(this); v != NULL; v = v->Next()) {
00103 ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00104 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00105 }
00106 return this->Vehicle::Crash(flooded);
00107 }
00108
00113 FORCEINLINE int32 GetSlopeResistance() const
00114 {
00115 int32 incl = 0;
00116
00117 for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00118 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00119 incl += u->gcache.cached_slope_resistance;
00120 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00121 incl -= u->gcache.cached_slope_resistance;
00122 }
00123 }
00124
00125 return incl;
00126 }
00127
00134 FORCEINLINE void UpdateZPositionAndInclination()
00135 {
00136 this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00137 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00138 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00139
00140 if (T::From(this)->TileMayHaveSlopedTrack()) {
00141
00142
00143
00144
00145 byte middle_z = GetSlopeZ((this->x_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE, (this->y_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE);
00146
00147 if (middle_z != this->z_pos) {
00148 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00149 }
00150 }
00151 }
00152
00159 FORCEINLINE void UpdateZPosition()
00160 {
00161 #if 0
00162
00163
00164 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00165 switch (this->direction) {
00166 case DIR_NE:
00167 this->z_pos += (this->x_pos & 1); break;
00168 case DIR_SW:
00169 this->z_pos += (this->x_pos & 1) ^ 1; break;
00170 case DIR_NW:
00171 this->z_pos += (this->y_pos & 1); break;
00172 case DIR_SE:
00173 this->z_pos += (this->y_pos & 1) ^ 1; break;
00174 default: break;
00175 }
00176 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00177 switch (this->direction) {
00178 case DIR_NE:
00179 this->z_pos -= (this->x_pos & 1); break;
00180 case DIR_SW:
00181 this->z_pos -= (this->x_pos & 1) ^ 1; break;
00182 case DIR_NW:
00183 this->z_pos -= (this->y_pos & 1); break;
00184 case DIR_SE:
00185 this->z_pos -= (this->y_pos & 1) ^ 1; break;
00186 default: break;
00187 }
00188 }
00189
00190
00191
00192 #endif
00193
00194
00195
00196
00197
00198
00199 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00200 if (T::From(this)->HasToUseGetSlopeZ()) {
00201
00202 this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00203 return;
00204 }
00205
00206 DiagDirection dir = DirToDiagDir(this->direction);
00207
00208 int8 x_pos = this->x_pos;
00209 int8 y_pos = this->y_pos;
00210
00211 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00212
00213 d &= 1;
00214
00215 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00216
00217
00218
00219 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00220 }
00221
00222 assert(this->z_pos == GetSlopeZ(this->x_pos, this->y_pos));
00223 }
00224
00231 FORCEINLINE byte UpdateInclination(bool new_tile, bool turned)
00232 {
00233 byte old_z = this->z_pos;
00234
00235 if (new_tile) {
00236 this->UpdateZPositionAndInclination();
00237 } else {
00238 this->UpdateZPosition();
00239 }
00240
00241 this->UpdateViewport(true, turned);
00242 return old_z;
00243 }
00244
00248 FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00249
00253 FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00254
00258 FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00259
00263 FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00264
00268 FORCEINLINE void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00269
00273 FORCEINLINE void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00274
00278 FORCEINLINE void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00279
00283 FORCEINLINE void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00284
00288 FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00289
00293 FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00294
00298 FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00299
00303 FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00304
00309 FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00310
00315 FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00316
00321 FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00322
00327 FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00328
00333 FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00334
00340 FORCEINLINE void SetLastSpeed()
00341 {
00342 if (this->cur_speed != this->gcache.last_speed) {
00343 if ((this->gcache.last_speed == 0) != (this->cur_speed == 0)) {
00344 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, VVW_WIDGET_START_STOP_VEH);
00345 }
00346 this->gcache.last_speed = this->cur_speed;
00347 }
00348 }
00349
00350 protected:
00364 FORCEINLINE uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
00365 {
00366 uint spd = this->subspeed + accel;
00367 this->subspeed = (byte)spd;
00368
00369
00370
00371 int tempmax = max_speed;
00372 if (this->cur_speed > max_speed) {
00373 tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
00374 }
00375
00376
00377
00378
00379
00380
00381 this->cur_speed = spd = max(min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
00382
00383 int scaled_spd = this->GetAdvanceSpeed(spd);
00384
00385 scaled_spd += this->progress;
00386 this->progress = 0;
00387 return scaled_spd;
00388 }
00389 };
00390
00391 #endif