//------------------------------------------------------------------------
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);
				}
			}
		}
	}
}
Пример #2
0
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;
}
Пример #3
0
	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());
								}
							}
						}
					}
				}
			}
		}
	}