//----------------------------------------------------------------------------- // Purpose: Tell the vehicle physics system whenever we teleport, so it can fixup the wheels. //----------------------------------------------------------------------------- void CPropVehicle::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) { matrix3x4_t startMatrixInv; MatrixInvert( EntityToWorldTransform(), startMatrixInv ); BaseClass::Teleport( newPosition, newAngles, newVelocity ); // Calculate the relative transform of the teleport matrix3x4_t xform; ConcatTransforms( EntityToWorldTransform(), startMatrixInv, xform ); m_VehiclePhysics.Teleport( xform ); }
//----------------------------------------------------------------------------- // Returns the unperterbed view position for a particular role //----------------------------------------------------------------------------- bool CBaseTFVehicle::GetRoleViewPosition( int nRole, Vector *pVehicleEyeOrigin, QAngle *pVehicleEyeAngles ) { // Generate the view position in world space. Vector vAbsOrigin; QAngle vAbsAngle; bool bUsingThirdPersonCamera = GetRoleAbsViewPosition( nRole, &vAbsOrigin, &vAbsAngle ); // Make a matrix for it. matrix3x4_t absMatrix; AngleMatrix( vAbsAngle, absMatrix ); MatrixSetColumn( vAbsOrigin, 3, absMatrix ); // Transform the matrix into local space. matrix3x4_t worldToEntity, local; MatrixInvert( EntityToWorldTransform(), worldToEntity ); ConcatTransforms( worldToEntity, absMatrix, local ); // Suck out the origin and angles. pVehicleEyeOrigin->Init( local[0][3], local[1][3], local[2][3] ); MatrixAngles( local, *pVehicleEyeAngles ); return bUsingThirdPersonCamera; }
void CRagdollProp::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ) { matrix3x4_t startMatrixInv; matrix3x4_t startMatrix; m_ragdoll.list[0].pObject->GetPositionMatrix( startMatrix ); MatrixInvert( startMatrix, startMatrixInv ); // object 0 MUST be the one to get teleported! VPhysicsSwapObject( m_ragdoll.list[0].pObject ); BaseClass::Teleport( newPosition, newAngles, newVelocity ); // Calculate the relative transform of the teleport matrix3x4_t xform; ConcatTransforms( EntityToWorldTransform(), startMatrixInv, xform ); UpdateNetworkDataFromVPhysics( m_ragdoll.list[0].pObject, 0 ); for ( int i = 1; i < m_ragdoll.listCount; i++ ) { matrix3x4_t matrix, newMatrix; m_ragdoll.list[i].pObject->GetPositionMatrix( matrix ); ConcatTransforms( xform, matrix, newMatrix ); m_ragdoll.list[i].pObject->SetPositionMatrix( newMatrix, true ); UpdateNetworkDataFromVPhysics( m_ragdoll.list[i].pObject, i ); } }
void CAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld ) { CStudioHdr *pStudioHdr = GetModelPtr( ); if (!pStudioHdr) { Assert(!"CBaseAnimating::GetBoneTransform: model missing"); return; } if (iBone < 0 || iBone >= pStudioHdr->numbones()) { Assert(!"CBaseAnimating::GetBoneTransform: invalid bone index"); return; } CBoneCache *pcache = GetBoneCache( ); matrix3x4_t *pmatrix = pcache->GetCachedBone( iBone ); if ( !pmatrix ) { MatrixCopy( EntityToWorldTransform(), pBoneToWorld ); return; } Assert( pmatrix ); // FIXME MatrixCopy( *pmatrix, pBoneToWorld ); }
virtual void ComputeWorldSpaceSurroundingBox( Vector *mins, Vector *maxs ) { Assert( mins != NULL && maxs != NULL ); if ( !mins || !maxs ) return; // Take our saved collision bounds, and transform into world space TransformAABB( EntityToWorldTransform(), m_collisionMins, m_collisionMaxs, *mins, *maxs ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPhysMagnet::DoMagnetSuck( CBaseEntity *pOther ) { if ( !HasSpawnFlags( SF_MAGNET_SUCK ) ) return; if ( !m_bActive ) return; // Don't repeatedly suck if ( m_flNextSuckTime > gpGlobals->curtime ) return; // Look for physics objects underneath the magnet and suck them onto it Vector vecCheckPos, vecSuckPoint; VectorTransform( Vector(0,0,-96), EntityToWorldTransform(), vecCheckPos ); VectorTransform( Vector(0,0,-64), EntityToWorldTransform(), vecSuckPoint ); CBaseEntity *pEntities[20]; int iNumEntities = UTIL_EntitiesInSphere( pEntities, 20, vecCheckPos, 80.0, 0 ); for ( int i = 0; i < iNumEntities; i++ ) { CBaseEntity *pEntity = pEntities[i]; if ( !pEntity || pEntity == pOther ) continue; IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); if ( pPhys && pEntity->GetMoveType() == MOVETYPE_VPHYSICS && pPhys->GetMass() < 5000 ) { // Do we have line of sight to it? trace_t tr; UTIL_TraceLine( GetAbsOrigin(), pEntity->GetAbsOrigin(), MASK_SHOT, this, 0, &tr ); if ( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { // Pull it towards the magnet Vector vecVelocity = (vecSuckPoint - pEntity->GetAbsOrigin()); VectorNormalize(vecVelocity); vecVelocity *= 5 * pPhys->GetMass(); pPhys->AddVelocity( &vecVelocity, NULL ); } } } m_flNextSuckTime = gpGlobals->curtime + 2.0; }
void CStickyBomb::Touch( CBaseEntity *pOther ) { // Don't stick if already stuck if ( GetMoveType() == MOVETYPE_FLYGRAVITY ) { trace_t tr = GetTouchTrace(); // stickies don't stick to each other or sky if ( FClassnameIs(pOther, "grenade_stickybomb") || (tr.surface.flags & SURF_SKY) ) { // bounce Vector vecNewVelocity; PhysicsClipVelocity( GetAbsVelocity(), tr.plane.normal, vecNewVelocity, 1.0 ); SetAbsVelocity( vecNewVelocity ); } else { SetAbsVelocity( vec3_origin ); SetMoveType( MOVETYPE_NONE ); if ( pOther->entindex() != 0 ) { // set up notification if the parent is deleted before we explode g_pNotify->AddEntity( this, pOther ); if ( (tr.surface.flags & SURF_HITBOX) && modelinfo->GetModelType( pOther->GetModel() ) == mod_studio ) { CBaseAnimating *pOtherAnim = dynamic_cast<CBaseAnimating *>(pOther); if ( pOtherAnim ) { matrix3x4_t bombWorldSpace; MatrixCopy( EntityToWorldTransform(), bombWorldSpace ); // get the bone info so we can follow the bone FollowEntity( pOther ); SetOwnerEntity( pOther ); m_boneIndexAttached = pOtherAnim->GetHitboxBone( tr.hitbox ); matrix3x4_t boneToWorld; pOtherAnim->GetBoneTransform( m_boneIndexAttached, boneToWorld ); // transform my current position/orientation into the hit bone's space // UNDONE: Eventually we need to intersect with the mesh here // REVISIT: maybe do something like the decal code to find a spot on // the mesh. matrix3x4_t worldToBone, localMatrix; MatrixInvert( boneToWorld, worldToBone ); ConcatTransforms( worldToBone, bombWorldSpace, localMatrix ); MatrixAngles( localMatrix, m_boneAngles.GetForModify(), m_bonePosition.GetForModify() ); return; } } SetParent( pOther ); } } } }
void C_ServerRagdoll::GetRenderBounds( Vector& theMins, Vector& theMaxs ) { if( !CollisionProp()->IsBoundsDefinedInEntitySpace() ) { IRotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), theMins, theMaxs ); } else { theMins = CollisionProp()->OBBMins(); theMaxs = CollisionProp()->OBBMaxs(); } }
//----------------------------------------------------------------------------- // Purpose: // Output : void SyncPoseToAimAngles //----------------------------------------------------------------------------- void CNPC_RocketTurret::SyncPoseToAimAngles ( void ) { QAngle localAngles = TransformAnglesToLocalSpace( m_vecCurrentAngles.Get(), EntityToWorldTransform() ); // Update pitch SetPoseParameter( m_iPosePitch, localAngles.x ); // Update yaw -- NOTE: This yaw movement is screwy for this model, we must invert the yaw delta and also skew an extra 90 deg to // get the 'forward face' of the turret to match up with the look direction. If the model and it's pose parameters change, this will be wrong. SetPoseParameter( m_iPoseYaw, AngleNormalize( -localAngles.y - 90 ) ); InvalidateBoneCache(); }
void CBeam::SetAbsEndPos( const Vector &pos ) { if (!GetMoveParent()) { SetEndPos( pos ); return; } Vector vecLocalPos; matrix3x4_t worldToBeam; MatrixInvert( EntityToWorldTransform(), worldToBeam ); VectorTransform( pos, worldToBeam, vecLocalPos ); SetEndPos( vecLocalPos ); }
const Vector &C_Beam::GetAbsEndPos( void ) const { static Vector vecEndAbsPosition; if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE ) { if (ComputeBeamEntPosition( m_hAttachEntity[m_nNumBeamEnts-1], m_nAttachIndex[m_nNumBeamEnts-1], false, vecEndAbsPosition )) return vecEndAbsPosition; } if (!const_cast<C_Beam*>(this)->GetMoveParent()) return m_vecEndPos.Get(); // FIXME: Cache this off? VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecEndAbsPosition ); return vecEndAbsPosition; }
const Vector &CE_CBeam::GetAbsEndPos( void ) { CEntity *ent = GetEndEntity(); if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE && ent ) { return ent->GetAbsOrigin(); } if (!const_cast<CE_CBeam*>(this)->GetMoveParent()) return m_vecEndPos; // FIXME: Cache this off? static Vector vecAbsPos; VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecAbsPos ); return vecAbsPos; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAntlionGrub::Spawn( void ) { Precache(); BaseClass::Spawn(); SetModel( ANTLIONGRUB_MODEL ); // FIXME: This is a big perf hit with the number of grubs we're using! - jdw CreateGlow(); SetSolid( SOLID_BBOX ); SetSolidFlags( FSOLID_TRIGGER ); SetMoveType( MOVETYPE_NONE ); SetCollisionGroup( COLLISION_GROUP_NONE ); AddEffects( EF_NOSHADOW ); CollisionProp()->UseTriggerBounds(true,1); SetTouch( &CAntlionGrub::GrubTouch ); SetHealth( 1 ); m_takedamage = DAMAGE_YES; // Stick to the nearest surface if ( HasSpawnFlags( SF_ANTLIONGRUB_NO_AUTO_PLACEMENT ) == false ) { AttachToSurface(); } // At this point, alter our bounds to make sure we're within them Vector vecMins, vecMaxs; RotateAABB( EntityToWorldTransform(), CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), vecMins, vecMaxs ); UTIL_SetSize( this, vecMins, vecMaxs ); // Start our idle activity SetSequence( SelectWeightedSequence( ACT_IDLE ) ); SetCycle( random->RandomFloat( 0.0f, 1.0f ) ); ResetSequenceInfo(); m_State = GRUB_STATE_IDLE; // Reset m_flFlinchTime = 0.0f; m_flNextIdleSoundTime = gpGlobals->curtime + random->RandomFloat( 4.0f, 8.0f ); }
bool C_WalkerStrider::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld ) { // // // This is a TOTAL hack, but we don't have any nodes that work well at all for mounted guns. // // studiohdr_t *pStudioHdr = GetModelPtr( ); if ( !pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->numattachments ) { return false; } Vector vLocalPos( 0, 0, 0 ); mstudioattachment_t *pAttachment = pStudioHdr->pAttachment( iAttachment-1 ); if ( stricmp( pAttachment->pszName(), "build_point_left_gun" ) == 0 ) { vLocalPos.y = sideDist; } else if ( stricmp( pAttachment->pszName(), "build_point_right_gun" ) == 0 ) { vLocalPos.y = -sideDist; } else if ( stricmp( pAttachment->pszName(), "ThirdPersonCameraOrigin" ) == 0 ) { } else { // Ok, it's not one of our magical attachments. Use the regular attachment setup stuff. return BaseClass::GetAttachment( iAttachment, attachmentToWorld ); } if ( m_bCrouched ) { vLocalPos.z += downDist; } // Now build the output matrix. matrix3x4_t localMatrix; SetIdentityMatrix( localMatrix ); PositionMatrix( vLocalPos, localMatrix ); ConcatTransforms( EntityToWorldTransform(), localMatrix, attachmentToWorld ); return true; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void C_NPC_Barnacle::StandardBlendingRules( Vector pos[], Quaternion q[], float currentTime, int boneMask ) { BaseClass::StandardBlendingRules( pos, q, currentTime, boneMask ); // Don't do anything while dead if ( !IsAlive() ) return; studiohdr_t *hdr = GetModelPtr(); if ( !hdr ) return; int firstBone = Studio_BoneIndexByName( hdr, "Barnacle.tongue1" ); Vector vecPrev = pos[firstBone-1]; Vector vecCurr = vec3_origin; for ( int i = 0; i <= BARNACLE_TONGUE_POINTS; i++ ) { // We double up the bones at the last node. Vector vecCurr; if ( i == BARNACLE_TONGUE_POINTS ) { vecCurr = m_TonguePhysics.GetLastNode()->m_vPos; } else { vecCurr = m_TonguePhysics.GetNode(i)->m_vPos; } //debugoverlay->AddBoxOverlay( vecCurr, -Vector(2,2,2), Vector(2,2,2), vec3_angle, 0,255,0, 128, 0.1 ); // Fill out the positions in local space VectorITransform( vecCurr, EntityToWorldTransform(), pos[firstBone+i] ); vecCurr = pos[firstBone+i]; // Fill out the angles Vector vecForward = (vecCurr - vecPrev); VectorNormalize( vecForward ); QAngle vecAngle; VectorAngles( vecForward, vecAngle ); AngleQuaternion( vecAngle, q[firstBone+i] ); vecPrev = vecCurr; } }
const Vector &CBeam::GetAbsEndPos( void ) const { if ( GetType() != BEAM_POINTS && GetType() != BEAM_HOSE && GetEndEntity() ) { edict_t *pent = engine->PEntityOfEntIndex( GetEndEntity() ); CBaseEntity *ent = CBaseEntity::Instance( pent ); if ( ent ) return ent->GetAbsOrigin(); } if (!const_cast<CBeam*>(this)->GetMoveParent()) return m_vecEndPos.Get(); // FIXME: Cache this off? static Vector vecAbsPos; VectorTransform( m_vecEndPos, EntityToWorldTransform(), vecAbsPos ); return vecAbsPos; }
void CFunc_LiquidPortal::ComputeLinkMatrix( void ) { CFunc_LiquidPortal *pLinkedPortal = m_hLinkedPortal.Get(); if( pLinkedPortal ) { VMatrix matLocalToWorld, matLocalToWorldInv, matRemoteToWorld; matLocalToWorld = EntityToWorldTransform(); matRemoteToWorld = pLinkedPortal->EntityToWorldTransform(); MatrixInverseTR( matLocalToWorld, matLocalToWorldInv ); m_matrixThisToLinked = matRemoteToWorld * matLocalToWorldInv; MatrixInverseTR( m_matrixThisToLinked, pLinkedPortal->m_matrixThisToLinked ); } else { m_matrixThisToLinked.Identity(); } }
//----------------------------------------------------------------------------- // Purpose: Vehicles are permanently oriented off angle for vphysics. //----------------------------------------------------------------------------- void CPropCrane::GetVectors(Vector* pForward, Vector* pRight, Vector* pUp) const { // This call is necessary to cause m_rgflCoordinateFrame to be recomputed const matrix3x4_t &entityToWorld = EntityToWorldTransform(); if (pForward != NULL) { MatrixGetColumn( entityToWorld, 1, *pForward ); } if (pRight != NULL) { MatrixGetColumn( entityToWorld, 0, *pRight ); } if (pUp != NULL) { MatrixGetColumn( entityToWorld, 2, *pUp ); } }
void CKeeperBot::BotAdjustPos() { float modifier = KEEPER_MID_COEFF; QAngle ang = m_oldcmd.viewangles; Vector target = GetTeam()->m_vGoalCenter; if (m_vBallVel.Length2D() > 750 && m_flAngToBallVel < 60) { float yDist = GetTeam()->m_vGoalCenter.GetY() - m_vBallPos.y; float vAng = acos(Sign(yDist) * m_vBallDir2D.y); float xDist = Sign(m_vBallDir2D.x) * abs(yDist) * tan(vAng); target.x = clamp(m_vBallPos.x + xDist, GetTeam()->m_vGoalCenter.GetX() - 150, GetTeam()->m_vGoalCenter.GetX() + 150); } if (m_pBall->State_Get() == BALL_STATE_KEEPERHANDS && m_pBall->GetCurrentPlayer() == this) { if (ShotButtonsReleased()) { modifier = KEEPER_CLOSE_COEFF; //m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK); m_cmd.buttons |= IN_ALT1; CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true); if (!pPl && SDKGameRules()->IsIntermissionState()) pPl = FindClosestPlayerToSelf(false, true); if (pPl) { VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang); ang[PITCH] = g_IOSRand.RandomFloat(-40, 0); //m_flBotNextShot = gpGlobals->curtime + 1; } else { VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang); ang[YAW] += g_IOSRand.RandomFloat(-45, 45); ang[PITCH] = g_IOSRand.RandomFloat(-40, 0); //m_flBotNextShot = gpGlobals->curtime + 1; } } } else// if (gpGlobals->curtime >= m_flBotNextShot) { VectorAngles(m_vDirToBall, ang); float ballDistToGoal = (m_vBallPos - GetTeam()->m_vGoalCenter).Length2D(); CSDKPlayer *pClosest = FindClosestPlayerToBall(); m_cmd.buttons |= IN_ATTACK; if (ballDistToGoal < 750 && m_vDirToBall.Length2D() < 200 && m_vDirToBall.z < 200 && (m_vDirToBall.z < 80 || m_vBallVel.z <= 0)) { modifier = KEEPER_CLOSE_COEFF;// max(0.15f, 1 - ballDistToGoal / 750); VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang); bool diving = false; if (m_flAngToBallVel < 60 && m_flAngToBallVel > 15) { if (abs(m_vDirToBall.x) > 50 && abs(m_vDirToBall.x) < 200 && m_vDirToBall.z < 150 && abs(m_vDirToBall.x) < 150 && m_vBallVel.Length() > 200) { m_cmd.buttons |= IN_JUMP; m_cmd.buttons |= Sign(m_vDirToBall.x) == GetTeam()->m_nRight ? IN_MOVERIGHT : IN_MOVELEFT; //m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK); diving = true; } else if (m_vDirToBall.z > 100 && m_vDirToBall.z < 150 && m_vDirToBall.Length2D() < 100) { m_cmd.buttons |= IN_JUMP; //m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK); diving = true; } else if (abs(m_vDirToBall.y) > 50 && abs(m_vDirToBall.y) < 200 && m_vDirToBall.z < 100 && abs(m_vDirToBall.x) < 50 && m_vBallVel.Length() < 200 && pClosest != this) { m_cmd.buttons |= IN_JUMP; m_cmd.buttons |= Sign(m_vLocalDirToBall.x) == GetTeam()->m_nForward ? IN_FORWARD : IN_BACK; //m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK); diving = true; } } if (!diving) { if (m_vDirToBall.Length2D() < 50) { modifier = KEEPER_CLOSE_COEFF; //m_cmd.buttons |= (IN_ATTACK2 | IN_ATTACK); CSDKPlayer *pPl = FindClosestPlayerToSelf(true, true); if (!pPl && SDKGameRules()->IsIntermissionState()) pPl = FindClosestPlayerToSelf(false, true); if (pPl) { VectorAngles(pPl->GetLocalOrigin() - GetLocalOrigin(), ang); ang[PITCH] = g_IOSRand.RandomFloat(-40, 0); //m_flBotNextShot = gpGlobals->curtime + 1; } else { VectorAngles(Vector(0, GetTeam()->m_nForward, 0), ang); ang[YAW] += g_IOSRand.RandomFloat(-45, 45); ang[PITCH] = g_IOSRand.RandomFloat(-40, 0); //m_flBotNextShot = gpGlobals->curtime + 1; } } else modifier = KEEPER_CLOSE_COEFF; } } else if (ballDistToGoal < 1250 && m_flAngToBallVel < 60 && m_vBallVel.Length2D() > 300 && (m_vBallVel.z > 100 || m_vDirToBall.z > 100)) { modifier = KEEPER_FAR_COEFF; } else if (ballDistToGoal < 1000 && m_vDirToBall.z < 80 && m_vBallVel.Length2D() < 300 && m_vBallVel.z < 100) { if (pClosest == this) modifier = KEEPER_CLOSE_COEFF; else modifier = max(KEEPER_FAR_COEFF, 1 - pow(min(1, ballDistToGoal / 750.0f), 2)); } else { modifier = KEEPER_MID_COEFF; } m_cmd.viewangles = ang; m_LastAngles = m_cmd.viewangles; SetLocalAngles(m_cmd.viewangles); SnapEyeAngles(ang); Vector targetPosDir = target + modifier * (m_vBallPos - target) - GetLocalOrigin(); targetPosDir.z = 0; float dist = targetPosDir.Length2D(); VectorNormalizeFast(targetPosDir); Vector localDir; VectorIRotate(targetPosDir, EntityToWorldTransform(), localDir); //float speed; //if (dist < 10) // speed = 0; //else if (dist < 100) // speed = mp_runspeed.GetInt(); //else // speed = mp_sprintspeed.GetInt(); //float speed = clamp(dist - 10, 0, mp_runspeed.GetInt()); float speed = 0; if (dist > 30) speed = clamp(5 * dist, 0, mp_sprintspeed.GetInt() * (mp_botkeeperskill.GetInt() / 100.0f)); if (speed > mp_runspeed.GetInt()) m_cmd.buttons |= IN_SPEED; m_cmd.forwardmove = localDir.x * speed; m_cmd.sidemove = -localDir.y * speed; if (m_cmd.forwardmove > 0) m_cmd.buttons |= IN_FORWARD; else if (m_cmd.forwardmove < 0) m_cmd.buttons |= IN_BACK; if (m_cmd.sidemove > 0) m_cmd.buttons |= IN_RIGHT; else if (m_cmd.sidemove < 0) m_cmd.buttons |= IN_MOVELEFT; } m_cmd.viewangles = ang; }
bool CStatueProp::CreateVPhysicsFromHitBoxes( CBaseAnimating *pInitBaseAnimating ) { if ( !pInitBaseAnimating ) return false; // Use the current animation sequence and cycle CopyAnimationDataFrom( pInitBaseAnimating ); // Copy over any render color color24 colorRender = pInitBaseAnimating->GetRenderColor(); SetRenderColor( colorRender.r, colorRender.g, colorRender.b ); SetRenderAlpha( pInitBaseAnimating->GetRenderAlpha() ); // Get hitbox data CStudioHdr *pStudioHdr = GetModelPtr(); if ( !pStudioHdr ) return false; mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet ); if ( !set ) return false; Vector position; QAngle angles; // Make enough pointers to convexes for each hitbox CPhysConvex **ppConvex = new (CPhysConvex*[ set->numhitboxes ]); float flTotalVolume = 0.0f; float flTotalSurfaceArea = 0.0f; for ( int i = 0; i < set->numhitboxes; i++ ) { // Get the hitbox info mstudiobbox_t *pbox = set->pHitbox( i ); GetBonePosition( pbox->bone, position, angles ); // Accumulate volume and area Vector flDimentions = pbox->bbmax - pbox->bbmin; flTotalVolume += flDimentions.x * flDimentions.y * flDimentions.z; flTotalSurfaceArea += 2.0f * ( flDimentions.x * flDimentions.y + flDimentions.x * flDimentions.z + flDimentions.y * flDimentions.z ); // Get angled min and max extents Vector vecMins, vecMaxs; VectorRotate( pbox->bbmin, angles, vecMins ); VectorRotate( pbox->bbmax, angles, vecMaxs ); // Get the corners in world space Vector vecMinCorner = position + vecMins; Vector vecMaxCorner = position + vecMaxs; // Get the normals of the hitbox in world space Vector vecForward, vecRight, vecUp; AngleVectors( angles, &vecForward, &vecRight, &vecUp ); vecRight = -vecRight; // Convert corners and normals to local space Vector vecCornerLocal[ 2 ]; Vector vecNormalLocal[ 3 ]; matrix3x4_t matToWorld = EntityToWorldTransform(); VectorITransform( vecMaxCorner, matToWorld, vecCornerLocal[ 0 ] ); VectorITransform( vecMinCorner, matToWorld, vecCornerLocal[ 1 ] ); VectorIRotate( vecForward, matToWorld, vecNormalLocal[ 0 ] ); VectorIRotate( vecRight, matToWorld, vecNormalLocal[ 1 ] ); VectorIRotate( vecUp, matToWorld, vecNormalLocal[ 2 ] ); // Create 6 planes from the local oriented hit box data float pPlanes[ 4 * 6 ]; for ( int iPlane = 0; iPlane < 6; ++iPlane ) { int iPlaneMod2 = iPlane % 2; int iPlaneDiv2 = iPlane / 2; bool bOdd = ( iPlaneMod2 == 1 ); // Plane Normal pPlanes[ iPlane * 4 + 0 ] = vecNormalLocal[ iPlaneDiv2 ].x * ( bOdd ? -1.0f : 1.0f ); pPlanes[ iPlane * 4 + 1 ] = vecNormalLocal[ iPlaneDiv2 ].y * ( bOdd ? -1.0f : 1.0f ); pPlanes[ iPlane * 4 + 2 ] = vecNormalLocal[ iPlaneDiv2 ].z * ( bOdd ? -1.0f : 1.0f ); // Plane D pPlanes[ iPlane * 4 + 3 ] = ( vecCornerLocal[ iPlaneMod2 ].x * vecNormalLocal[ iPlaneDiv2 ].x + vecCornerLocal[ iPlaneMod2 ].y * vecNormalLocal[ iPlaneDiv2 ].y + vecCornerLocal[ iPlaneMod2 ].z * vecNormalLocal[ iPlaneDiv2 ].z ) * ( bOdd ? -1.0f : 1.0f ); } // Create convex from the intersection of these planes ppConvex[ i ] = physcollision->ConvexFromPlanes( pPlanes, 6, 0.0f ); } // Make a single collide out of the group of convex boxes CPhysCollide *pPhysCollide = physcollision->ConvertConvexToCollide( ppConvex, set->numhitboxes ); delete[] ppConvex; // Create the physics object objectparams_t params = g_PhysDefaultObjectParams; params.pGameData = static_cast<void *>( this ); int nMaterialIndex = physprops->GetSurfaceIndex( "ice" ); // use ice material IPhysicsObject* p = physenv->CreatePolyObject( pPhysCollide, nMaterialIndex, GetAbsOrigin(), GetAbsAngles(), ¶ms ); Assert( p != NULL ); // Set velocity Vector vecInitialVelocity = pInitBaseAnimating->GetAbsVelocity(); p->SetVelocity( &vecInitialVelocity, NULL ); // Compute mass float flMass; float flDensity, flThickness; physprops->GetPhysicsProperties( nMaterialIndex, &flDensity, &flThickness, NULL, NULL ); // Make it more hollow flThickness = MIN ( 1.0f, flThickness + 0.5f ); if ( flThickness > 0.0f ) { flMass = flTotalSurfaceArea * flThickness * CUBIC_METERS_PER_CUBIC_INCH * flDensity; } else { // density is in kg/m^3, volume is in in^3 flMass = flTotalVolume * CUBIC_METERS_PER_CUBIC_INCH * flDensity; } // Mass is somewhere between the original and if it was all ice p->SetMass( flMass ); // Yes, gravity p->EnableGravity( true ); // Use this as our vphysics VPhysicsSetObject( p ); SetSolid( SOLID_VPHYSICS ); AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); SetMoveType( MOVETYPE_VPHYSICS ); if ( pInitBaseAnimating != this ) { // Transfer children from the init base animating TransferChildren( pInitBaseAnimating, this ); CBaseEntity *pChild = FirstMoveChild(); while ( pChild ) { CEntityFreezing *pFreezing = dynamic_cast<CEntityFreezing*>( pChild ); if ( pFreezing ) { pFreezing->FinishFreezing(); } pChild = pChild->NextMovePeer(); } } return true; }
bool CStatueProp::CreateVPhysicsFromOBBs( CBaseAnimating *pInitBaseAnimating ) { // Make enough pointers to convexes for each hitbox CPhysConvex **ppConvex = new (CPhysConvex*[ m_pInitOBBs->Count() ]); float flTotalVolume = 0.0f; float flTotalSurfaceArea = 0.0f; for ( int i = 0; i < m_pInitOBBs->Count(); i++ ) { const outer_collision_obb_t *pOBB = &((*m_pInitOBBs)[ i ]); // Accumulate volume and area Vector flDimentions = pOBB->vecMaxs - pOBB->vecMins; flTotalVolume += flDimentions.x * flDimentions.y * flDimentions.z; flTotalSurfaceArea += 2.0f * ( flDimentions.x * flDimentions.y + flDimentions.x * flDimentions.z + flDimentions.y * flDimentions.z ); // Get angled min and max extents Vector vecMins, vecMaxs; VectorRotate( pOBB->vecMins, pOBB->angAngles, vecMins ); VectorRotate( pOBB->vecMaxs, pOBB->angAngles, vecMaxs ); // Get the corners in world space Vector vecMinCorner = pOBB->vecPos + vecMins; Vector vecMaxCorner = pOBB->vecPos + vecMaxs; // Get the normals of the hitbox in world space Vector vecForward, vecRight, vecUp; AngleVectors( pOBB->angAngles, &vecForward, &vecRight, &vecUp ); vecRight = -vecRight; // Convert corners and normals to local space Vector vecCornerLocal[ 2 ]; Vector vecNormalLocal[ 3 ]; matrix3x4_t matToWorld = EntityToWorldTransform(); VectorITransform( vecMaxCorner, matToWorld, vecCornerLocal[ 0 ] ); VectorITransform( vecMinCorner, matToWorld, vecCornerLocal[ 1 ] ); VectorIRotate( vecForward, matToWorld, vecNormalLocal[ 0 ] ); VectorIRotate( vecRight, matToWorld, vecNormalLocal[ 1 ] ); VectorIRotate( vecUp, matToWorld, vecNormalLocal[ 2 ] ); // Create 6 planes from the local oriented hit box data float pPlanes[ 4 * 6 ]; for ( int iPlane = 0; iPlane < 6; ++iPlane ) { int iPlaneMod2 = iPlane % 2; int iPlaneDiv2 = iPlane / 2; bool bOdd = ( iPlaneMod2 == 1 ); // Plane Normal pPlanes[ iPlane * 4 + 0 ] = vecNormalLocal[ iPlaneDiv2 ].x * ( bOdd ? -1.0f : 1.0f ); pPlanes[ iPlane * 4 + 1 ] = vecNormalLocal[ iPlaneDiv2 ].y * ( bOdd ? -1.0f : 1.0f ); pPlanes[ iPlane * 4 + 2 ] = vecNormalLocal[ iPlaneDiv2 ].z * ( bOdd ? -1.0f : 1.0f ); // Plane D pPlanes[ iPlane * 4 + 3 ] = ( vecCornerLocal[ iPlaneMod2 ].x * vecNormalLocal[ iPlaneDiv2 ].x + vecCornerLocal[ iPlaneMod2 ].y * vecNormalLocal[ iPlaneDiv2 ].y + vecCornerLocal[ iPlaneMod2 ].z * vecNormalLocal[ iPlaneDiv2 ].z ) * ( bOdd ? -1.0f : 1.0f ); } // Create convex from the intersection of these planes ppConvex[ i ] = physcollision->ConvexFromPlanes( pPlanes, 6, 0.0f ); } // Make a single collide out of the group of convex boxes CPhysCollide *pPhysCollide = physcollision->ConvertConvexToCollide( ppConvex, m_pInitOBBs->Count() ); delete[] ppConvex; // Create the physics object objectparams_t params = g_PhysDefaultObjectParams; params.pGameData = static_cast<void *>( this ); int nMaterialIndex = physprops->GetSurfaceIndex( "ice" ); // use ice material IPhysicsObject* p = physenv->CreatePolyObject( pPhysCollide, nMaterialIndex, GetAbsOrigin(), GetAbsAngles(), ¶ms ); Assert( p != NULL ); // Set velocity Vector vecInitialVelocity = pInitBaseAnimating->GetAbsVelocity(); p->SetVelocity( &vecInitialVelocity, NULL ); // Compute mass float flMass; float flDensity, flThickness; physprops->GetPhysicsProperties( nMaterialIndex, &flDensity, &flThickness, NULL, NULL ); // Make it more hollow flThickness = MIN ( 1.0f, flThickness + 0.5f ); if ( flThickness > 0.0f ) { flMass = flTotalSurfaceArea * flThickness * CUBIC_METERS_PER_CUBIC_INCH * flDensity; } else { // density is in kg/m^3, volume is in in^3 flMass = flTotalVolume * CUBIC_METERS_PER_CUBIC_INCH * flDensity; } // Mass is somewhere between the original and if it was all ice p->SetMass( flMass ); // Yes, gravity p->EnableGravity( true ); // Use this as our vphysics VPhysicsSetObject( p ); SetSolid( SOLID_VPHYSICS ); AddSolidFlags( FSOLID_CUSTOMRAYTEST | FSOLID_CUSTOMBOXTEST ); SetMoveType( MOVETYPE_VPHYSICS ); m_pInitOBBs = NULL; return true; }
//----------------------------------------------------------------------------- // Purpose: Recompute my rendering box //----------------------------------------------------------------------------- void C_QUA_Strider::ClientThink() { int i; Vector vecMins, vecMaxs; Vector vecAbsMins, vecAbsMaxs; matrix3x4_t worldToStrider, hitboxToStrider; Vector vecBoxMins, vecBoxMaxs; Vector vecBoxAbsMins, vecBoxAbsMaxs; mstudiohitboxset_t *set; CBoneCache *pCache = NULL; // The reason why this is here, as opposed to in SetObjectCollisionBox, // is because of IK. The code below recomputes bones so as to get at the hitboxes, // which causes IK to trigger, which causes raycasts against the other entities to occur, // which is illegal to do while in the Relink phase. studiohdr_t *pStudioHdr = GetModel()?modelinfo->GetStudiomodel( GetModel() ):NULL; if (!pStudioHdr) goto doneWithComputation; set = pStudioHdr->pHitboxSet( m_nHitboxSet ); if ( !set || !set->numhitboxes ) goto doneWithComputation; CStudioHdr *hdr = GetModelPtr(); pCache = GetBoneCache( hdr ); matrix3x4_t *hitboxbones[MAXSTUDIOBONES]; pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones ); // // Compute a box in world space that surrounds this entity m_vecRenderMins.Init( FLT_MAX, FLT_MAX, FLT_MAX ); m_vecRenderMaxs.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX ); // MatrixInvert( EntityToWorldTransform(), worldToStrider ); // for ( i = 0; i < set->numhitboxes; i++ ) { mstudiobbox_t *pbox = set->pHitbox(i); ConcatTransforms( worldToStrider, *hitboxbones[pbox->bone], hitboxToStrider ); TransformAABB( hitboxToStrider, pbox->bbmin, pbox->bbmax, vecBoxMins, vecBoxMaxs ); VectorMin( m_vecRenderMins, vecBoxMins, m_vecRenderMins ); VectorMax( m_vecRenderMaxs, vecBoxMaxs, m_vecRenderMaxs ); } // // Deberiamos poner aqui lo de la vista?? // // // UNDONE: Disabled this until we can get closer to a final map and tune //#if 0 // // Cut ropes. // if ( gpGlobals->curtime >= m_flNextRopeCutTime ) // { // // Blow the bbox out a little. // Vector vExtendedMins = vecMins - Vector( 50, 50, 50 ); // Vector vExtendedMaxs = vecMaxs + Vector( 50, 50, 50 ); // // C_RopeKeyframe *ropes[512]; // int nRopes = C_RopeKeyframe::GetRopesIntersectingAABB( ropes, ARRAYSIZE( ropes ), GetAbsOrigin() + vExtendedMins, GetAbsOrigin() + vExtendedMaxs ); // for ( int i=0; i < nRopes; i++ ) // { // C_RopeKeyframe *pRope = ropes[i]; // // if ( pRope->GetEndEntity() ) // { // Vector vPos; // if ( pRope->GetEndPointPos( 1, vPos ) ) // { // // Detach the endpoint. // pRope->SetEndEntity( NULL ); // // // Make some spark effect here.. // g_pEffects->Sparks( vPos ); // } // } // } // // m_flNextRopeCutTime = gpGlobals->curtime + 0.5; // } //#endif doneWithComputation: // True argument because the origin may have stayed the same, but the size is expected to always change g_pClientShadowMgr->AddToDirtyShadowList( this, true ); }