void OnUpdate( SActivationInfo* pActInfo ) { const Vec3 positionOffsetLocal = GetPortVec3( pActInfo, PORT_IN_POSITION_OFFSET_LOCAL ); const float maxDistance = max( 0.f, GetPortFloat( pActInfo, PORT_IN_MAX_LENGTH ) ); const CCamera& camera = GetISystem()->GetViewCamera(); const Vec3 cameraDirection = camera.GetViewdir(); const Vec3 cameraPositionWorld = camera.GetPosition(); const Matrix33 cameraOrientation = Matrix33::CreateRotationVDir( cameraDirection ); const Vec3 positionOffsetWorld = cameraOrientation * positionOffsetLocal; const Vec3 rayOriginWorld = cameraPositionWorld + positionOffsetWorld; const Vec3 raySegment = cameraDirection * maxDistance; IPhysicalWorld* pWorld = gEnv->pPhysicalWorld; const int objectTypes = ent_all; const unsigned int raycastFlags = rwi_stop_at_pierceable | rwi_colltype_any; ray_hit hit; const int hitCount = pWorld->RayWorldIntersection( rayOriginWorld, raySegment, objectTypes, raycastFlags, &hit, 1 ); float hitDistance = maxDistance; if ( 0 < hitCount ) { hitDistance = hit.dist; } const float timeDelta = 0.1f; const float smoothTime = max( 0.f, GetPortFloat( pActInfo, PORT_IN_SMOOTH_TIME ) ); SmoothCD( m_smoothedHitDistance, m_hitDistanceChangeRate, timeDelta, hitDistance, smoothTime ); ActivateOutput( pActInfo, PORT_OUT_FOCUS_DISTANCE, m_smoothedHitDistance ); const float focusRangeFactor = max( 0.f, GetPortFloat( pActInfo, PORT_IN_FOCUS_RANGE_FACTOR ) ); const float focusRange = focusRangeFactor * m_smoothedHitDistance; ActivateOutput( pActInfo, PORT_OUT_FOCUS_RANGE, focusRange ); const bool drawDebugInfo = GetPortBool( pActInfo, PORT_IN_DEBUG_ENABLED ); if ( ! drawDebugInfo ) { return; } IRenderer* pRenderer = gEnv->pRenderer; IRenderAuxGeom* pRenderAuxGeom = pRenderer->GetIRenderAuxGeom(); ColorB rayColor = ( 0 < hitCount ) ? ColorB( 255, 255, 0 ) : ColorB( 255, 0, 0 ); pRenderAuxGeom->DrawSphere( hit.pt, 0.1f, rayColor ); pRenderAuxGeom->DrawLine( rayOriginWorld, rayColor, hit.pt, rayColor ); }
void CLookAim_Helper::UpdateLook(CPlayer* pPlayer, ICharacterInstance* pCharacter, bool bEnabled, f32 FOV, const Vec3& targetGlobal,const f32 *customBlends /*= NULL*/) { if (!m_initialized) { Init(pPlayer, pCharacter); } bool useLookAtComplex; bool useLookAtSimple; if (m_canUseLookAtComplex) { // for now just use the old 'complex' look at method until we sort out how to properly blend old and new look at useLookAtComplex = true; useLookAtSimple = false; } else { useLookAtComplex = true; // for backwards compatibility reasons we still update the old look-at even when m_canUseLookAtComplex is false useLookAtSimple = m_canUseLookAtSimple; } // --------------------------- // Complex (old style) Look-At // --------------------------- ISkeletonPose * pSkeletonPose = pCharacter->GetISkeletonPose(); pSkeletonPose->SetLookIK(useLookAtComplex && bEnabled, FOV, targetGlobal, customBlends); // --------------------------- // Simple Head-Only Look-At // --------------------------- if (m_canUseLookAtSimple) { float frameTime = gEnv->pTimer->GetFrameTime(); // Fade In/Out the Weight m_lookAtWeight = bEnabled ? CLAMP(m_lookAtWeight + (frameTime * m_lookAtFadeInSpeed), 0.0f, 1.0f) : CLAMP(m_lookAtWeight - (frameTime * m_lookAtFadeOutSpeed), 0.0f, 1.0f); // Blend To The Target if (targetGlobal.IsValid()) { m_lookAtTargetGlobal = targetGlobal; } SmoothCD(m_lookAtInterpolatedTargetGlobal, m_lookAtTargetRate, frameTime, m_lookAtTargetGlobal, m_lookAtTargetSmoothTime); // Push the LookAtSimple PoseModifier if (useLookAtSimple && (m_lookAtWeight > 0.0f)) { m_lookAtSimple->SetTargetGlobal(m_lookAtInterpolatedTargetGlobal); m_lookAtSimple->SetWeight(m_lookAtWeight); pCharacter->GetISkeletonAnim()->PushLayer(cryinterface_cast<IAnimationPoseModifier>(m_lookAtSimple)); } } }
void CAnimatedCharacter::SetDesiredLocalLocation( ISkeletonAnim* pSkeletonAnim, const QuatT& desiredLocalLocation, float fDeltaTime) { CRY_ASSERT(desiredLocalLocation.IsValid()); { uint32 NumAnimsInQueue = pSkeletonAnim->GetNumAnimsInFIFO(0); uint32 nMaxActiveInQueue=MAX_EXEC_QUEUE; if (nMaxActiveInQueue>NumAnimsInQueue) nMaxActiveInQueue=NumAnimsInQueue; if (NumAnimsInQueue>nMaxActiveInQueue) NumAnimsInQueue=nMaxActiveInQueue; uint32 active=0; for (uint32 a=0; a<NumAnimsInQueue; a++) { const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a); active += anim.IsActivated() ? 1 : 0; } if (active>nMaxActiveInQueue) active=nMaxActiveInQueue; nMaxActiveInQueue=active; const SParametricSampler *pLMG = NULL; for (int32 a=nMaxActiveInQueue-1; (a >= 0) && !pLMG; --a) { const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a); pLMG = anim.GetParametricSampler(); } } const Vec3 dir = desiredLocalLocation.GetColumn1(); float turnAngle = atan2f(-dir.x, dir.y); float turnSpeed = turnAngle / fDeltaTime; const Vec2 deltaVector(desiredLocalLocation.t.x, desiredLocalLocation.t.y); const float travelDist = deltaVector.GetLength(); const Vec2 deltaDir = (travelDist > 0.0f) ? (deltaVector / travelDist) : Vec2(0,0); float travelAngle = (deltaDir.x == 0.0f && deltaDir.y == 0.0f ? 0.0f : atan2f(-deltaDir.x, deltaDir.y)); float travelSpeed; if (gEnv->bMultiplayer) { travelSpeed = travelDist / fDeltaTime; } else { const float cosGroundSlope = fabsf(cosf(m_fGroundSlopeMoveDirSmooth)); travelSpeed = (cosGroundSlope > FLT_EPSILON) ? (travelDist / (fDeltaTime * cosGroundSlope)) : (travelDist / fDeltaTime); } // TravelAngle smoothing { const Vec2 newStrafe = Vec2(-sin_tpl(travelAngle), cos_tpl(travelAngle)); if (CAnimationGraphCVars::Get().m_enableTurnAngleSmoothing) { SmoothCD(m_fDesiredStrafeSmoothQTX, m_fDesiredStrafeSmoothRateQTX, fDeltaTime, newStrafe, 0.10f); } else { m_fDesiredStrafeSmoothQTX=newStrafe; m_fDesiredStrafeSmoothRateQTX.zero(); } travelAngle = Ang3::CreateRadZ(Vec2(0,1),m_fDesiredStrafeSmoothQTX); } const bool modulateTurnSpeedByTravelAngle = true; if (modulateTurnSpeedByTravelAngle) { static float minimum = DEG2RAD(10.0f); // do not change turnSpeed when travelAngle is below this static float maximum = DEG2RAD(40.0f); // force turnspeed to zero when travelAngle is above this const float turnSpeedScale = 1.0f - clamp_tpl( fabsf(travelAngle) - minimum, 0.0f, maximum - minimum ) / ( maximum - minimum ); turnSpeed *= turnSpeedScale; } // TurnSpeed smoothing { if (CAnimationGraphCVars::Get().m_enableTurnSpeedSmoothing) { SmoothCD(m_fDesiredTurnSpeedSmoothQTX, m_fDesiredTurnSpeedSmoothRateQTX, fDeltaTime, turnSpeed, 0.40f); } else { m_fDesiredTurnSpeedSmoothQTX = turnSpeed; m_fDesiredTurnSpeedSmoothRateQTX = 0.0f; } } // TravelSpeed smoothing { if (CAnimationGraphCVars::Get().m_enableTravelSpeedSmoothing) { SmoothCD(m_fDesiredMoveSpeedSmoothQTX, m_fDesiredMoveSpeedSmoothRateQTX, fDeltaTime, travelSpeed, 0.04f); } else { m_fDesiredMoveSpeedSmoothQTX = travelSpeed; m_fDesiredMoveSpeedSmoothRateQTX = 0.0f; } } SetMotionParam(pSkeletonAnim, eMotionParamID_TravelSpeed, m_fDesiredMoveSpeedSmoothQTX); SetMotionParam(pSkeletonAnim, eMotionParamID_TurnSpeed, m_fDesiredTurnSpeedSmoothQTX * CAnimationGraphCVars::Get().m_turnSpeedParamScale); SetMotionParam(pSkeletonAnim, eMotionParamID_TravelAngle, travelAngle); // eMotionParamID_TravelSlope SetMotionParam(pSkeletonAnim, eMotionParamID_TurnAngle, turnAngle); // eMotionParamID_TravelDist SetMotionParam(pSkeletonAnim, eMotionParamID_StopLeg, 0); }
void SBasicReplayMovementParams::SetDesiredLocalLocation2( ISkeletonAnim* pSkeletonAnim, const QuatT& desiredLocalLocation, float lookaheadTime, float fDeltaTime, float turnSpeedMultiplier) { QuatT m_desiredLocalLocationQTX = desiredLocalLocation; assert(m_desiredLocalLocationQTX.q.IsValid()); f32 m_desiredArrivalDeltaTimeQTX = lookaheadTime; f32 m_desiredTurnSpeedMultiplierQTX = turnSpeedMultiplier; uint32 NumAnimsInQueue = pSkeletonAnim->GetNumAnimsInFIFO(0); uint32 nMaxActiveInQueue=MAX_EXEC_QUEUE; if (nMaxActiveInQueue>NumAnimsInQueue) nMaxActiveInQueue=NumAnimsInQueue; if (NumAnimsInQueue>nMaxActiveInQueue) NumAnimsInQueue=nMaxActiveInQueue; uint32 active=0; for (uint32 a=0; a<NumAnimsInQueue; a++) { CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a); active += anim.IsActivated() ? 1 : 0; } if (active>nMaxActiveInQueue) active=nMaxActiveInQueue; nMaxActiveInQueue=active; const QuatT &rDesiredLocation = m_desiredLocalLocationQTX; const SParametricSampler *pLMG = NULL; for (int32 a=nMaxActiveInQueue-1; (a >= 0) && !pLMG; --a) { const CAnimation& anim = pSkeletonAnim->GetAnimFromFIFO(0,a); pLMG = anim.GetParametricSampler(); } Vec3 dir = rDesiredLocation.q * FORWARD_DIRECTION; Vec2 predictedDir( dir.x, dir.y ); float predictedAngle = RAD2DEG(atan2f(-predictedDir.x, predictedDir.y)); float turnSpeed = m_desiredTurnSpeedMultiplierQTX * DEG2RAD(predictedAngle) / max(0.1f, m_desiredArrivalDeltaTimeQTX); float turnAngle = DEG2RAD(predictedAngle); Vec2 deltaVector(rDesiredLocation.t.x, rDesiredLocation.t.y); float deltaDist = deltaVector.GetLength(); const float thresholdDistMin = 0.05f; const float thresholdDistMax = 0.15f; f32 uniform_scale = 1.0f;//m_pInstance->CCharInstance::GetUniformScale(); float travelDistScale = CLAMP((deltaDist - thresholdDistMin) / (thresholdDistMax - thresholdDistMin), 0.0f, 1.0f); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelDistScale, travelDistScale/uniform_scale, fDeltaTime); Vec2 deltaDir = (deltaDist > 0.0f) ? (deltaVector / deltaDist) : Vec2(0,0); float deltaAngle = (deltaDir.x == 0.0f && deltaDir.y == 0.0f ? 0.0f : RAD2DEG(atan2f(-deltaDir.x, deltaDir.y)) ); float travelAngle = DEG2RAD(deltaAngle); // Update travel direction only if distance bigger (more secure) than thresholdDistMax. // Though, also update travel direction if distance is small enough to not have any visible effect (since distance scale is zero). bool initOnly = DO_INIT_ONLY_TEST && ((deltaDist > thresholdDistMin) && (deltaDist < thresholdDistMax)); Vec2 newStrafe = Vec2(-cry_sinf(travelAngle), cry_cosf(travelAngle)); if (pLMG) { SmoothCD(m_desiredStrafeSmoothQTX, m_desiredStrafeSmoothRateQTX, fDeltaTime, newStrafe, 0.10f); } else { // CryFatalError("CryAnimation: no smooth"); m_desiredStrafeSmoothQTX=newStrafe; m_desiredStrafeSmoothRateQTX.zero(); } travelAngle=Ang3::CreateRadZ(Vec2(0,1),m_desiredStrafeSmoothQTX); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelAngle, travelAngle, fDeltaTime); float curvingFraction = 0.0f; if (pLMG) { SmoothCD(m_fDesiredTurnSpeedSmoothQTX, m_fDesiredTurnSpeedSmoothRateQTX, fDeltaTime, turnSpeed, 0.40f); } else { m_fDesiredTurnSpeedSmoothQTX=turnSpeed; m_fDesiredTurnSpeedSmoothRateQTX = 0.0f; } pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TurnSpeed, m_fDesiredTurnSpeedSmoothQTX, fDeltaTime); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TurnAngle, turnAngle, fDeltaTime); // Curving Distance float div = cry_cosf(DEG2RAD(90.0f - predictedAngle)); float curveRadius = (deltaDist / 2.0f); if( abs(div) > 0.0f ) curveRadius = curveRadius / div; float circumference = curveRadius * 2.0f * gf_PI; float curveDist = circumference * (predictedAngle * 2.0f / 360.0f); curveDist = max(deltaDist, curveDist); // Travel Speed/Distance float travelDist = LERP(deltaDist, curveDist, curvingFraction); float travelSpeed = travelDist / max(0.1f, m_desiredArrivalDeltaTimeQTX); //travelDist *= travelDistScale; //travelSpeed *= travelDistScale; // float fColDebug[4] = {1,0,0,1}; // g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.6f, fColDebug, false,"qqqtravelSpeed: atime: %f", travelSpeed ); // g_YLine+=26.0f; SmoothCD(m_fDesiredMoveSpeedSmoothQTX, m_fDesiredMoveSpeedSmoothRateQTX, fDeltaTime, travelSpeed, 0.04f); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelSpeed, m_fDesiredMoveSpeedSmoothQTX, fDeltaTime); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_TravelDist, travelDist, fDeltaTime); pSkeletonAnim->SetDesiredMotionParam(eMotionParamID_Scale, uniform_scale, fDeltaTime); }
void CVehicleMovementMPVTOL::SPathing::UpdatePathFollowing( const EntityId vtolId, const float dt, CVehicleMovementMPVTOL& rMovement, const SVehiclePhysicsStatus& physStatus, const Vec3& posNoise ) { //CryWatch("VTOL: id[%d] path[%p] loc[%f] error[%f] wait[%f]", vtolId, pCachedPathPtr, pathingData.location, networkError, waitTime ); if(!pCachedPathPtr) return; networkError *= max(0.f, 1.f-(dt*2.0f)); float networkAdj = networkError; if(waitTime > 0.f) { waitTime -= dt; if(waitTime < 0.f) { waitTime = 0.f; targetSpeed = defaultSpeed; } else { networkAdj = 0.f; targetSpeed = 0.0f; } } CWaypointPath::TNodeId currentInerpolatedNode = interpolatedNode; Vec3 targetPos; if(pCachedPathPtr->GetPosAfterDistance(currentNode, physStatus.centerOfMass, g_pGameCVars->g_VTOLPathingLookAheadDistance, targetPos, interpolatedNode, currentNode, pathingData.location, shouldLoop)) { QuatT location; CWaypointPath::TNodeId locationNode = -1; pCachedPathPtr->GetPathLoc(pathingData.location, location, locationNode); const Vec3 forward(targetPos-location.t); const Vec3 side(forward.y, -forward.x, 0.f); Vec3 noise(side.GetNormalizedSafe(physStatus.q.GetColumn0())*posNoise.x); noise.z = posNoise.z; targetPos += noise; if(waitTime<=0.f && currentInerpolatedNode!=interpolatedNode) { float fValueOut = 0.f; CWaypointPath::E_NodeDataType dataTypeOut; if(pCachedPathPtr->HasDataAtNode(interpolatedNode, dataTypeOut, fValueOut)) { if(dataTypeOut == CWaypointPath::ENDT_Speed) { targetSpeed = fValueOut; } else if(dataTypeOut == CWaypointPath::ENDT_Wait && fValueOut > 0.f) { targetSpeed = speed = 0.f; waitTime = fValueOut; } } else { targetSpeed = defaultSpeed; } } SmoothCD(speed, accel, dt, targetSpeed, 0.2f); const float finalSpeed = max(0.f, speed + clamp( networkAdj, -speed, g_pGameCVars->v_MPVTOLNetworkCatchupSpeedLimit )); const float scalar = clamp( (speed>0.1f) ? finalSpeed/speed : 1.f, 1.f, 3.f ); CMovementRequest movementRequest; movementRequest.SetDesiredSpeed(finalSpeed); movementRequest.SetMoveTarget(targetPos); movementRequest.SetBodyTarget(targetPos); movementRequest.SetLookTarget(targetPos); rMovement.RequestMovement(movementRequest); rMovement.SetYawResponseScalar(scalar); } else { pathComplete |= 0x1; } }
void CVehicleMovementMPVTOL::Update(const float deltaTime) { BaseClass::Update(deltaTime); //Update wing rotation based on linear and angular velocities if(m_pLeftWing && m_pRightWing) { const float angVelZ = m_physStatus[k_mainThread].w.z; const float speedRatio = min(1.f, __fres(m_maxAngleSpeed)*m_CurrentSpeed); //Move inside and outside wings (in terms of turning circle) at different speeds const bool leftWingIsInside = angVelZ > 0.f; const float maxRadAtCurrentSpeedOutside = m_maxAngleRad * speedRatio * clamp(m_angularVelMult * angVelZ, -1.f, 1.f); const float maxRadAtCurrentSpeedInside = maxRadAtCurrentSpeedOutside * m_insideWingMaxAngleMult; const float insideSmoothRate = m_angleSmoothTime * (2.f - speedRatio); const float outsideSmoothRate = insideSmoothRate * m_insideWingSpeedMult; if(leftWingIsInside) { SmoothCD(m_leftWingRotationRad, m_leftWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedInside, insideSmoothRate); SmoothCD(m_rightWingRotationRad, m_rightWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedOutside, outsideSmoothRate); } else { SmoothCD(m_leftWingRotationRad, m_leftWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedOutside, outsideSmoothRate); SmoothCD(m_rightWingRotationRad, m_rightWingRotationSmoothRate, deltaTime, maxRadAtCurrentSpeedInside, insideSmoothRate); } const float leftWingNoise = m_leftWingNoise.Update(deltaTime); const float rightWingNoise = m_rightWingNoise.Update(deltaTime); const Quat leftRotation = Quat::CreateRotationX(m_leftWingRotationRad+leftWingNoise); const Quat rightRotation = Quat::CreateRotationX(-m_rightWingRotationRad+rightWingNoise); m_pLeftWing->SetLocalBaseTM(Matrix34(leftRotation)); m_pRightWing->SetLocalBaseTM(Matrix34(rightRotation)); } //Exhausts periodically cut out whilst damaged if(m_exhaustsCutOut || m_exhaustsTimer) { m_exhaustsTimer -= deltaTime; if(m_exhaustsTimer < 0.f) { if(m_exhaustsCutOut) { StartExhaust(); if(--m_exhaustStuttersRemaining > 0) { m_exhaustsTimer = m_stutterDurationOn; } else { m_exhaustsTimer = Random(m_minTimeBetweenStutters, m_maxTimeBetweenStutters); //Time between stutters decreases linearly as more damage is received float progress = m_pVehicle->GetDamageRatio() - m_stutterStartDamageRatio; m_exhaustsTimer *= 1.f - ((progress * m_invStutterDamageSpread) * m_timeBetweenStutterDecayMult); m_exhaustStuttersRemaining = m_baseStutters + Random(m_maxExtraStutters); //Number of stutters next time } } else { StopExhaust(); m_exhaustsTimer = m_stutterDurationOff; } m_exhaustsCutOut = !m_exhaustsCutOut; } } #ifndef _RELEASE // Keep updating this, in case it is changed mid-game. m_sendTime = g_pGameCVars->v_MPVTOLNetworkSyncFreq; #endif }
//------------------------------------------------------------------------ void CMelee::Update(float frameTime, uint32 frameId) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); bool remote = false; bool doMelee = false; bool requireUpdate = false; Vec3 dirToTarget(ZERO); if(m_pMeleeAction && s_meleeSnapTargetId && g_pGameCVars->pl_melee.mp_melee_system_camera_lock_and_turn) { m_attackTime += frameTime; CActor* pOwner = m_pWeapon->GetOwnerActor(); IEntity* pTarget = gEnv->pEntitySystem->GetEntity(s_meleeSnapTargetId); if(pOwner && pTarget) { Vec3 targetPos = pTarget->GetWorldPos(); if(s_bMeleeSnapTargetCrouched) { targetPos.z -= g_pGameCVars->pl_melee.mp_melee_system_camera_lock_crouch_height_offset; } dirToTarget = targetPos - pOwner->GetEntity()->GetWorldPos(); dirToTarget.Normalize(); static const float smooth_time = 0.1f; SmoothCD(m_attackTurnAmount, m_attackTurnAmountSmoothRate, frameTime, 1.f, smooth_time); Quat newViewRotation; newViewRotation.SetSlerp(pOwner->GetViewRotation(), Quat::CreateRotationVDir(dirToTarget), m_attackTurnAmount); Ang3 newAngles(newViewRotation); newAngles.y = 0.f; //No head tilting newViewRotation = Quat(newAngles); pOwner->SetViewRotation( newViewRotation ); } if(m_attackTime >= g_pGameCVars->pl_melee.mp_melee_system_camera_lock_time && pOwner && pOwner->IsClient()) { pOwner->GetActorParams().viewLimits.ClearViewLimit(SViewLimitParams::eVLS_Item); } } if (m_attacking) { MeleeDebugLog ("CMelee<%p> Update while attacking: m_attacked=%d, delay=%f", this, m_attacked, m_delayTimer); requireUpdate = true; if (m_delayTimer>0.0f) { RequestAlignmentToNearestTarget(); m_delayTimer-=frameTime; if (m_delayTimer<=0.0f) { m_delayTimer=0.0f; } } else if (m_netAttacking) { remote = true; doMelee = true; m_attacking = false; m_slideKick = false; m_netAttacking = false; m_pWeapon->SetBusy(false); } else if (!m_attacked) { doMelee = true; m_attacked = true; } if ( !m_collisionHelper.IsBlocked() && doMelee) { if (CActor *pActor = m_pWeapon->GetOwnerActor()) { if (IMovementController * pMC = pActor->GetMovementController()) { SMovementState info; pMC->GetMovementState(info); if(!dirToTarget.IsZeroFast()) { PerformMelee(info.weaponPosition, dirToTarget, remote); //We know where we will be facing at the point of impact - using our current fire direction is not accurate enough } else { PerformMelee(info.weaponPosition, info.fireDirection, remote); } } } } if( (m_useMeleeWeaponDelay <= 0.0f && m_useMeleeWeaponDelay > -1.0f) ) { m_useMeleeWeaponDelay = -1.0f; // Switch to the MELEE WEAPON. SwitchToMeleeWeaponAndAttack(); m_attacking = false; } m_useMeleeWeaponDelay -= frameTime; } if (requireUpdate) m_pWeapon->RequireUpdate(eIUS_FireMode); }