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 bool IsChainInDepot() const;
00096
00102 uint Crash(bool flooded)
00103 {
00104
00105 for (T *v = T::From(this); v != NULL; v = v->Next()) {
00106 ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00107 ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00108 }
00109 return this->Vehicle::Crash(flooded);
00110 }
00111
00116 inline int64 GetSlopeResistance() const
00117 {
00118 int64 incl = 0;
00119
00120 for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00121 if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00122 incl += u->gcache.cached_slope_resistance;
00123 } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00124 incl -= u->gcache.cached_slope_resistance;
00125 }
00126 }
00127
00128 return incl;
00129 }
00130
00137 inline void UpdateZPositionAndInclination()
00138 {
00139 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
00140 ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00141 ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00142
00143 if (T::From(this)->TileMayHaveSlopedTrack()) {
00144
00145
00146
00147
00148 int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2));
00149
00150 if (middle_z != this->z_pos) {
00151 SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00152 }
00153 }
00154 }
00155
00162 inline void UpdateZPosition()
00163 {
00164 #if 0
00165
00166
00167 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00168 switch (this->direction) {
00169 case DIR_NE:
00170 this->z_pos += (this->x_pos & 1); break;
00171 case DIR_SW:
00172 this->z_pos += (this->x_pos & 1) ^ 1; break;
00173 case DIR_NW:
00174 this->z_pos += (this->y_pos & 1); break;
00175 case DIR_SE:
00176 this->z_pos += (this->y_pos & 1) ^ 1; break;
00177 default: break;
00178 }
00179 } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00180 switch (this->direction) {
00181 case DIR_NE:
00182 this->z_pos -= (this->x_pos & 1); break;
00183 case DIR_SW:
00184 this->z_pos -= (this->x_pos & 1) ^ 1; break;
00185 case DIR_NW:
00186 this->z_pos -= (this->y_pos & 1); break;
00187 case DIR_SE:
00188 this->z_pos -= (this->y_pos & 1) ^ 1; break;
00189 default: break;
00190 }
00191 }
00192
00193
00194
00195 #endif
00196
00197
00198
00199
00200
00201
00202 if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00203 if (T::From(this)->HasToUseGetSlopePixelZ()) {
00204
00205 this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos);
00206 return;
00207 }
00208
00209 DiagDirection dir = DirToDiagDir(this->direction);
00210
00211 int8 x_pos = this->x_pos;
00212 int8 y_pos = this->y_pos;
00213
00214 int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00215
00216 d &= 1;
00217
00218 d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00219
00220
00221
00222 this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00223 }
00224
00225 assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos));
00226 }
00227
00234 inline byte UpdateInclination(bool new_tile, bool update_delta)
00235 {
00236 byte old_z = this->z_pos;
00237
00238 if (new_tile) {
00239 this->UpdateZPositionAndInclination();
00240 } else {
00241 this->UpdateZPosition();
00242 }
00243
00244 this->UpdateViewport(true, update_delta);
00245 return old_z;
00246 }
00247
00251 inline void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00252
00256 inline void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00257
00261 inline void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00262
00266 inline void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00267
00271 inline void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00272
00276 inline void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00277
00281 inline void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00282
00286 inline void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00287
00291 inline void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00292
00296 inline void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00297
00301 inline void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00302
00306 inline void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00307
00312 inline bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00313
00318 inline bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00319
00324 inline bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00325
00330 inline bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00331
00336 inline bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00337
00343 inline void SetLastSpeed()
00344 {
00345 if (this->cur_speed != this->gcache.last_speed) {
00346 SetWindowWidgetDirty(WC_VEHICLE_VIEW, this->index, WID_VV_START_STOP);
00347 this->gcache.last_speed = this->cur_speed;
00348 }
00349 }
00350
00351 protected:
00365 inline uint DoUpdateSpeed(uint accel, int min_speed, int max_speed)
00366 {
00367 uint spd = this->subspeed + accel;
00368 this->subspeed = (byte)spd;
00369
00370
00371
00372 int tempmax = max_speed;
00373 if (this->cur_speed > max_speed) {
00374 tempmax = max(this->cur_speed - (this->cur_speed / 10) - 1, max_speed);
00375 }
00376
00377
00378
00379
00380
00381
00382 this->cur_speed = spd = max(min(this->cur_speed + ((int)spd >> 8), tempmax), min_speed);
00383
00384 int scaled_spd = this->GetAdvanceSpeed(spd);
00385
00386 scaled_spd += this->progress;
00387 this->progress = 0;
00388 return scaled_spd;
00389 }
00390 };
00391
00392 #endif