float CCannonBall::GetFinalDamage( const Vec3& hitPos ) const { float damage = (float)m_damage - m_accumulatedDamageFallOffAfterPenetration; if(m_damageFallOffAmount > 0.f) { float distTravelledSq = (m_initial_pos - hitPos).GetLengthSquared(); bool fallof = distTravelledSq > (m_damageFallOffStart*m_damageFallOffStart); bool pointBlank = distTravelledSq < (m_pointBlankFalloffDistance*m_pointBlankFalloffDistance) && m_ownerIsPlayer; float distTravelled = (fallof || pointBlank) ? cry_sqrtf(distTravelledSq) : 0.0f; if (fallof) { distTravelled -= m_damageFallOffStart; damage -= distTravelled * m_damageFallOffAmount; } if (pointBlank) { damage *= Projectile::GetPointBlankMultiplierAtRange(distTravelled, m_pointBlankDistance, m_pointBlankFalloffDistance, m_pointBlankAmount); } } damage = max(damage, m_damageFalloffMin); return damage; }
//------------------------------------------------------------------------ void CMelee::Impulse(const Vec3 &pt, const Vec3 &dir, const Vec3 &normal, IPhysicalEntity *pCollider, int partId, int ipart, int surfaceIdx, float impulseScale) { if(m_noImpulse) { m_noImpulse = false; return; } if (pCollider && m_pShared->meleeparams.impulse > 0.001f) { bool strengthMode = false; CPlayer *pPlayer = (CPlayer *)m_pWeapon->GetOwnerActor(); pe_status_dynamics dyn; if (!pCollider->GetStatus(&dyn)) { if(strengthMode) { impulseScale *= 3.0f; } } else { impulseScale *= clamp((dyn.mass * 0.01f), 1.0f, 15.0f); } //[kirill] add impulse to phys proxy - to make sure it's applied to cylinder as well (not only skeleton) - so that entity gets pushed // if no pEntity - do it old way IEntity *pEntity = (IEntity *) pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); if(gEnv->bMultiplayer && pEntity) { if(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()) == NULL) { impulseScale *= 0.33f; } } if(pEntity) { bool crapDollFilter = false; #ifdef CRAPDOLLS static IEntityClass *pDeadBodyClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("DeadBody"); if (pEntity->GetClass() == pDeadBodyClass) { crapDollFilter = true; } #endif //CRAPDOLLS if (!crapDollFilter) { IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy *)pEntity->GetProxy(ENTITY_PROXY_PHYSICS); CActor *pActor = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()); if (pActor) { SActorStats *pAS = pActor->GetActorStats(); if (pAS && pAS->isRagDoll) { //marcok: talk to me before touching this impulseScale = 1.0f; //jan: melee impulses were scaled down, I made sure it still "barely moves" #ifdef CRAPDOLLS crapDollFilter = true; #endif //CRAPDOLLS } } // scale impulse up a bit for player if (!crapDollFilter) { pPhysicsProxy->AddImpulse(partId, pt, dir * m_pShared->meleeparams.impulse * impulseScale * m_meleeScale, true, 1.f); } } } else { pe_action_impulse ai; ai.partid = partId; ai.ipart = ipart; ai.point = pt; ai.iApplyTime = 0; ai.impulse = dir * (m_pShared->meleeparams.impulse * impulseScale * m_meleeScale); pCollider->Action(&ai); } ISurfaceTypeManager *pSurfaceTypeManager = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager(); int invId = pSurfaceTypeManager->GetSurfaceTypeByName("mat_invulnerable")->GetId(); // create a physical collision to break trees pe_action_register_coll_event collision; collision.collMass = 0.005f; // this is actually ignored collision.partid[1] = partId; // collisions involving partId<-1 are to be ignored by game's damage calculations // usually created articially to make stuff break. collision.partid[0] = -2; collision.idmat[1] = surfaceIdx; collision.idmat[0] = invId; collision.n = normal; collision.pt = pt; // scar bullet // m = 0.0125 // v = 800 // energy: 4000 // in this case the mass of the active collider is a player part // so we must solve for v given the same energy as a scar bullet Vec3 v = dir; float speed = cry_sqrtf(4000.0f / (80.0f * 0.5f)); // 80.0f is the mass of the player // [marco] Check if an object. Should take lots of time to break stuff if not in nanosuit strength mode; // and still creates a very low impulse for stuff that might depend on receiving an impulse. IRenderNode *pBrush = (IRenderNode *)pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC); collision.vSelf = (v.normalized() * speed * m_meleeScale); collision.v = Vec3(0, 0, 0); collision.pCollider = pCollider; IEntity *pOwner = m_pWeapon->GetOwner(); if (pOwner && pOwner->GetCharacter(0) && pOwner->GetCharacter(0)->GetISkeletonPose()->GetCharacterPhysics()) { if (ISkeletonPose *pSkeletonPose = pOwner->GetCharacter(0)->GetISkeletonPose()) { if (pSkeletonPose && pSkeletonPose->GetCharacterPhysics()) { pSkeletonPose->GetCharacterPhysics()->Action(&collision); } } } } }
void CMelee::Impulse(const Vec3 &pt, const Vec3 &dir, const Vec3 &normal, IPhysicalEntity *pCollider, EntityId collidedEntityId, int partId, int ipart, int surfaceIdx, int hitTypeID, int iPrim) { if (pCollider && m_pMeleeParams->meleeparams.impulse>0.001f) { CActor* pOwnerActor = m_pWeapon->GetOwnerActor(); const SPlayerMelee& meleeCVars = g_pGameCVars->pl_melee; const SMeleeParams& meleeParams = m_pMeleeParams->meleeparams; float impulse = meleeParams.impulse; bool aiShooter = pOwnerActor ? !pOwnerActor->IsPlayer() : true; bool delayImpulse = false; float impulseScale = 1.0f; //[kirill] add impulse to phys proxy - to make sure it's applied to cylinder as well (not only skeleton) - so that entity gets pushed // if no pEntity - do it old way IEntity * pEntity = gEnv->pEntitySystem->GetEntity(collidedEntityId); IGameFramework* pGameFramework = g_pGame->GetIGameFramework(); CActor* pTargetActor = static_cast<CActor*>(pGameFramework->GetIActorSystem()->GetActor(collidedEntityId)); if (pEntity && pTargetActor) { //If it's an entity, use the specific impulses if needed, and apply to physics proxy if ( meleeCVars.impulses_enable != SPlayerMelee::ei_Disabled ) { impulse = meleeParams.impulse_actor; bool aiTarget = !pTargetActor->IsPlayer(); if (aiShooter && !aiTarget) { float impulse_ai_to_player = GetImpulseAiToPlayer(); if (impulse_ai_to_player != -1.f) { impulse = impulse_ai_to_player; } } //Delay a bit on death actors, when switching from alive to death, impulses don't apply //I schedule an impulse here, to get rid off the ugly .lua code which was calculating impulses on its own if (pTargetActor->IsDead()) { if (meleeCVars.impulses_enable != SPlayerMelee::ei_OnlyToAlive) { delayImpulse = true; const float actorCustomScale = 1.0f; impulseScale *= actorCustomScale; } else { impulse = 0.0f; } } else if (meleeCVars.impulses_enable == SPlayerMelee::ei_OnlyToDead) { // Always allow impulses for melee from AI to local player // [*DavidR | 27/Oct/2010] Not sure about this if (!(aiShooter && !aiTarget)) impulse = 0.0f; } } else if (pGameFramework->GetIVehicleSystem()->GetVehicle(collidedEntityId)) { impulse = m_pMeleeParams->meleeparams.impulse_vehicle; impulseScale = 1.0f; } } const float fScaledImpulse = impulse * impulseScale; if (fScaledImpulse > 0.0f) { if (!delayImpulse) { m_collisionHelper.Impulse(pCollider, pt, dir * fScaledImpulse, partId, ipart, hitTypeID); } else { //Force up impulse, to make the enemy fly a bit Vec3 newDir = (dir.z < 0.0f) ? Vec3(dir.x, dir.y, 0.1f) : dir; newDir.Normalize(); newDir.x *= fScaledImpulse; newDir.y *= fScaledImpulse; newDir.z *= impulse; if( pTargetActor ) { pe_action_impulse imp; imp.iApplyTime = 0; imp.impulse = newDir; //imp.ipart = ipart; imp.partid = partId; imp.point = pt; pTargetActor->GetImpulseHander()->SetOnRagdollPhysicalizedImpulse( imp ); } else { m_pWeapon->GetScheduler()->TimerAction(100, CSchedulerAction<DelayedImpulse>::Create(DelayedImpulse(*this, collidedEntityId, pt, newDir, partId, ipart, hitTypeID)), true); } } } // scar bullet // m = 0.0125 // v = 800 // energy: 4000 // in this case the mass of the active collider is a player part // so we must solve for v given the same energy as a scar bullet float speed = cry_sqrtf(4000.0f/(80.0f*0.5f)); // 80.0f is the mass of the player if( IRenderNode *pBrush = (IRenderNode*)pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC) ) { speed = 0.003f; } m_collisionHelper.GenerateArtificialCollision(m_pWeapon->GetOwner(), pCollider, pt, normal, dir * speed, partId, ipart, surfaceIdx, iPrim); } }