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 #include "widgets/vehicle_widget.h"
00020
00022 enum AccelStatus {
00023 AS_ACCEL,
00024 AS_BRAKE,
00025 };
00026
00031 struct GroundVehicleCache {
00032
00033 uint32 cached_weight;
00034 uint32 cached_slope_resistance;
00035 uint32 cached_max_te;
00036 uint16 cached_axle_resistance;
00037
00038
00039 uint16 cached_max_track_speed;
00040 uint32 cached_power;
00041 uint32 cached_air_drag;
00042
00043
00044 uint16 cached_total_length;
00045 EngineID first_engine;
00046 uint8 cached_veh_length;
00047
00048
00049 uint16 last_speed;
00050 };
00051
00053 enum GroundVehicleFlags {
00054 GVF_GOINGUP_BIT = 0,
00055 GVF_GOINGDOWN_BIT = 1,
00056 GVF_SUPPRESS_IMPLICIT_ORDERS = 2,
00057 };
00058
00080 template <class T, VehicleType Type>
00081 struct GroundVehicle : public SpecializedVehicle<T, Type> {
00082 GroundVehicleCache gcache;
00083 uint16 gv_flags;
00084
00085 typedef GroundVehicle<T, Type> GroundVehicleBase;
00086
00090 GroundVehicle() : SpecializedVehicle<T, Type>() {}
00091
00092 void PowerChanged();
00093 void CargoChanged();
00094 int GetAcceleration() const;
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 inline 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 inline void UpdateZPositionAndInclination()
00137 {
00138 this->z_pos = GetSlopePixelZ(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 = GetSlopePixelZ((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
00161 inline void UpdateZPosition()
00162 {
00163 #if 0
00164
00165
00166 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00167 switch (this->direction) {
00168 case DIR_NE:
00169 this->z_pos += (this->x_pos & 1); break;
00170 case DIR_SW:
00171 this->z_pos += (this->x_pos & 1) ^ 1; break;
00172 case DIR_NW:
00173 this->z_pos += (this->y_pos & 1); break;
00174 case DIR_SE:
00175 this->z_pos += (this->y_pos & 1) ^ 1; break;
00176 default: break;
00177 }
00178 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00179 switch (this->direction) {
00180 case DIR_NE:
00181 this->z_pos -= (this->x_pos & 1); break;
00182 case DIR_SW:
00183 this->z_pos -= (this->x_pos & 1) ^ 1; break;
00184 case DIR_NW:
00185 this->z_pos -= (this->y_pos & 1); break;
00186 case DIR_SE:
00187 this->z_pos -= (this->y_pos & 1) ^ 1; break;
00188 default: break;
00189 }
00190 }
00191
00192
00193
00194 #endif
00195
00196
00197
00198
00199
00200
00201 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00202 if (T::From(this)->HasToUseGetSlopePixelZ()) {
00203
00204 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
00205 return;
00206 }
00207
00208 DiagDirection dir = DirToDiagDir(this->direction);
00209
00210 int8 x_pos = this->x_pos;
00211 int8 y_pos = this->y_pos;
00212
00213 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00214
00215 d &= 1;
00216
00217 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00218
00219
00220
00221 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00222 }
00223
00224 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
00225 }
00226
00233 inline byte UpdateInclination(bool new_tile, bool update_delta)
00234 {
00235 byte old_z = this->z_pos;
00236
00237 if (new_tile) {
00238 this->UpdateZPositionAndInclination();
00239 } else {
00240 this->UpdateZPosition();
00241 }
00242
00243 this->UpdateViewport(true, update_delta);
00244 return old_z;
00245 }
00246
00250 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00251
00255 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00256
00260 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00261
00265 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00266
00270 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00271
00275 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00276
00280 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00281
00285 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00286
00290 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00291
00295 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00296
00300 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00301
00305 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00306
00311 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00312
00317 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00318
00323 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00324
00329 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00330
00335 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00336
00342 inline void SetLastSpeed()
00343 {
00344 if (this->cur_speed != this->gcache.last_speed) {
00345 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
00346 this->gcache.last_speed = this->cur_speed;
00347 }
00348 }
00349
00350 protected:
00364 inline 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