//------------------------------------------------------------------------ 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); } } } } }
bool CShotgun::Shoot(bool resetAnimation, bool autoreload/* =true */, bool noSound /* =false */) { IEntityClass *ammo = m_pShared->fireparams.ammo_type_class; int ammoCount = m_pWeapon->GetAmmoCount(ammo); if(m_pShared->fireparams.clip_size==0) ammoCount = m_pWeapon->GetInventoryAmmoCount(ammo); CActor *pActor = m_pWeapon->GetOwnerActor(); bool playerIsShooter = pActor?pActor->IsPlayer():false; if(!CanFire(true)) { if((ammoCount <= 0) && (!m_reloading)) { m_pWeapon->PlayAction(m_pShared->actions.empty_clip); //Auto reload m_pWeapon->Reload(); } return false; } else if(m_pWeapon->IsWeaponLowered()) { m_pWeapon->PlayAction(m_pShared->actions.null_fire); return false; } if(m_reloading) { if(m_pWeapon->IsBusy()) m_pWeapon->SetBusy(false); if(CanFire(true) && !m_break_reload) { m_break_reload = true; m_pWeapon->RequestCancelReload(); } return false; } // Aim assistance m_pWeapon->AssistAiming(); const char *action = m_pShared->actions.fire_cock.c_str(); if(ammoCount == 1 || (m_pShared->fireparams.no_cock && m_pWeapon->IsZoomed())) action = m_pShared->actions.fire.c_str(); m_pWeapon->PlayAction(action, 0, false, CItem::eIPAF_Default|CItem::eIPAF_RestartAnimation|CItem::eIPAF_CleanBlending); Vec3 hit = GetProbableHit(WEAPON_HIT_RANGE); Vec3 pos = GetFiringPos(hit); Vec3 fdir = ApplySpread(GetFiringDir(hit, pos), GetSpread()); Vec3 vel = GetFiringVelocity(fdir); Vec3 dir; CheckNearMisses(hit, pos, fdir, WEAPON_HIT_RANGE, m_pShared->shotgunparams.spread); bool serverSpawn = m_pWeapon->IsServerSpawn(ammo); // SHOT HERE for(int i = 0; i < m_pShared->shotgunparams.pellets; i++) { CProjectile *pAmmo = m_pWeapon->SpawnAmmo(ammo, false); if(pAmmo) { dir = ApplySpread(fdir, m_pShared->shotgunparams.spread); int hitTypeId = g_pGame->GetGameRules()->GetHitTypeId(m_pShared->fireparams.hit_type.c_str()); pAmmo->SetParams(m_pWeapon->GetOwnerId(), m_pWeapon->GetHostId(), m_pWeapon->GetEntityId(), m_pShared->shotgunparams.pelletdamage, hitTypeId, playerIsShooter?m_pShared->fireparams.damage_drop_per_meter:0.0f, m_pShared->fireparams.damage_drop_min_distance); pAmmo->SetDestination(m_pWeapon->GetDestination()); pAmmo->Launch(pos, dir, vel); if((!m_pShared->tracerparams.geometry.empty() || !m_pShared->tracerparams.effect.empty()) && (ammoCount==GetClipSize() || (ammoCount%m_pShared->tracerparams.frequency==0))) { EmitTracer(pos,hit,false); } m_projectileId = pAmmo->GetEntity()->GetId(); } } m_pWeapon->OnShoot(m_pWeapon->GetOwnerId(), 0, ammo, pos, dir, vel); if(m_pWeapon->IsServer()) { const char *ammoName = ammo != NULL ? ammo->GetName() : NULL; g_pGame->GetIGameFramework()->GetIGameplayRecorder()->Event(m_pWeapon->GetOwner(), GameplayEvent(eGE_WeaponShot, ammoName, m_pShared->shotgunparams.pellets, (void *)m_pWeapon->GetEntityId())); } MuzzleFlashEffect(true); RejectEffect(); m_fired = true; m_next_shot += m_next_shot_dt; m_zoomtimeout = m_next_shot + 0.5f; ammoCount--; if(playerIsShooter) { if(pActor->InZeroG()) { IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy *)pActor->GetEntity()->GetProxy(ENTITY_PROXY_PHYSICS); SMovementState ms; pActor->GetMovementController()->GetMovementState(ms); CPlayer *plr = (CPlayer *)pActor; if(m_recoilparams.back_impulse > 0.0f) { Vec3 impulseDir = ms.aimDirection * -1.0f; Vec3 impulsePos = ms.pos; float impulse = m_recoilparams.back_impulse; pPhysicsProxy->AddImpulse(-1, impulsePos, impulseDir * impulse * 100.0f, true, 1.0f); } if(m_recoilparams.angular_impulse > 0.0f) { float impulse = m_recoilparams.angular_impulse; pActor->AddAngularImpulse(Ang3(0,impulse,0), 1.0f); } } if(pActor->IsClient()) if(gEnv->pInput) gEnv->pInput->ForceFeedbackEvent(SFFOutputEvent(eDI_XI, eFF_Rumble_Basic, 0.15f, 0.0f, fabsf(m_recoilparams.back_impulse)*3.0f)); } if(m_pShared->fireparams.clip_size != -1) { if(m_pShared->fireparams.clip_size!=0) m_pWeapon->SetAmmoCount(ammo, ammoCount); else m_pWeapon->SetInventoryAmmoCount(ammo, ammoCount); } if((ammoCount<1) && !m_pShared->fireparams.slider_layer.empty()) { const char *slider_back_layer = m_pShared->fireparams.slider_layer.c_str(); m_pWeapon->PlayLayer(slider_back_layer, CItem::eIPAF_Default|CItem::eIPAF_NoBlend); } if(OutOfAmmo()) { m_pWeapon->OnOutOfAmmo(ammo); if(autoreload) { m_pWeapon->GetScheduler()->TimerAction(m_pWeapon->GetCurrentAnimationTime(eIGS_FirstPerson), CSchedulerAction<ScheduleReload>::Create(m_pWeapon), false); } } m_pWeapon->RequestShoot(ammo, pos, dir, vel, hit, 1.0f, 0, false); return true; }
void Update(float elapsed) { float maxTime = GetPortFloat(&m_actInfo, EIP_Duration); float percent = maxTime > FLT_EPSILON ? elapsed / maxTime : 1.0f; if(percent >= 1.0f) { m_actInfo.pGraph->SetRegularlyUpdated(m_actInfo.myID, false); m_triggered = false; return; } Vec3 N = GetPortVec3(&m_actInfo, EIP_Normal); float rangeMin = GetPortFloat(&m_actInfo, EIP_RangeMin); float rangeMax = GetPortFloat(&m_actInfo, EIP_RangeMax); const float range = rangeMax - rangeMin; Vec3 boxDim(rangeMax, rangeMax, rangeMax); Vec3 ptmin = m_effectCenter - boxDim; Vec3 ptmax = m_effectCenter + boxDim; float speed = GetPortFloat(&m_actInfo, EIP_Speed); float waveFront = elapsed * speed; float decay = GetPortFloat(&m_actInfo, EIP_Decay); if(decay > FLT_EPSILON) decay = 1.0f / decay; float force = GetPortFloat(&m_actInfo, EIP_Force); force = pow_tpl(force * (1-percent), decay); float amplitude = GetPortFloat(&m_actInfo, EIP_Amplitude); amplitude = pow_tpl(amplitude * (1-percent), decay); if (gEnv->bMultiplayer) // Turned off for performance and network issues { return; } IPhysicalEntity** pEntityList = NULL; static const int iObjTypes = ent_rigid | ent_sleeping_rigid | ent_living;// | ent_allocate_list; int numEntities = gEnv->pPhysicalWorld->GetEntitiesInBox(ptmin, ptmax, pEntityList, iObjTypes); AABB bounds; for(int i=0; i<numEntities; ++i) { IPhysicalEntity* pPhysicalEntity = pEntityList[i]; IEntity* pEntity = static_cast<IEntity*>(pPhysicalEntity->GetForeignData(PHYS_FOREIGN_ID_ENTITY)); // Has the entity already been affected? if(pEntity) { bool affected = stl::find(m_entitiesAffected, pEntity->GetId()); if(!affected) { IEntityPhysicalProxy* pPhysicalProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS)); if(pPhysicalProxy) { pPhysicalProxy->GetWorldBounds(bounds); Vec3 p = bounds.GetCenter(); Vec3 v = p - m_effectCenter; float distFromCenter = v.GetLength() + FLT_EPSILON; if(distFromCenter < rangeMax) { if(waveFront > distFromCenter) // has the wavefront passed the entity? { //pPhysicalEntity->GetStatus(&dyn); // normalize v, cheaper than another sqrt v /= distFromCenter; Vec3 dir = N + v * force; static bool usePos = false; float impulse = 1.0f - (max(0.0f, distFromCenter - rangeMin) / range); impulse = impulse * amplitude;// / dyn.mass; if(impulse > FLT_EPSILON) { pPhysicalProxy->AddImpulse(-1, p, dir * impulse, usePos, 1.0f); m_entitiesAffected.push_back(pEntity->GetId()); } } } } } } } }