1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ 2 3 #ifndef SOLID_OBJECT_H 4 #define SOLID_OBJECT_H 5 6 #include "WorldObject.h" 7 #include "System/bitops.h" 8 #include "System/Matrix44f.h" 9 #include "System/type2.h" 10 #include "System/Misc/BitwiseEnum.h" 11 #include "System/Sync/SyncedFloat3.h" 12 #include "System/Sync/SyncedPrimitive.h" 13 14 struct MoveDef; 15 struct CollisionVolume; 16 struct LocalModelPiece; 17 struct SolidObjectDef; 18 struct SolidObjectGroundDecal; 19 20 struct DamageArray; 21 class CUnit; 22 23 enum TerrainChangeTypes { 24 TERRAINCHANGE_DAMAGE_RECALCULATION = 0, // update after regular explosion or terraform event 25 TERRAINCHANGE_SQUARE_TYPEMAP_INDEX = 1, // update after typemap-index of a square changed (Lua) 26 TERRAINCHANGE_TYPEMAP_SPEED_VALUES = 2, // update after speed-values of a terrain-type changed (Lua) 27 TERRAINCHANGE_OBJECT_INSERTED = 3, 28 TERRAINCHANGE_OBJECT_INSERTED_YM = 4, 29 TERRAINCHANGE_OBJECT_DELETED = 5, 30 }; 31 32 enum YardmapStates { 33 YARDMAP_OPEN = 0, // always free ( walkable buildable) 34 // YARDMAP_WALKABLE = 4, // open for walk ( walkable, not buildable) 35 YARDMAP_YARD = 1, // walkable when yard is open 36 YARDMAP_YARDINV = 2, // walkable when yard is closed 37 YARDMAP_BLOCKED = 0xFF & ~YARDMAP_YARDINV, // always block (not walkable, not buildable) 38 39 // helpers 40 YARDMAP_YARDBLOCKED = YARDMAP_YARD, 41 YARDMAP_YARDFREE = ~YARDMAP_YARD, 42 YARDMAP_GEO = YARDMAP_BLOCKED, 43 }; 44 typedef Bitwise::BitwiseEnum<YardmapStates> YardMapStatus; 45 46 47 48 class CSolidObject: public CWorldObject { 49 public: 50 CR_DECLARE(CSolidObject) 51 52 enum PhysicalState { 53 // NOTE: 54 // {ONGROUND,*WATER} and INAIR are mutually exclusive 55 // {UNDERGROUND,UNDERWATER} are not (and are the only 56 // bits to take radius into account) 57 // TODO: 58 // should isDead be on this list for spatial queries? 59 PSTATE_BIT_ONGROUND = (1 << 0), 60 PSTATE_BIT_INWATER = (1 << 1), 61 PSTATE_BIT_UNDERWATER = (1 << 2), 62 PSTATE_BIT_UNDERGROUND = (1 << 3), 63 PSTATE_BIT_INAIR = (1 << 4), 64 PSTATE_BIT_INVOID = (1 << 5), 65 66 // special bits for impulse-affected objects that do 67 // not get set automatically by UpdatePhysicalState; 68 // also used by aircraft to control block / unblock 69 // behavior 70 // NOTE: FLYING DOES NOT ALWAYS IMPLY INAIR! 71 PSTATE_BIT_MOVING = (1 << 6), 72 PSTATE_BIT_FLYING = (1 << 7), 73 PSTATE_BIT_FALLING = (1 << 8), 74 PSTATE_BIT_SKIDDING = (1 << 9), 75 PSTATE_BIT_CRASHING = (1 << 10), 76 PSTATE_BIT_BLOCKING = (1 << 11), 77 }; 78 enum CollidableState { 79 CSTATE_BIT_SOLIDOBJECTS = (1 << 0), // can be set while (physicalState & PSTATE_BIT_BLOCKING) == 0! 80 CSTATE_BIT_PROJECTILES = (1 << 1), 81 CSTATE_BIT_QUADMAPRAYS = (1 << 2), 82 }; 83 enum DamageType { 84 DAMAGE_EXPLOSION_WEAPON = 0, // weapon-projectile that triggered GameHelper::Explosion (weaponDefID >= 0) 85 DAMAGE_EXPLOSION_DEBRIS = 1, // piece-projectile that triggered GameHelper::Explosion (weaponDefID < 0) 86 DAMAGE_COLLISION_GROUND = 2, // ground collision 87 DAMAGE_COLLISION_OBJECT = 3, // object collision 88 DAMAGE_EXTSOURCE_FIRE = 4, 89 DAMAGE_EXTSOURCE_WATER = 5, // lava/acid/etc 90 DAMAGE_EXTSOURCE_KILLED = 6, 91 DAMAGE_EXTSOURCE_CRUSHED = 7, 92 }; 93 94 CSolidObject(); 95 virtual ~CSolidObject(); 96 AddBuildPower(CUnit * builder,float amount)97 virtual bool AddBuildPower(CUnit* builder, float amount) { return false; } DoDamage(const DamageArray & damages,const float3 & impulse,CUnit * attacker,int weaponDefID,int projectileID)98 virtual void DoDamage(const DamageArray& damages, const float3& impulse, CUnit* attacker, int weaponDefID, int projectileID) {} 99 ApplyImpulse(const float3 & impulse)100 virtual void ApplyImpulse(const float3& impulse) { SetVelocity(speed + impulse); } 101 102 virtual void Kill(CUnit* killer, const float3& impulse, bool crushed); GetBlockingMapID()103 virtual int GetBlockingMapID() const { return -1; } 104 ForcedMove(const float3 & newPos)105 virtual void ForcedMove(const float3& newPos) {} 106 virtual void ForcedSpin(const float3& newDir); 107 108 virtual void UpdatePhysicalState(float eps); 109 Move(const float3 & v,bool relative)110 void Move(const float3& v, bool relative) { 111 const float3& dv = relative? v: (v - pos); 112 113 pos += dv; 114 midPos += dv; 115 aimPos += dv; 116 } 117 118 // this should be called whenever the direction 119 // vectors are changed (ie. after a rotation) in 120 // eg. movetype code UpdateMidAndAimPos()121 void UpdateMidAndAimPos() { 122 midPos = GetMidPos(); 123 aimPos = GetAimPos(); 124 } SetMidAndAimPos(const float3 & mp,const float3 & ap,bool relative)125 void SetMidAndAimPos(const float3& mp, const float3& ap, bool relative) { 126 SetMidPos(mp, relative); 127 SetAimPos(ap, relative); 128 } 129 130 SetDirVectors(const CMatrix44f & matrix)131 void SetDirVectors(const CMatrix44f& matrix) { 132 rightdir.x = -matrix[0]; updir.x = matrix[4]; frontdir.x = matrix[ 8]; 133 rightdir.y = -matrix[1]; updir.y = matrix[5]; frontdir.y = matrix[ 9]; 134 rightdir.z = -matrix[2]; updir.z = matrix[6]; frontdir.z = matrix[10]; 135 } 136 // update object's <heading> from current frontdir 137 // should always be called after a SetDirVectors() 138 void SetHeadingFromDirection(); 139 // update object's local coor-sys from current <heading> 140 // (unlike ForcedSpin which updates from given <updir>) 141 // NOTE: movetypes call this directly 142 void UpdateDirVectors(bool useGroundNormal); 143 144 virtual CMatrix44f GetTransformMatrix(const bool synced = false, const bool error = false) const { 145 // should never get called (should be pure virtual, but cause of CREG we cannot use it) 146 assert(false); 147 return CMatrix44f(); 148 } 149 GetCollisionVolume(const LocalModelPiece * lmp)150 virtual const CollisionVolume* GetCollisionVolume(const LocalModelPiece* lmp) const { return collisionVolume; } 151 152 153 /** 154 * adds this object to the GroundBlockingMap if and only 155 * if HasCollidableStateBit(CSTATE_BIT_SOLIDOBJECTS), else 156 * does nothing 157 */ 158 void Block(); 159 /** 160 * Removes this object from the GroundBlockingMap if it 161 * is currently marked on it, does nothing otherwise. 162 */ 163 void UnBlock(); 164 165 // these transform a point or vector to object-space GetObjectSpaceVec(const float3 & v)166 float3 GetObjectSpaceVec(const float3& v) const { return ( (frontdir * v.z) + (rightdir * v.x) + (updir * v.y)); } GetObjectSpacePos(const float3 & p)167 float3 GetObjectSpacePos(const float3& p) const { return (pos + (frontdir * p.z) + (rightdir * p.x) + (updir * p.y)); } GetObjectSpacePosUnsynced(const float3 & p)168 float3 GetObjectSpacePosUnsynced(const float3& p) const { return (drawPos + GetObjectSpaceVec(p)); } 169 GetMapPos()170 int2 GetMapPos() const { return (GetMapPos(pos)); } 171 int2 GetMapPos(const float3& position) const; 172 173 float3 GetDragAccelerationVec(const float4& params) const; 174 float3 GetWantedUpDir(bool useGroundNormal) const; 175 176 YardMapStatus GetGroundBlockingMaskAtPos(float3 gpos) const; 177 BlockMapPosChanged()178 bool BlockMapPosChanged() const { return (groundBlockPos != pos); } 179 IsOnGround()180 bool IsOnGround () const { return (HasPhysicalStateBit(PSTATE_BIT_ONGROUND )); } IsInAir()181 bool IsInAir () const { return (HasPhysicalStateBit(PSTATE_BIT_INAIR )); } IsInWater()182 bool IsInWater () const { return (HasPhysicalStateBit(PSTATE_BIT_INWATER )); } IsUnderWater()183 bool IsUnderWater () const { return (HasPhysicalStateBit(PSTATE_BIT_UNDERWATER )); } IsUnderGround()184 bool IsUnderGround() const { return (HasPhysicalStateBit(PSTATE_BIT_UNDERGROUND)); } IsInVoid()185 bool IsInVoid () const { return (HasPhysicalStateBit(PSTATE_BIT_INVOID )); } 186 IsMoving()187 bool IsMoving () const { return (HasPhysicalStateBit(PSTATE_BIT_MOVING )); } IsFlying()188 bool IsFlying () const { return (HasPhysicalStateBit(PSTATE_BIT_FLYING )); } IsFalling()189 bool IsFalling () const { return (HasPhysicalStateBit(PSTATE_BIT_FALLING )); } IsSkidding()190 bool IsSkidding() const { return (HasPhysicalStateBit(PSTATE_BIT_SKIDDING)); } IsCrashing()191 bool IsCrashing() const { return (HasPhysicalStateBit(PSTATE_BIT_CRASHING)); } IsBlocking()192 bool IsBlocking() const { return (HasPhysicalStateBit(PSTATE_BIT_BLOCKING)); } 193 HasPhysicalStateBit(unsigned int bit)194 bool HasPhysicalStateBit(unsigned int bit) const { return ((physicalState & bit) != 0); } SetPhysicalStateBit(unsigned int bit)195 void SetPhysicalStateBit(unsigned int bit) { unsigned int ps = physicalState; ps |= ( bit); physicalState = static_cast<PhysicalState>(ps); } ClearPhysicalStateBit(unsigned int bit)196 void ClearPhysicalStateBit(unsigned int bit) { unsigned int ps = physicalState; ps &= (~bit); physicalState = static_cast<PhysicalState>(ps); } PushPhysicalStateBit(unsigned int bit)197 void PushPhysicalStateBit(unsigned int bit) { UpdatePhysicalStateBit(1u << (32u - (bits_ffs(bit) - 1u)), HasPhysicalStateBit(bit)); } PopPhysicalStateBit(unsigned int bit)198 void PopPhysicalStateBit(unsigned int bit) { UpdatePhysicalStateBit(bit, HasPhysicalStateBit(1u << (32u - (bits_ffs(bit) - 1u)))); } UpdatePhysicalStateBit(unsigned int bit,bool set)199 bool UpdatePhysicalStateBit(unsigned int bit, bool set) { 200 if (set) { 201 SetPhysicalStateBit(bit); 202 } else { 203 ClearPhysicalStateBit(bit); 204 } 205 return (HasPhysicalStateBit(bit)); 206 } 207 HasCollidableStateBit(unsigned int bit)208 bool HasCollidableStateBit(unsigned int bit) const { return ((collidableState & bit) != 0); } SetCollidableStateBit(unsigned int bit)209 void SetCollidableStateBit(unsigned int bit) { unsigned int cs = collidableState; cs |= ( bit); collidableState = static_cast<CollidableState>(cs); } ClearCollidableStateBit(unsigned int bit)210 void ClearCollidableStateBit(unsigned int bit) { unsigned int cs = collidableState; cs &= (~bit); collidableState = static_cast<CollidableState>(cs); } PushCollidableStateBit(unsigned int bit)211 void PushCollidableStateBit(unsigned int bit) { UpdateCollidableStateBit(1u << (32u - (bits_ffs(bit) - 1u)), HasCollidableStateBit(bit)); } PopCollidableStateBit(unsigned int bit)212 void PopCollidableStateBit(unsigned int bit) { UpdateCollidableStateBit(bit, HasCollidableStateBit(1u << (32u - (bits_ffs(bit) - 1u)))); } UpdateCollidableStateBit(unsigned int bit,bool set)213 bool UpdateCollidableStateBit(unsigned int bit, bool set) { 214 if (set) { 215 SetCollidableStateBit(bit); 216 } else { 217 ClearCollidableStateBit(bit); 218 } 219 return (HasCollidableStateBit(bit)); 220 } 221 222 bool SetVoidState(); 223 bool ClearVoidState(); 224 void UpdateVoidState(bool set); 225 226 private: SetMidPos(const float3 & mp,bool relative)227 void SetMidPos(const float3& mp, bool relative) { 228 if (relative) { 229 relMidPos = mp; midPos = GetMidPos(); 230 } else { 231 midPos = mp; relMidPos = midPos - pos; 232 } 233 } SetAimPos(const float3 & ap,bool relative)234 void SetAimPos(const float3& ap, bool relative) { 235 if (relative) { 236 relAimPos = ap; aimPos = GetAimPos(); 237 } else { 238 aimPos = ap; relAimPos = aimPos - pos; 239 } 240 } 241 GetMidPos()242 float3 GetMidPos() const { return (GetObjectSpacePos(relMidPos)); } GetAimPos()243 float3 GetAimPos() const { return (GetObjectSpacePos(relAimPos)); } 244 245 public: 246 float health; 247 float mass; ///< the physical mass of this object (run-time constant) 248 float crushResistance; ///< how much MoveDef::crushStrength is required to crush this object (run-time constant) 249 250 bool crushable; ///< whether this object can potentially be crushed during a collision with another object 251 bool immobile; ///< whether this object can be moved or not (except perhaps along y-axis, to make it stay on ground) 252 bool blockEnemyPushing; ///< if false, object can be pushed during enemy collisions even when modrules forbid it 253 bool blockHeightChanges; ///< if true, map height cannot change under this object (through explosions, etc.) 254 255 bool luaDraw; ///< if true, LuaRules::Draw{Unit, Feature} will be called for this object (UNSYNCED) 256 bool noSelect; ///< if true, unit/feature can not be selected/mouse-picked by a player (UNSYNCED) 257 258 int xsize; ///< The x-size of this object, according to its footprint. (Note: this is rotated depending on buildFacing!!!) 259 int zsize; ///< The z-size of this object, according to its footprint. (Note: this is rotated depending on buildFacing!!!) 260 int2 footprint; ///< The unrotated x-/z-size of this object, according to its footprint. 261 262 SyncedSshort heading; ///< Contains the same information as frontdir, but in a short signed integer. 263 PhysicalState physicalState; ///< bitmask indicating current state of this object within the game world 264 CollidableState collidableState; ///< bitmask indicating which types of objects this object can collide with 265 266 int team; ///< team that "owns" this object 267 int allyteam; ///< allyteam that this->team is part of 268 269 int tempNum; ///< used to check if object has already been processed (in QuadField queries, etc) 270 271 const SolidObjectDef* objectDef; ///< points to a UnitDef or to a FeatureDef instance 272 273 MoveDef* moveDef; ///< mobility information about this object (if NULL, object is either static or aircraft) 274 CollisionVolume* collisionVolume; 275 SolidObjectGroundDecal* groundDecal; 276 277 SyncedFloat3 frontdir; ///< object-local z-axis (in WS) 278 SyncedFloat3 rightdir; ///< object-local x-axis (in WS) 279 SyncedFloat3 updir; ///< object-local y-axis (in WS) 280 281 SyncedFloat3 relMidPos; ///< local-space vector from pos to midPos (read from model, used to initialize midPos) 282 SyncedFloat3 relAimPos; ///< local-space vector from pos to aimPos (read from model, used to initialize aimPos) 283 SyncedFloat3 midPos; ///< mid-position of model in WS, used as center of mass (and many other things) 284 SyncedFloat3 aimPos; ///< used as aiming position by weapons 285 286 int2 mapPos; ///< current position on GroundBlockingObjectMap 287 float3 groundBlockPos; 288 289 float3 dragScales; 290 291 float3 drawPos; ///< = pos + speed * timeOffset (unsynced) 292 float3 drawMidPos; ///< = drawPos + relMidPos (unsynced) 293 294 const YardMapStatus* blockMap; ///< Current (unrotated!) blockmap/yardmap of this object. 0 means no active yardmap => all blocked. 295 short int buildFacing; ///< Orientation of footprint, 4 different states 296 297 static const float DEFAULT_MASS; 298 static const float MINIMUM_MASS; 299 static const float MAXIMUM_MASS; 300 301 static int deletingRefID; SetDeletingRefID(int id)302 static void SetDeletingRefID(int id) { deletingRefID = id; } 303 // returns the object (command reference) id of the object currently being deleted, 304 // for units this equals unit->id, and for features feature->id + unitHandler->MaxUnits() GetDeletingRefID()305 static int GetDeletingRefID() { return deletingRefID; } 306 }; 307 308 #endif // SOLID_OBJECT_H 309