void StudioModel::Chrome (int *pchrome, int bone, vec3_t normal) { float n; if (g_chromeage[bone] != g_smodels_total) { // calculate vectors from the viewer to the bone. This roughly adjusts for position vec3_t chromeupvec; // g_chrome t vector in world reference frame vec3_t chromerightvec; // g_chrome s vector in world reference frame vec3_t tmp; // vector pointing at bone in world reference frame VectorScale( m_origin, -1, tmp ); tmp[0] += g_bonetransform[bone][0][3]; tmp[1] += g_bonetransform[bone][1][3]; tmp[2] += g_bonetransform[bone][2][3]; VectorNormalize( tmp ); CrossProduct( tmp, g_vright, chromeupvec ); VectorNormalize( chromeupvec ); CrossProduct( tmp, chromeupvec, chromerightvec ); VectorNormalize( chromerightvec ); VectorIRotate( chromeupvec, g_bonetransform[bone], g_chromeup[bone] ); VectorIRotate( chromerightvec, g_bonetransform[bone], g_chromeright[bone] ); g_chromeage[bone] = g_smodels_total; } // calc s coord n = DotProduct( normal, g_chromeright[bone] ); pchrome[0] = (n + 1.0) * 32; // FIX: make this a float // calc t coord n = DotProduct( normal, g_chromeup[bone] ); pchrome[1] = (n + 1.0) * 32; // FIX: make this a float }
void VectorITransform(const vec3_t in1, const float in2[3][4], vec3_t out) { vec3_t tmp; tmp[0] = in1[0] - in2[0][3]; tmp[1] = in1[1] - in2[1][3]; tmp[2] = in1[2] - in2[2][3]; VectorIRotate(tmp, in2, out); }
void VectorITransform(Vector *vIn, Matrix *mat, Vector *vOut) { Vector temp; temp.x = vIn->x - mat->origin.x; temp.y = vIn->y - mat->origin.y; temp.z = vIn->z - mat->origin.z; VectorIRotate(&temp,mat,vOut); }
void CPhysicsObject::WorldToLocalVector(Vector *localVector, const Vector &worldVector) const { if (!localVector) return; matrix3x4_t matrix; GetPositionMatrix(&matrix); VectorIRotate(worldVector, matrix, *localVector); }
//----------------------------------------------------------------------------- // Purpose: Try and find an entity to lock onto //----------------------------------------------------------------------------- CBaseEntity *CWeaponCombat_ChargeablePlasma::GetLockTarget( void ) { CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner(); if ( !pPlayer ) return NULL; Vector vecSrc = pPlayer->Weapon_ShootPosition( ); Vector vecAiming; pPlayer->EyeVectors( &vecAiming ); Vector vecEnd = vecSrc + vecAiming * MAX_TRACE_LENGTH; trace_t tr; TFGameRules()->WeaponTraceLine( vecSrc, vecEnd, MASK_SHOT, pPlayer, GetDamageType(), &tr ); if ( (tr.fraction < 1.0f) && tr.m_pEnt ) { CBaseEntity *pTargetEntity = tr.m_pEnt; // Don't guide on same team or on anything other than players, objects, and NPCs if ( pTargetEntity->InSameTeam(pPlayer) || (!pTargetEntity->IsPlayer() && (pTargetEntity->MyNPCPointer() == NULL)) ) return NULL; // Compute the target offset relative to the target Vector vecWorldOffset; VectorSubtract( tr.endpos, pTargetEntity->GetAbsOrigin(), vecWorldOffset ); VectorIRotate( vecWorldOffset, pTargetEntity->EntityToWorldTransform(), m_vecTargetOffset ); m_flLockedAt = gpGlobals->curtime + 0.2; return pTargetEntity; } return NULL; }
void CPhysicsObject::WorldToLocalVector( Vector &localVector, const Vector &worldVector ) { matrix3x4_t matrix; GetPositionMatrix( matrix ); // copy in case the src == dest VectorIRotate( Vector(worldVector), matrix, localVector ); }
int CBaseTurret::MoveTurret(void) { bool bDidMove = false; int iPose; matrix3x4_t localToWorld; GetAttachment( LookupAttachment( "eyes" ), localToWorld ); Vector vecGoalDir; AngleVectors( m_vecGoalAngles, &vecGoalDir ); Vector vecGoalLocalDir; VectorIRotate( vecGoalDir, localToWorld, vecGoalLocalDir ); QAngle vecGoalLocalAngles; VectorAngles( vecGoalLocalDir, vecGoalLocalAngles ); float flDiff; QAngle vecNewAngles; // update pitch flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1 * m_iBaseTurnRate ) ); iPose = LookupPoseParameter( TURRET_BC_PITCH ); SetPoseParameter( iPose, GetPoseParameter( iPose ) + flDiff / 1.5 ); if (fabs(flDiff) > 0.1) { bDidMove = true; } // update yaw, with acceleration #if 0 float flDist = AngleNormalize( vecGoalLocalAngles.y ); float flNewDist; float flNewTurnRate; ChangeDistance( 0.1, flDist, 0.0, m_fTurnRate, m_iBaseTurnRate, m_iBaseTurnRate * 4, flNewDist, flNewTurnRate ); m_fTurnRate = flNewTurnRate; flDiff = flDist - flNewDist; #else flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1 * m_iBaseTurnRate ) ); #endif iPose = LookupPoseParameter( TURRET_BC_YAW ); SetPoseParameter( iPose, GetPoseParameter( iPose ) + flDiff / 1.5 ); if (fabs(flDiff) > 0.1) { bDidMove = true; } if (bDidMove) { // DevMsg( "(%.2f, %.2f)\n", AngleNormalize( vecGoalLocalAngles.x ), AngleNormalize( vecGoalLocalAngles.y ) ); } return bDidMove; }
//----------------------------------------------------------------------------- // Purpose: Causes the turret to face its desired angles //----------------------------------------------------------------------------- bool CNPC_CeilingTurret::UpdateFacing( void ) { bool bMoved = false; matrix3x4_t localToWorld; GetAttachment( LookupAttachment( "eyes" ), localToWorld ); Vector vecGoalDir; AngleVectors( m_vecGoalAngles, &vecGoalDir ); Vector vecGoalLocalDir; VectorIRotate( vecGoalDir, localToWorld, vecGoalLocalDir ); if ( g_debug_turret_ceiling.GetBool() ) { Vector vecMuzzle, vecMuzzleDir; QAngle vecMuzzleAng; GetAttachment( "eyes", vecMuzzle, vecMuzzleAng ); AngleVectors( vecMuzzleAng, &vecMuzzleDir ); NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle+(vecMuzzleDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 255, 0, false, 0.05 ); NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecMuzzleDir*256), 255, 255, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle, -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Cross3D( vecMuzzle+(vecGoalDir*256), -Vector(2,2,2), Vector(2,2,2), 255, 0, 0, false, 0.05 ); NDebugOverlay::Line( vecMuzzle, vecMuzzle+(vecGoalDir*256), 255, 0, 0, false, 0.05 ); } QAngle vecGoalLocalAngles; VectorAngles( vecGoalLocalDir, vecGoalLocalAngles ); // Update pitch float flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1f * MaxYawSpeed() ) ); SetPoseParameter( m_poseAim_Pitch, GetPoseParameter( m_poseAim_Pitch ) + ( flDiff / 1.5f ) ); if ( fabs( flDiff ) > 0.1f ) { bMoved = true; } // Update yaw flDiff = AngleNormalize( UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed() ) ); SetPoseParameter( m_poseAim_Yaw, GetPoseParameter( m_poseAim_Yaw ) + ( flDiff / 1.5f ) ); if ( fabs( flDiff ) > 0.1f ) { bMoved = true; } InvalidateBoneCache(); return bMoved; }
void TransformNormal (MS3D *ms3d, const ms3d_vertex_t *vertex, const vec3_t normal, vec3_t out) { int i; int jointIndices[4], jointWeights[4]; FillJointIndicesAndWeights(vertex, jointIndices, jointWeights); //if (jointIndices[0] < 0 || jointIndices[0] >= (int) m_joints.size() || m_currentTime < 0.0f) if (jointIndices[0] < 0 || jointIndices[0] >= ms3d->nNumJoints || ms3d->fCurrentTime < 0.0f) { out[0] = normal[0]; out[1] = normal[1]; out[2] = normal[2]; } else { // count valid weights int numWeights = 0; for (i = 0; i < 4; i++) { if (jointWeights[i] > 0 && jointIndices[i] >= 0 && jointIndices[i] < ms3d->nNumJoints) ++numWeights; else break; } // init out[0] = 0.0f; out[1] = 0.0f; out[2] = 0.0f; float weights[4] = { (float) jointWeights[0] / 100.0f, (float) jointWeights[1] / 100.0f, (float) jointWeights[2] / 100.0f, (float) jointWeights[3] / 100.0f }; if (numWeights == 0) { numWeights = 1; weights[0] = 1.0f; } // add weighted vertices for (i = 0; i < numWeights; i++) { //const ms3d_joint_t *joint = &m_joints[jointIndices[i]]; const ms3d_joint_t *joint = &ms3d->joints[jointIndices[i]]; vec3_t tmp, norm; VectorIRotate(normal, joint->matGlobalSkeleton, tmp); VectorRotate(tmp, joint->matGlobal, norm); out[0] += norm[0] * weights[i]; out[1] += norm[1] * weights[i]; out[2] += norm[2] * weights[i]; } } }
void RagdollApplyAnimationAsVelocity( ragdoll_t &ragdoll, matrix3x4_t *pPrevBones, matrix3x4_t *pCurrentBones, float dt ) { for ( int i = 0; i < ragdoll.listCount; i++ ) { Vector velocity; AngularImpulse angVel; int boneIndex = ragdoll.boneIndex[i]; CalcBoneDerivatives( velocity, angVel, pPrevBones[boneIndex], pCurrentBones[boneIndex], dt ); Vector localVelocity; AngularImpulse localAngVelocity; // move these derivatives into the local bone space of the "current" bone VectorIRotate( velocity, pCurrentBones[boneIndex], localVelocity ); VectorIRotate( angVel, pCurrentBones[boneIndex], localAngVelocity ); // move those bone-local coords back to world space using the ragdoll transform ragdoll.list[i].pObject->LocalToWorldVector( velocity, localVelocity ); ragdoll.list[i].pObject->LocalToWorldVector( angVel, localAngVelocity ); ragdoll.list[i].pObject->AddVelocity( &velocity, &angVel ); } }
//----------------------------------------------------------------------------- // Purpose: Causes the camera to face its desired angles //----------------------------------------------------------------------------- bool CNPC_CombineCamera::UpdateFacing() { bool bMoved = false; matrix3x4_t localToWorld; GetAttachment(LookupAttachment("eyes"), localToWorld); Vector vecGoalDir; AngleVectors(m_vecGoalAngles, &vecGoalDir ); Vector vecGoalLocalDir; VectorIRotate(vecGoalDir, localToWorld, vecGoalLocalDir); QAngle vecGoalLocalAngles; VectorAngles(vecGoalLocalDir, vecGoalLocalAngles); // Update pitch float flDiff = AngleNormalize(UTIL_ApproachAngle( vecGoalLocalAngles.x, 0.0, 0.1f * MaxYawSpeed())); int iPose = LookupPoseParameter(COMBINE_CAMERA_BC_PITCH); SetPoseParameter(iPose, GetPoseParameter(iPose) + (flDiff / 1.5f)); if (fabs(flDiff) > 0.1f) { bMoved = true; } // Update yaw flDiff = AngleNormalize(UTIL_ApproachAngle( vecGoalLocalAngles.y, 0.0, 0.1f * MaxYawSpeed())); iPose = LookupPoseParameter(COMBINE_CAMERA_BC_YAW); SetPoseParameter(iPose, GetPoseParameter(iPose) + (flDiff / 1.5f)); if (fabs(flDiff) > 0.1f) { bMoved = true; } if (bMoved && (m_flMoveSoundTime < gpGlobals->curtime)) { EmitSound("NPC_CombineCamera.Move"); m_flMoveSoundTime = gpGlobals->curtime + CAMERA_MOVE_INTERVAL; } // You're going to make decisions based on this info. So bump the bone cache after you calculate everything InvalidateBoneCache(); return bMoved; }
void CPhysTorque::SetupForces( IPhysicsObject *pPhys, Vector &linear, AngularImpulse &angular ) { // clear out force linear.Init(); matrix3x4_t matrix; pPhys->GetPositionMatrix( matrix ); // transform motor axis to local space Vector axis_ls; VectorIRotate( m_axis, matrix, axis_ls ); // Set torque to be around selected axis angular = axis_ls * m_force; }
SOPAngle *SOPAngle::RotateAroundAxis(SOPVector *vec, lua_Number degrees) { matrix3x4_t m_rgflCoordinateFrame; Vector rotationAxisLs; Quaternion q; matrix3x4_t xform; matrix3x4_t localToWorldMatrix; Vector axisvector = vec->ToVector(); QAngle rotatedAngles; QAngle angOurAngs = ToQAngle(); AngleMatrix( angOurAngs, m_rgflCoordinateFrame ); VectorIRotate( axisvector, m_rgflCoordinateFrame, rotationAxisLs ); AxisAngleQuaternion( rotationAxisLs, degrees, q ); QuaternionMatrix( q, vec3_origin, xform ); ConcatTransforms( m_rgflCoordinateFrame, xform, localToWorldMatrix ); MatrixAngles( localToWorldMatrix, rotatedAngles ); return new SOPAngle(rotatedAngles.x, rotatedAngles.y, rotatedAngles.z); }
/* ================ StudioModel::SetupLighting set some global variables based on entity position inputs: outputs: g_ambientlight g_shadelight ================ */ void StudioModel::SetupLighting ( ) { int i; g_ambientlight = 32; g_shadelight = 192; g_lightvec[0] = 0; g_lightvec[1] = 0; g_lightvec[2] = -1.0; g_lightcolor[0] = 1.0; g_lightcolor[1] = 1.0; g_lightcolor[2] = 1.0; // TODO: only do it for bones that actually have textures for (i = 0; i < m_pstudiohdr->numbones; i++) { VectorIRotate( g_lightvec, g_bonetransform[i], g_blightvec[i] ); } }
IMotionEvent::simresult_e CKeepUpright::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) { if ( !m_bActive ) return SIM_NOTHING; Vector currentAxis; matrix3x4_t matrix; // get the object's local to world transform pObject->GetPositionMatrix( matrix ); // Get the object's local test axis in world space VectorRotate( m_localTestAxis, matrix, currentAxis ); Vector rotationAxis = CrossProduct( currentAxis, m_worldGoalAxis ); // atan2() is well defined, so do a Dot & Cross instead of asin(Cross) float cosine = DotProduct( currentAxis, m_worldGoalAxis ); float sine = VectorNormalize( rotationAxis ); float angle = atan2( sine, cosine ); angle = RAD2DEG(angle); rotationAxis *= angle; VectorIRotate( rotationAxis, matrix, angular ); float invDeltaTime = (1/deltaTime); angular *= invDeltaTime * invDeltaTime; AngularImpulse angVel; pObject->GetVelocity( NULL, &angVel ); angular -= angVel; float len = VectorNormalize( angular ); if ( len > m_angularLimit * invDeltaTime ) len = m_angularLimit * invDeltaTime; angular *= len; linear.Init(); return SIM_LOCAL_ACCELERATION; }
void GetBumpNormals( const Vector& sVect, const Vector& tVect, const Vector& flatNormal, const Vector& phongNormal, Vector bumpNormals[NUM_BUMP_VECTS] ) { Vector tmpNormal; bool leftHanded; int i; assert( NUM_BUMP_VECTS == 3 ); // Are we left or right handed? CrossProduct( sVect, tVect, tmpNormal ); if( DotProduct( flatNormal, tmpNormal ) < 0.0f ) { leftHanded = true; } else { leftHanded = false; } // Build a basis for the face around the phong normal matrix3x4_t smoothBasis; CrossProduct( phongNormal.Base(), sVect.Base(), smoothBasis[1] ); VectorNormalize( smoothBasis[1] ); CrossProduct( smoothBasis[1], phongNormal.Base(), smoothBasis[0] ); VectorNormalize( smoothBasis[0] ); VectorCopy( phongNormal.Base(), smoothBasis[2] ); if( leftHanded ) { VectorNegate( smoothBasis[1] ); } // move the g_localBumpBasis into world space to create bumpNormals for( i = 0; i < 3; i++ ) { VectorIRotate( g_localBumpBasis[i], smoothBasis, bumpNormals[i] ); } }
void CPhysMotor::Activate( void ) { BaseClass::Activate(); // This gets called after all objects spawn and after all objects restore if ( m_attachedObject == NULL ) { CBaseEntity *pAttach = gEntList.FindEntityByName( NULL, m_nameAttach, NULL ); if ( pAttach && pAttach->GetMoveType() == MOVETYPE_VPHYSICS ) { m_attachedObject = pAttach; IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); CalculateAcceleration(); matrix3x4_t matrix; pPhys->GetPositionMatrix( matrix ); Vector motorAxis_ls; VectorIRotate( m_motor.m_axis, matrix, motorAxis_ls ); float inertia = DotProductAbs( pPhys->GetInertia(), motorAxis_ls ); m_motor.m_maxTorque = inertia * m_motor.m_inertiaFactor * (m_angularAcceleration + m_additionalAcceleration); m_motor.m_restistanceDamping = 1.0f; } } if ( m_attachedObject ) { IPhysicsObject *pPhys = m_attachedObject->VPhysicsGetObject(); // create a hinge constraint for this object? if ( m_spawnflags & SF_MOTOR_HINGE ) { // UNDONE: Don't do this on restore? if ( !m_pHinge ) { constraint_hingeparams_t hingeParams; hingeParams.Defaults(); hingeParams.worldAxisDirection = m_motor.m_axis; hingeParams.worldPosition = GetLocalOrigin(); m_pHinge = physenv->CreateHingeConstraint( g_PhysWorldObject, pPhys, NULL, hingeParams ); m_pHinge->SetGameData( (void *)this ); } if ( m_spawnflags & SF_MOTOR_NOCOLLIDE ) { physenv->DisableCollisions( pPhys, g_PhysWorldObject ); } } else { m_pHinge = NULL; } // NOTE: On restore, this path isn't run because m_pController will not be NULL if ( !m_pController ) { m_pController = physenv->CreateMotionController( &m_motor ); m_pController->AttachObject( m_attachedObject->VPhysicsGetObject() ); if ( m_spawnflags & SF_MOTOR_START_ON ) { TurnOn(); } } } // Need to do this on restore since there's no good way to save this if ( m_pController ) { m_pController->SetEventHandler( &m_motor ); } }
IMotionEvent::simresult_e CMotorController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) { linear = vec3_origin; angular = vec3_origin; if ( m_speed == 0 ) return SIM_NOTHING; matrix3x4_t matrix; pObject->GetPositionMatrix( matrix ); AngularImpulse currentRotAxis; // currentRotAxis is in local space pObject->GetVelocity( NULL, ¤tRotAxis ); // transform motor axis to local space Vector motorAxis_ls; VectorIRotate( m_axis, matrix, motorAxis_ls ); float currentSpeed = DotProduct( currentRotAxis, motorAxis_ls ); float inertia = DotProductAbs( pObject->GetInertia(), motorAxis_ls ); // compute absolute acceleration, don't integrate over the timestep float accel = m_speed - currentSpeed; float rotForce = accel * inertia * m_inertiaFactor; // BUGBUG: This heuristic is a little flaky // UNDONE: Make a better heuristic for speed control if ( fabsf(m_lastAcceleration) > 0 ) { float deltaSpeed = currentSpeed - m_lastSpeed; // make sure they are going the same way if ( deltaSpeed * accel > 0 ) { float factor = deltaSpeed / m_lastAcceleration; factor = 1 - clamp( factor, 0, 1 ); rotForce += m_lastForce * factor * m_restistanceDamping; } else { if ( currentSpeed != 0 ) { // have we reached a steady state that isn't our target? float increase = deltaSpeed / m_lastAcceleration; if ( fabsf(increase) < 0.05 ) { rotForce += m_lastForce * m_restistanceDamping; } } } } // ------------------------------------------------------- if ( m_maxTorque != 0 ) { if ( rotForce > m_maxTorque ) { rotForce = m_maxTorque; } else if ( rotForce < -m_maxTorque ) { rotForce = -m_maxTorque; } } m_lastForce = rotForce; m_lastAcceleration = (rotForce / inertia); m_lastSpeed = currentSpeed; // this is in local space angular = motorAxis_ls * rotForce; return SIM_LOCAL_FORCE; }
IMotionEvent::simresult_e CNailGrenadeController::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular ) { // Try to get to m_vecDesiredPosition // Try to orient ourselves to m_angDesiredOrientation Vector currentPos; QAngle currentAng; pObject->GetPosition( ¤tPos, ¤tAng ); Vector vecVel; AngularImpulse angVel; pObject->GetVelocity( &vecVel, &angVel ); linear.Init(); angular.Init(); if ( m_bReachedPos ) { // Lock at this height if ( vecVel.Length() > 1.0 ) { AngularImpulse nil( 0,0,0 ); pObject->SetVelocityInstantaneous( &vec3_origin, &nil ); // For now teleport to the proper orientation currentAng.x = 0; currentAng.y = 0; currentAng.z = 0; pObject->SetPosition( currentPos, currentAng, true ); } } else { // not at the right height yet, keep moving up linear.z = 50 * ( m_vecDesiredPosition.z - currentPos.z ); if ( currentPos.z > m_vecDesiredPosition.z ) { // lock into position m_bReachedPos = true; } // Start rotating in the right direction // we'll lock angles once we reach proper height to stop the oscillating matrix3x4_t matrix; // get the object's local to world transform pObject->GetPositionMatrix( &matrix ); Vector m_worldGoalAxis(0,0,1); // Get the alignment axis in object space Vector currentLocalTargetAxis; VectorIRotate( m_worldGoalAxis, matrix, currentLocalTargetAxis ); float invDeltaTime = (1/deltaTime); float m_angularLimit = 10; angular = ComputeRotSpeedToAlignAxes( m_worldGoalAxis, currentLocalTargetAxis, angVel, 1.0, invDeltaTime * invDeltaTime, m_angularLimit * invDeltaTime ); } return SIM_GLOBAL_ACCELERATION; }
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; }
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::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; }