// ----------------------------------------------------------------------------- // Purpose: // Note: Think function to delay the impact decal until the animation is finished // playing. // ----------------------------------------------------------------------------- void CTFWeaponBaseMelee::Smack( void ) { trace_t trace; CBasePlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; #if !defined (CLIENT_DLL) // Move other players back to history positions based on local player's lag lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); #endif // We hit, setup the smack. if ( DoSwingTrace( trace ) ) { // Hit sound - immediate. if( trace.m_pEnt->IsPlayer() ) { WeaponSound( MELEE_HIT ); } else { WeaponSound( MELEE_HIT_WORLD ); } // Get the current player. CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( !pPlayer ) return; Vector vecForward; AngleVectors( pPlayer->EyeAngles(), &vecForward ); Vector vecSwingStart = pPlayer->Weapon_ShootPosition(); Vector vecSwingEnd = vecSwingStart + vecForward * 48; #ifndef CLIENT_DLL // Do Damage. int iCustomDamage = TF_DMG_CUSTOM_NONE; float flDamage = GetMeleeDamage( trace.m_pEnt, iCustomDamage ); int iDmgType = DMG_BULLET | DMG_NEVERGIB | DMG_CLUB; if ( IsCurrentAttackACrit() ) { // TODO: Not removing the old critical path yet, but the new custom damage is marking criticals as well for melee now. iDmgType |= DMG_CRITICAL; } CTFWeaponBase *pWpn = pPlayer->GetActiveTFWeapon(); CTFUbersaw *pUbersaw = dynamic_cast<CTFUbersaw*>(pWpn); CWeaponMedigun *pMedigun = static_cast<CWeaponMedigun*>(pPlayer->Weapon_OwnsThisID(TF_WEAPON_MEDIGUN)); if (pMedigun && pUbersaw) { if(trace.m_pEnt->IsPlayer() && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber()) { pMedigun->AddCharge(); } } CWeaponKritzkrieg *pKritzkrieg = static_cast<CWeaponKritzkrieg*>(pPlayer->Weapon_OwnsThisID(TF_WEAPON_KRITZKRIEG)); if (pKritzkrieg && pUbersaw) { if(trace.m_pEnt->IsPlayer() && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber()) { pKritzkrieg->AddCharge(); } } CTakeDamageInfo info( pPlayer, pPlayer, flDamage, iDmgType, iCustomDamage ); CalculateMeleeDamageForce( &info, vecForward, vecSwingEnd, 1.0f / flDamage * tf_meleeattackforcescale.GetFloat() ); trace.m_pEnt->DispatchTraceAttack( info, vecForward, &trace ); ApplyMultiDamage(); OnEntityHit( trace.m_pEnt ); #endif // Don't impact trace friendly players or objects if ( trace.m_pEnt && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber() ) { #ifdef CLIENT_DLL UTIL_ImpactTrace( &trace, DMG_CLUB ); #endif m_bConnected = true; } } #if !defined (CLIENT_DLL) lagcompensation->FinishLagCompensation( pPlayer ); #endif }
//------------------------------------------------------------------------ int CMelee::Hit(const Vec3 &pt, const Vec3 &dir, const Vec3 &normal, IPhysicalEntity *pCollider, EntityId collidedEntityId, int partId, int ipart, int surfaceIdx, bool remote) { MeleeDebugLog ("CMelee<%p> HitPointDirNormal(remote=%s)", this, remote ? "true" : "false"); int hitTypeID = 0; CActor *pOwnerActor = m_pWeapon->GetOwnerActor(); if (pOwnerActor) { IActor* pTargetActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(collidedEntityId); IEntity* pTarget = pTargetActor ? pTargetActor->GetEntity() : gEnv->pEntitySystem->GetEntity(collidedEntityId); IEntity* pOwnerEntity = pOwnerActor->GetEntity(); IAIObject* pOwnerAI = pOwnerEntity->GetAI(); float damageScale = 1.0f; bool silentHit = false; if(pTargetActor) { IAnimatedCharacter* pTargetAC = pTargetActor->GetAnimatedCharacter(); IAnimatedCharacter* pOwnerAC = pOwnerActor->GetAnimatedCharacter(); if(pTargetAC && pOwnerAC) { Vec3 targetFacing(pTargetAC->GetAnimLocation().GetColumn1()); Vec3 ownerFacing(pOwnerAC->GetAnimLocation().GetColumn1()); float ownerFacingDot = ownerFacing.Dot(targetFacing); float fromBehindDot = cos_tpl(DEG2RAD(g_pGameCVars->pl_melee.angle_limit_from_behind)); if(ownerFacingDot > fromBehindDot) { #ifndef _RELEASE if (g_pGameCVars->g_LogDamage) { CryLog ("[DAMAGE] %s '%s' is%s meleeing %s '%s' from behind (because %f > %f)", pOwnerActor->GetEntity()->GetClass()->GetName(), pOwnerActor->GetEntity()->GetName(), silentHit ? " silently" : "", pTargetActor->GetEntity()->GetClass()->GetName(), pTargetActor->GetEntity()->GetName(), ownerFacingDot, fromBehindDot); } #endif damageScale *= g_pGameCVars->pl_melee.damage_multiplier_from_behind; } } } // Send target stimuli if (!gEnv->bMultiplayer) { IAISystem *pAISystem = gEnv->pAISystem; ITargetTrackManager *pTargetTrackManager = pAISystem ? pAISystem->GetTargetTrackManager() : NULL; if (pTargetTrackManager && pOwnerAI) { IAIObject *pTargetAI = pTarget ? pTarget->GetAI() : NULL; if (pTargetAI) { const tAIObjectID aiOwnerId = pOwnerAI->GetAIObjectID(); const tAIObjectID aiTargetId = pTargetAI->GetAIObjectID(); TargetTrackHelpers::SStimulusEvent eventInfo; eventInfo.vPos = pt; eventInfo.eStimulusType = TargetTrackHelpers::eEST_Generic; eventInfo.eTargetThreat = AITHREAT_AGGRESSIVE; pTargetTrackManager->HandleStimulusEventForAgent(aiTargetId, aiOwnerId, "MeleeHit",eventInfo); pTargetTrackManager->HandleStimulusEventInRange(aiOwnerId, "MeleeHitNear", eventInfo, 5.0f); } } } //Check if is a friendly hit, in that case FX and Hit will be skipped bool isFriendlyHit = (pOwnerEntity && pTarget) ? IsFriendlyHit(pOwnerEntity, pTarget) : false; if(!isFriendlyHit) { CPlayer * pAttackerPlayer = pOwnerActor->IsPlayer() ? static_cast<CPlayer*>(pOwnerActor) : NULL; float damage = m_pMeleeParams->meleeparams.damage_ai; if(pOwnerActor->IsPlayer()) { damage = m_slideKick ? m_pMeleeParams->meleeparams.slide_damage : GetMeleeDamage(); } #ifndef _RELEASE if (pTargetActor && g_pGameCVars->g_LogDamage) { CryLog ("[DAMAGE] %s '%s' is%s meleeing %s '%s' applying damage = %.3f x %.3f = %.3f", pOwnerActor->GetEntity()->GetClass()->GetName(), pOwnerActor->GetEntity()->GetName(), silentHit ? " silently" : "", pTargetActor->GetEntity()->GetClass()->GetName(), pTargetActor->GetEntity()->GetName(), damage, damageScale, damage * damageScale); } #endif //Generate Hit if(pTarget) { CGameRules *pGameRules = g_pGame->GetGameRules(); CRY_ASSERT_MESSAGE(pGameRules, "No game rules! Melee can not apply hit damage"); if (pGameRules) { hitTypeID = silentHit ? CGameRules::EHitType::SilentMelee : m_hitTypeID; HitInfo info(m_pWeapon->GetOwnerId(), pTarget->GetId(), m_pWeapon->GetEntityId(), damage * damageScale, 0.0f, surfaceIdx, partId, hitTypeID, pt, dir, normal); if (m_pMeleeParams->meleeparams.knockdown_chance>0 && Random(100) < m_pMeleeParams->meleeparams.knockdown_chance) info.knocksDown = true; info.remote = remote; pGameRules->ClientHit(info); } if (pAttackerPlayer && pAttackerPlayer->IsClient()) { const Vec3 posOffset = (pt - pTarget->GetWorldPos()); SMeleeHitParams params; params.m_boostedMelee = false; params.m_hitNormal = normal; params.m_hitOffset = posOffset; params.m_surfaceIdx = surfaceIdx; params.m_targetId = pTarget->GetId(); pAttackerPlayer->OnMeleeHit(params); } } else { //Play Material FX PlayHitMaterialEffect(pt, normal, false, surfaceIdx); } } if (pTarget) { CActor *pCTargetActor = static_cast<CActor*>(pTargetActor); CPlayer* pTargetPlayer = (pTargetActor && pTargetActor->IsPlayer()) ? static_cast<CPlayer*>(pTargetActor) : NULL; if(pTargetPlayer && pTargetPlayer->IsClient()) { if(m_pMeleeParams->meleeparams.trigger_client_reaction) { pTargetPlayer->TriggerMeleeReaction(); } } } } return hitTypeID; }