ground_vehicle.hpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #ifndef GROUND_VEHICLE_HPP
00013 #define GROUND_VEHICLE_HPP
00014 
00015 #include "vehicle_base.h"
00016 #include "landscape.h"
00017 
00019 enum AccelStatus {
00020   AS_ACCEL, 
00021   AS_BRAKE  
00022 };
00023 
00028 struct GroundVehicleCache {
00029   /* Cached acceleration values, recalculated when the cargo on a vehicle changes (in addition to the conditions below) */
00030   uint32 cached_weight;           
00031   uint32 cached_slope_resistance; 
00032   uint32 cached_max_te;           
00033   uint16 cached_axle_resistance;  
00034 
00035   /* Cached acceleration values, recalculated on load and each time a vehicle is added to/removed from the consist. */
00036   uint16 cached_max_track_speed;  
00037   uint32 cached_power;            
00038   uint32 cached_air_drag;         
00039 
00040   /* Cached NewGRF values, recalculated on load and each time a vehicle is added to/removed from the consist. */
00041   uint16 cached_total_length;     
00042   EngineID first_engine;          
00043   uint8 cached_veh_length;        
00044 };
00045 
00047 enum GroundVehicleFlags {
00048   GVF_GOINGUP_BIT       = 0,
00049   GVF_GOINGDOWN_BIT     = 1,
00050 };
00051 
00073 template <class T, VehicleType Type>
00074 struct GroundVehicle : public SpecializedVehicle<T, Type> {
00075   GroundVehicleCache gcache; 
00076   uint16 gv_flags;           
00077 
00078   typedef GroundVehicle<T, Type> GroundVehicleBase; 
00079 
00083   GroundVehicle() : SpecializedVehicle<T, Type>() {}
00084 
00085   void PowerChanged();
00086   void CargoChanged();
00087   int GetAcceleration() const;
00088 
00094   /* virtual */ uint Crash(bool flooded)
00095   {
00096     /* Crashed vehicles aren't going up or down */
00097     for (T *v = T::From(this); v != NULL; v = v->Next()) {
00098       ClrBit(v->gv_flags, GVF_GOINGUP_BIT);
00099       ClrBit(v->gv_flags, GVF_GOINGDOWN_BIT);
00100     }
00101     return this->Vehicle::Crash(flooded);
00102   }
00103 
00108   FORCEINLINE int32 GetSlopeResistance() const
00109   {
00110     int32 incl = 0;
00111 
00112     for (const T *u = T::From(this); u != NULL; u = u->Next()) {
00113       if (HasBit(u->gv_flags, GVF_GOINGUP_BIT)) {
00114         incl += u->gcache.cached_slope_resistance;
00115       } else if (HasBit(u->gv_flags, GVF_GOINGDOWN_BIT)) {
00116         incl -= u->gcache.cached_slope_resistance;
00117       }
00118     }
00119 
00120     return incl;
00121   }
00122 
00129   FORCEINLINE void UpdateZPositionAndInclination()
00130   {
00131     this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00132     ClrBit(this->gv_flags, GVF_GOINGUP_BIT);
00133     ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT);
00134 
00135     if (T::From(this)->TileMayHaveSlopedTrack()) {
00136       /* To check whether the current tile is sloped, and in which
00137        * direction it is sloped, we get the 'z' at the center of
00138        * the tile (middle_z) and the edge of the tile (old_z),
00139        * which we then can compare. */
00140       byte middle_z = GetSlopeZ((this->x_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE, (this->y_pos & ~TILE_UNIT_MASK) | HALF_TILE_SIZE);
00141 
00142       if (middle_z != this->z_pos) {
00143         SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT);
00144       }
00145     }
00146   }
00147 
00154   FORCEINLINE void UpdateZPosition()
00155   {
00156 #if 0
00157     /* The following code does this: */
00158 
00159     if (HasBit(this->gv_flags, GVF_GOINGUP_BIT)) {
00160       switch (this->direction) {
00161         case DIR_NE:
00162           this->z_pos += (this->x_pos & 1); break;
00163         case DIR_SW:
00164           this->z_pos += (this->x_pos & 1) ^ 1; break;
00165         case DIR_NW:
00166           this->z_pos += (this->y_pos & 1); break;
00167         case DIR_SE:
00168           this->z_pos += (this->y_pos & 1) ^ 1; break;
00169         default: break;
00170       }
00171     } else if (HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00172       switch (this->direction) {
00173         case DIR_NE:
00174           this->z_pos -= (this->x_pos & 1); break;
00175         case DIR_SW:
00176           this->z_pos -= (this->x_pos & 1) ^ 1; break;
00177         case DIR_NW:
00178           this->z_pos -= (this->y_pos & 1); break;
00179         case DIR_SE:
00180           this->z_pos -= (this->y_pos & 1) ^ 1; break;
00181         default: break;
00182       }
00183     }
00184 
00185     /* But gcc 4.4.5 isn't able to nicely optimise it, and the resulting
00186      * code is full of conditional jumps. */
00187 #endif
00188 
00189     /* Vehicle's Z position can change only if it has GVF_GOINGUP_BIT or GVF_GOINGDOWN_BIT set.
00190      * Furthermore, if this function is called once every time the vehicle's position changes,
00191      * we know the Z position changes by +/-1 at certain moments - when x_pos, y_pos is odd/even,
00192      * depending on orientation of the slope and vehicle's direction */
00193 
00194     if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) {
00195       if (T::From(this)->HasToUseGetSlopeZ()) {
00196         /* In some cases, we have to use GetSlopeZ() */
00197         this->z_pos = GetSlopeZ(this->x_pos, this->y_pos);
00198         return;
00199       }
00200       /* DirToDiagDir() is a simple right shift */
00201       DiagDirection dir = DirToDiagDir(this->direction);
00202       /* Read variables, so the compiler knows the access doesn't trap */
00203       int8 x_pos = this->x_pos;
00204       int8 y_pos = this->y_pos;
00205       /* DiagDirToAxis() is a simple mask */
00206       int8 d = DiagDirToAxis(dir) == AXIS_X ? x_pos : y_pos;
00207       /* We need only the least significant bit */
00208       d &= 1;
00209       /* Conditional "^ 1". Optimised to "(dir - 1) <= 1". */
00210       d ^= (int8)(dir == DIAGDIR_SW || dir == DIAGDIR_SE);
00211       /* Subtraction instead of addition because we are testing for GVF_GOINGUP_BIT.
00212        * GVF_GOINGUP_BIT is used because it's bit 0, so simple AND can be used,
00213        * without any shift */
00214       this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d;
00215     }
00216 
00217     assert(this->z_pos == GetSlopeZ(this->x_pos, this->y_pos));
00218   }
00219 
00226   FORCEINLINE byte UpdateInclination(bool new_tile, bool turned)
00227   {
00228     byte old_z = this->z_pos;
00229 
00230     if (new_tile) {
00231       this->UpdateZPositionAndInclination();
00232     } else {
00233       this->UpdateZPosition();
00234     }
00235 
00236     this->UpdateViewport(true, turned);
00237     return old_z;
00238   }
00239 
00244   enum GroundVehicleSubtypeFlags {
00245     GVSF_FRONT            = 0, 
00246     GVSF_ARTICULATED_PART = 1, 
00247     GVSF_WAGON            = 2, 
00248     GVSF_ENGINE           = 3, 
00249     GVSF_FREE_WAGON       = 4, 
00250     GVSF_MULTIHEADED      = 5, 
00251   };
00252 
00256   FORCEINLINE void SetFrontEngine() { SetBit(this->subtype, GVSF_FRONT); }
00257 
00261   FORCEINLINE void ClearFrontEngine() { ClrBit(this->subtype, GVSF_FRONT); }
00262 
00266   FORCEINLINE void SetArticulatedPart() { SetBit(this->subtype, GVSF_ARTICULATED_PART); }
00267 
00271   FORCEINLINE void ClearArticulatedPart() { ClrBit(this->subtype, GVSF_ARTICULATED_PART); }
00272 
00276   FORCEINLINE void SetWagon() { SetBit(this->subtype, GVSF_WAGON); }
00277 
00281   FORCEINLINE void ClearWagon() { ClrBit(this->subtype, GVSF_WAGON); }
00282 
00286   FORCEINLINE void SetEngine() { SetBit(this->subtype, GVSF_ENGINE); }
00287 
00291   FORCEINLINE void ClearEngine() { ClrBit(this->subtype, GVSF_ENGINE); }
00292 
00296   FORCEINLINE void SetFreeWagon() { SetBit(this->subtype, GVSF_FREE_WAGON); }
00297 
00301   FORCEINLINE void ClearFreeWagon() { ClrBit(this->subtype, GVSF_FREE_WAGON); }
00302 
00306   FORCEINLINE void SetMultiheaded() { SetBit(this->subtype, GVSF_MULTIHEADED); }
00307 
00311   FORCEINLINE void ClearMultiheaded() { ClrBit(this->subtype, GVSF_MULTIHEADED); }
00312 
00317   FORCEINLINE bool IsFrontEngine() const { return HasBit(this->subtype, GVSF_FRONT); }
00318 
00323   FORCEINLINE bool IsFreeWagon() const { return HasBit(this->subtype, GVSF_FREE_WAGON); }
00324 
00329   FORCEINLINE bool IsEngine() const { return HasBit(this->subtype, GVSF_ENGINE); }
00330 
00335   FORCEINLINE bool IsWagon() const { return HasBit(this->subtype, GVSF_WAGON); }
00336 
00341   FORCEINLINE bool IsMultiheaded() const { return HasBit(this->subtype, GVSF_MULTIHEADED); }
00342 
00347   FORCEINLINE bool IsRearDualheaded() const { return this->IsMultiheaded() && !this->IsEngine(); }
00348 
00353   FORCEINLINE bool IsArticulatedPart() const { return HasBit(this->subtype, GVSF_ARTICULATED_PART); }
00354 
00359   FORCEINLINE bool HasArticulatedPart() const { return this->Next() != NULL && this->Next()->IsArticulatedPart(); }
00360 };
00361 
00362 #endif /* GROUND_VEHICLE_HPP */

Generated on Sun Jan 23 01:49:02 2011 for OpenTTD by  doxygen 1.6.1