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 int GetAcceleration() const;
00094
00100 uint Crash(bool flooded)
00101 {
00102
00103 for (T *v = T::From(this); v != NULL; v = v->Next()) {
00104 ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00105 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00106 }
00107 return this->Vehicle::Crash(flooded);
00108 }
00109
00114 inline int32 GetSlopeResistance() const
00115 {
00116 int32 incl = 0;
00117
00118 for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00119 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00120 incl += u->gcache.cached_slope_resistance;
00121 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00122 incl -= u->gcache.cached_slope_resistance;
00123 }
00124 }
00125
00126 return incl;
00127 }
00128
00135 inline void UpdateZPositionAndInclination()
00136 {
00137 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
00138 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00139 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00140
00141 if (T::From(this)->TileMayHaveSlopedTrack()) {
00142
00143
00144
00145
00146 int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE, (this->y_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE);
00147
00148 if (middle_z != this->z_pos) {
00149 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00150 }
00151 }
00152 }
00153
00160 inline void UpdateZPosition()
00161 {
00162 #if 0
00163
00164
00165 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00166 switch (this->direction) {
00167 case DIR_NE:
00168 this->z_pos += (this->x_pos & 1); break;
00169 case DIR_SW:
00170 this->z_pos += (this->x_pos & 1) ^ 1; break;
00171 case DIR_NW:
00172 this->z_pos += (this->y_pos & 1); break;
00173 case DIR_SE:
00174 this->z_pos += (this->y_pos & 1) ^ 1; break;
00175 default: break;
00176 }
00177 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00178 switch (this->direction) {
00179 case DIR_NE:
00180 this->z_pos -= (this->x_pos & 1); break;
00181 case DIR_SW:
00182 this->z_pos -= (this->x_pos & 1) ^ 1; break;
00183 case DIR_NW:
00184 this->z_pos -= (this->y_pos & 1); break;
00185 case DIR_SE:
00186 this->z_pos -= (this->y_pos & 1) ^ 1; break;
00187 default: break;
00188 }
00189 }
00190
00191
00192
00193 #endif
00194
00195
00196
00197
00198
00199
00200 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00201 if (T::From(this)->HasToUseGetSlopePixelZ()) {
00202
00203 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
00204 return;
00205 }
00206
00207 DiagDirection dir = DirToDiagDir(this->direction);
00208
00209 int8 x_pos = this->x_pos;
00210 int8 y_pos = this->y_pos;
00211
00212 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00213
00214 d &= 1;
00215
00216 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00217
00218
00219
00220 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00221 }
00222
00223 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
00224 }
00225
00232 inline byte UpdateInclination(bool new_tile, bool turned)
00233 {
00234 byte old_z = this->z_pos;
00235
00236 if (new_tile) {
00237 this->UpdateZPositionAndInclination();
00238 } else {
00239 this->UpdateZPosition();
00240 }
00241
00242 this->UpdateViewport(true, turned);
00243 return old_z;
00244 }
00245
00249 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00250
00254 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00255
00259 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00260
00264 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00265
00269 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00270
00274 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00275
00279 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00280
00284 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00285
00289 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00290
00294 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00295
00299 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00300
00304 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00305
00310 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00311
00316 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00317
00322 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00323
00328 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00329
00334 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00335
00341 inline void SetLastSpeed()
00342 {
00343 if (this->cur_speed != this->gcache.last_speed) {
00344 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
00345 this->gcache.last_speed = this->cur_speed;
00346 }
00347 }
00348
00349 protected:
00363 inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
00364 {
00365 uint spd = this->subspeed + accel;
00366 this->subspeed = (byte)spd;
00367
00368
00369
00370 int tempmax = max_speed;
00371 if (this->cur_speed > max_speed) {
00372 tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
00373 }
00374
00375
00376
00377
00378
00379
00380 this->cur_speed = spd = max(min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
00381
00382 int scaled_spd = this->GetAdvanceSpeed(spd);
00383
00384 scaled_spd += this->progress;
00385 this->progress = 0;
00386 return scaled_spd;
00387 }
00388 };
00389
00390 #endif