コード例 #1
0
bool CGameRulesMPDamageHandling::SvOnHitScaled( const HitInfo &hitInfo )
{
	bool bReturnDied = false;
	IEntity *pTarget = gEnv->pEntitySystem->GetEntity(hitInfo.targetId);
	CActor *pActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(hitInfo.targetId));

	if(!pActor)
	{
		IVehicle* pVictimVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(hitInfo.targetId);

		if(pVictimVehicle)
		{
			float vehicleDamageMultiplier = 1.f;

			//Additional damage scaling check for vehicles with associated body damage files
			CBodyDamageManager *pBodyDamageManager = g_pGame->GetBodyDamageManager();

			TBodyDamageProfileId bodyDamageProfileId;
			TVehicleBodyDamageMap::const_iterator iter = m_vehicleBodyDamageMap.find( hitInfo.targetId );
			if( iter != m_vehicleBodyDamageMap.end() )
			{
				bodyDamageProfileId = iter->second;
			}
			else
			{
				bodyDamageProfileId = pBodyDamageManager->GetBodyDamage( *pTarget );
				m_vehicleBodyDamageMap[hitInfo.targetId] = bodyDamageProfileId;
			}

			if(bodyDamageProfileId != INVALID_BODYDAMAGEPROFILEID)
			{
				vehicleDamageMultiplier *= pBodyDamageManager->GetDamageMultiplier(bodyDamageProfileId, *pTarget, hitInfo);
			}

			float fPreviousHealth = pVictimVehicle->GetStatus().health;

			// for vehicles, no need to call lua any more, we can just apply the hit directly to the vehicle
			{
				HitInfo hitInfoTemp = hitInfo;
				hitInfoTemp.damage *= vehicleDamageMultiplier;
				hitInfoTemp.explosion = false;
				pVictimVehicle->OnHit(hitInfoTemp);
			}


			float fNewHealth = pVictimVehicle->GetStatus().health;

			//Hit indicator for driver
			//	Health check is required to take into account damage removal due to friendly fire.
			if(fNewHealth != fPreviousHealth)
			{
				if(IActor* pDriver = pVictimVehicle->GetDriver())
				{
					if(IEntity* pShooterEntity = gEnv->pEntitySystem->GetEntity(hitInfo.shooterId))
					{
						Vec3 shooterPos = pShooterEntity->GetWorldPos();

						if(pDriver->IsClient())
						{
							SHUDEvent hitEvent(eHUDEvent_OnShowHitIndicatorPlayerUpdated);
							hitEvent.ReserveData(3);
							hitEvent.AddData(shooterPos.x);
							hitEvent.AddData(shooterPos.y);
							hitEvent.AddData(shooterPos.z);
							CHUDEventDispatcher::CallEvent(hitEvent);
						}
						else
						{
							m_pGameRules->GetGameObject()->InvokeRMI( CGameRules::ClActivateHitIndicator(), CGameRules::ActivateHitIndicatorParams(shooterPos), eRMI_ToClientChannel, pDriver->GetChannelId() );
						}
					}
				}
			}

			// no need for further processing, or calling OnEntityKilled, so just return early.
			if(pVictimVehicle->GetDamageRatio() >= 1.f)
			{
				if(fNewHealth != fPreviousHealth)
				{
					SVehicleDestroyedParams params(hitInfo.targetId, hitInfo.weaponId, hitInfo.type, hitInfo.projectileClassId);
					if(hitInfo.shooterId == g_pGame->GetClientActorId())
					{
						CPersistantStats::GetInstance()->OnClientDestroyedVehicle(params);
					}
					else if(IGameObject * pShooterGameObject = g_pGame->GetIGameFramework()->GetGameObject(hitInfo.shooterId))
					{
						m_pGameRules->GetGameObject()->InvokeRMIWithDependentObject(CGameRules::ClVehicleDestroyed(), params, eRMI_ToClientChannel, hitInfo.shooterId, pShooterGameObject->GetChannelId());
					}					
				}
				m_pGameRules->OnEntityKilled(hitInfo);
				return true; 
			}
			else
			{
				return false;
			}
		}
	}

	if (pTarget)
	{
		IScriptTable *pTargetScript = pTarget->GetScriptTable();
		if (pTargetScript)
		{
			m_pGameRules->CreateScriptHitInfo(m_scriptHitInfo, hitInfo);

			bool isDead = false;

			if (pActor)
			{
				if (pActor->IsDead())
				{
					isDead = true;

					// Target is already dead
					HSCRIPTFUNCTION pfnOnDeadHit = 0;
					if (pActor->GetActorStats()->isRagDoll && pTargetScript->GetValue("OnDeadHit", pfnOnDeadHit))
					{
						Script::CallMethod(pTargetScript, pfnOnDeadHit, m_scriptHitInfo);
						gEnv->pScriptSystem->ReleaseFunc(pfnOnDeadHit);
					}
				}
			}

			if (!isDead)
			{
				SmartScriptTable targetServerScript;
				if (pTargetScript->GetValue("Server", targetServerScript))
				{
					HSCRIPTFUNCTION pfnOnHit = 0;
					if (targetServerScript->GetValue("OnHit", pfnOnHit))
					{
						if (Script::CallReturn(gEnv->pScriptSystem, pfnOnHit, pTargetScript, m_scriptHitInfo, bReturnDied))
						{
							if (bReturnDied)
							{
								if (pActor)
								{
									ProcessDeath(hitInfo, *pActor);
								}
								else
								{
									m_pGameRules->OnEntityKilled(hitInfo);
								}
							}
						}
						gEnv->pScriptSystem->ReleaseFunc(pfnOnHit);
					}
				}
			}
		}
	}

	return bReturnDied;
}
コード例 #2
0
//------------------------------------------------------------------------
void CGameRulesMPDamageHandling::SvOnCollision(const IEntity *pVictimEntity, const CGameRules::SCollisionHitInfo& collisionHitInfo)
{
	FUNCTION_PROFILER(gEnv->pSystem, PROFILE_GAME);
	CRY_ASSERT(gEnv->bMultiplayer);

#if !defined(_RELEASE)
	if (g_pGameCVars->g_DisableCollisionDamage)
		return;
#endif

	IGameFramework* gameFramwork = g_pGame->GetIGameFramework();

	EntityId victimID = pVictimEntity->GetId();
	EntityId offenderID = collisionHitInfo.targetId;

	const IEntity* pOffenderEntity = gEnv->pEntitySystem->GetEntity(offenderID);

	float currentTime = gEnv->pTimer->GetCurrTime();

	CActor* victimActor = static_cast<CActor*>(gameFramwork->GetIActorSystem()->GetActor(victimID));
	IVehicle* offenderVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(offenderID);
	IVehicle* victimVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(victimID);
	IActor* offenderActor = gameFramwork->GetIActorSystem()->GetActor(offenderID);

	if(pOffenderEntity && !offenderVehicle && !offenderActor)
	{
		if( IEntity* pParent = pOffenderEntity->GetParent() )
		{
			 offenderVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(pParent->GetId());
		}
	}

	// Vehicles being flipped do no damage, for now
	if (offenderVehicle != NULL && offenderVehicle->GetStatus().beingFlipped)
		return;

	// Players can't damage vehicles
	if (victimVehicle && offenderActor)
		return;

	// Filter frequent collisions
	if (pOffenderEntity)
	{
		FRAME_PROFILER("Filter out recent collisions", gEnv->pSystem, PROFILE_GAME);

		EntityCollisionRecords::const_iterator collisionRecordIter = m_entityCollisionRecords.find(victimID);
		if (collisionRecordIter != m_entityCollisionRecords.end())
		{
			const EntityCollisionRecord& record = collisionRecordIter->second;
			if (record.entityID == offenderID &&
			    record.time + EntityCollisionIgnoreTimeBetweenCollisions > currentTime)
			{
				return;
			}
		}
	}

	float offenderMass = collisionHitInfo.target_mass;

	enum
	{
		CollisionWithEntity,
		CollisionWithStaticWorld
	}
	collisionType = (pOffenderEntity || offenderMass > 0.0f) ? CollisionWithEntity : CollisionWithStaticWorld;

	const Vec3& victimVelocity = collisionHitInfo.velocity;
	const Vec3& offenderVelocity = collisionHitInfo.target_velocity;

	float relativeSpeedSq = 0.0f;
	float minSpeedToCareAboutCollisionSq = 0.0f;
	float contactMass = 0.0f;

	bool offenderIsBig = offenderMass > 1000.f;

	switch (collisionType)
	{
	case CollisionWithEntity:
		{
			Vec3 relativeVelocity = victimVelocity - offenderVelocity;
			relativeSpeedSq = relativeVelocity.GetLengthSquared();

			minSpeedToCareAboutCollisionSq = sqr(10.0f);

			if (victimActor && offenderIsBig)
			{
				minSpeedToCareAboutCollisionSq = sqr(1.0f);
			}

			if (victimActor && offenderVehicle)
			{
				//Players won't be hurt by vehicles with a negative kill player speed
				if(offenderVehicle->GetDamageParams().aiKillPlayerSpeed < 0.f)
				{
					return;
				}

				minSpeedToCareAboutCollisionSq = sqr(2.0f);
			}

			const float offenderSpeedSq = offenderVelocity.GetLengthSquared();
			if (offenderSpeedSq == 0.0f) // -- if collision target it not moving
			{
				minSpeedToCareAboutCollisionSq *= sqr(2.0f);
			}

			//////////////////////////////////////////////////////////////////////////

			contactMass = offenderMass;
			break;
		}

	case CollisionWithStaticWorld:
		{
			// Actors don't take damage from running into walls!
			if (victimActor)
			{
				return;
			}

			relativeSpeedSq = victimVelocity.GetLengthSquared();
			minSpeedToCareAboutCollisionSq = sqr(7.5f);
			contactMass = collisionHitInfo.mass;

			break;
		}
	}

	const bool contactMassIsTooLowToCare = contactMass < 0.01f;
	if (contactMassIsTooLowToCare)
		return;

			
	//////////////////////////////////////////////////////////////////////////
	// Calculate the collision damage
	if (relativeSpeedSq >= minSpeedToCareAboutCollisionSq)
	{
		bool useDefaultCalculation = true;
		float fEnergy = 0.f;
		float damage = 0.f;
		EntityId kickerId = 0;

		// Calculate damage
		if (offenderVehicle && victimActor)
		{
			useDefaultCalculation = false;
			damage = ProcessActorVehicleCollision(victimActor, victimID, offenderVehicle, offenderID, damage, collisionHitInfo, kickerId);
		}
		else if (offenderIsBig && victimActor) // i.e. a kickable car
		{
			// Try to find the kicker
			CTimeValue time = gEnv->pTimer->GetAsyncTime();
			IActorSystem* pActorSystem = gEnv->pGame->GetIGameFramework()->GetIActorSystem();
			IActorIteratorPtr pActorIterator = pActorSystem->CreateActorIterator();
			IActor* pActor = pActorIterator->Next();
			float lowestTime = 5.f;
			while (pActor != NULL)
			{
				CPlayer* pPlayer = static_cast<CPlayer*>(pActor);
				EntityId kicked = pPlayer->GetLargeObjectInteraction().GetLastObjectId();
				if (kicked==offenderID)
				{
					float timeSinceKick = (time - pPlayer->GetLargeObjectInteraction().GetLastObjectTime()).GetSeconds();
					if (timeSinceKick < lowestTime)
					{
						// We found the kicker and the kicked
						kickerId = pActor->GetEntityId();
						lowestTime = timeSinceKick;
					}
				}
				pActor = pActorIterator->Next();
			}
			damage = ProcessActorKickedVehicle(victimActor, victimID, kickerId, offenderID, damage, collisionHitInfo);
			useDefaultCalculation = false;
		}

		if (useDefaultCalculation)
		{
			fEnergy = GetCollisionEnergy(pVictimEntity, collisionHitInfo);
			if (victimVehicle || offenderIsBig)
			{
				damage = 0.0005f * fEnergy;
			}
			else
			{
				damage = 0.0025f * fEnergy;
			}

			// Apply damage multipliers
			damage *= GetCollisionDamageMult(pVictimEntity, pOffenderEntity, collisionHitInfo);

			if (victimActor)
			{
				const bool victimIsPlayer = victimActor->IsPlayer();

				if (victimIsPlayer)
				{
					damage = AdjustPlayerCollisionDamage(pVictimEntity, pOffenderEntity, collisionHitInfo, damage);
				}
			}
		}

		if (damage >= DAMAGE_THRESHOLD_COLLISIONS)
		{
			HitInfo hit;
			hit.damage = damage;
			hit.pos = collisionHitInfo.pos;
			if (collisionHitInfo.target_velocity.GetLengthSquared() > 1e-6)
				hit.dir = collisionHitInfo.target_velocity.GetNormalized();
			hit.radius = 0.0f;
			hit.partId = collisionHitInfo.partId;
			hit.targetId = victimID;
			hit.weaponId = offenderID;
			hit.shooterId = kickerId != 0 ? kickerId : offenderID;
			hit.material = 0;
			hit.type = CGameRules::EHitType::Collision;
			hit.explosion = false;

			CGameRules *pGameRules = g_pGame->GetGameRules();
			if (pGameRules->GetTeamCount() > 1)
			{
				int shooterTeamId = pGameRules->GetTeam(hit.shooterId);
				int targetTeamId = pGameRules->GetTeam(hit.targetId);

				if (shooterTeamId && (shooterTeamId == targetTeamId))
				{
					damage = GetFriendlyFireDamage(damage, hit, victimActor);
				}
			}

			if (damage >= DAMAGE_THRESHOLD_COLLISIONS)
			{
				IScriptTable* pVictimScript = pVictimEntity ? pVictimEntity->GetScriptTable() : NULL;
				IScriptTable* pOffenderScript = pOffenderEntity ? pOffenderEntity->GetScriptTable() : NULL;

				if (!pOffenderEntity && pVictimEntity)
				{
					pOffenderEntity = pVictimEntity;
					offenderID = victimID;
				}

				m_entityCollisionRecords[victimID] = EntityCollisionRecord(offenderID, currentTime);

				if(victimVehicle)
				{
					victimVehicle->OnHit(hit);
				}	
				else if (pVictimScript)
				{
					FRAME_PROFILER("Call to OnHit", gEnv->pSystem, PROFILE_GAME);

					if (!IsDead(victimActor, pVictimScript))
					{
						if (IActor* offenderDriver = offenderVehicle ? offenderVehicle->GetDriver() : NULL)
							hit.shooterId = offenderDriver->GetEntityId();

						DelegateServerHit(pVictimScript, hit, victimActor);
					}
				}
			}
		}
	}
}