Exemple #1
0
bool CHeavyWeapon::AllowInteraction(EntityId interactionEntity, EInteractionType interactionType)
{
    IGameFramework* pGameFramework = g_pGame->GetIGameFramework();
    IVehicleSystem* pVehicleSystem = pGameFramework->GetIVehicleSystem();
    IVehicle* pInteractiveVehicle = pVehicleSystem->GetVehicle(interactionEntity);

    if (pInteractiveVehicle != 0)
        {
            return false;
        }
    else
        {
            return BaseClass::AllowInteraction(interactionEntity, interactionType);
        }
}
CGameRulesCommonDamageHandling::SCollisionEntityInfo::SCollisionEntityInfo( const IEntity* _pEntity )
: pEntity(_pEntity)
, entityId(0)
, pEntityActor(NULL)
, pEntityVehicle(NULL)
{
	if (pEntity)
	{
		entityId = pEntity->GetId();

		IGameFramework* pGameFrameWork = g_pGame->GetIGameFramework();

		pEntityActor = pGameFrameWork->GetIActorSystem()->GetActor(entityId);
		pEntityVehicle = (pEntityActor == NULL) ? pGameFrameWork->GetIVehicleSystem()->GetVehicle(entityId) : NULL;
	}
}
//------------------------------------------------------------------------
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);
					}
				}
			}
		}
	}
}
//
//-----------------------------------------------------------------------------------------------------------
// (MATT) Moved here from Scriptbind_AI when that was moved to the AI system {2008/02/15:15:23:16}
int CScriptBind_Action::RegisterWithAI(IFunctionHandler *pH)
{
	if (gEnv->bMultiplayer && !gEnv->bServer)
		return pH->EndFunction();

	int type;
	ScriptHandle hdl;

	if (!pH->GetParams(hdl, type))
		return pH->EndFunction();

	EntityId entityID = (EntityId)hdl.n;
	IEntity *pEntity = gEnv->pEntitySystem->GetEntity(entityID);

	if(!pEntity)
	{
		GameWarning("RegisterWithAI: Tried to set register with AI nonExisting entity with id [%d]. ", entityID);
		return pH->EndFunction();
	}

	// Apparently we can't assume that there is just one IGameObject to an entity, because we choose between (at least) Actor and Vehicle objects.
	// (MATT) Do we really need to check on the actor system here? {2008/02/15:18:38:34}
	IGameFramework *pGameFramework = gEnv->pGame->GetIGameFramework();
	IVehicleSystem*	pVSystem = pGameFramework->GetIVehicleSystem();
	IActorSystem*	pASystem = pGameFramework->GetIActorSystem();
	if(!pASystem)
	{
		GameWarning("RegisterWithAI: no ActorSystem for %s.", pEntity->GetName());
		return pH->EndFunction();
	}

	AIObjectParams params(type, 0, entityID);
	bool autoDisable(true);

	// For most types, we need to parse the tables
	// For others we leave them blank
	switch (type)
	{
	case AIOBJECT_ACTOR:
	case AIOBJECT_2D_FLY:
	case AIOBJECT_BOAT:
	case AIOBJECT_CAR:
	case AIOBJECT_HELICOPTER:
	
	case AIOBJECT_INFECTED:
	case AIOBJECT_ALIENTICK:
	
	case AIOBJECT_HELICOPTERCRYSIS2:
		if(gEnv->pAISystem && ! gEnv->pAISystem->ParseTables(3, true, pH, params, autoDisable))
			return pH->EndFunction();
	default:;
	}

	// Most types check these, so just get them in advance
	IActor*	pActor = pASystem->GetActor( pEntity->GetId() );

	IVehicle*	pVehicle = NULL;
	if( pVSystem )
		pVehicle = pVSystem->GetVehicle( pEntity->GetId() );

	// Set this if we've found something to create a proxy from
	IGameObject* pGameObject = NULL;

	switch(type)
	{
	case AIOBJECT_ACTOR:
	case AIOBJECT_2D_FLY:
	
	case AIOBJECT_INFECTED:
	case AIOBJECT_ALIENTICK:
	
		{
			// (MATT) The pActor/pVehicle test below - is it basically trying to distiguish between the two cases above? If so, separate them! {2008/02/15:19:38:08}
			if(!pActor)
			{
				GameWarning("RegisterWithAI: no Actor for %s.", pEntity->GetName());
				return pH->EndFunction(); 
			}
			pGameObject = pActor->GetGameObject();
		}
		break;
	case AIOBJECT_BOAT:
	case AIOBJECT_CAR:
		{
			if(!pVehicle)
			{
				GameWarning("RegisterWithAI: no Vehicle for %s (Id %i).", pEntity->GetName(), pEntity->GetId());
				return pH->EndFunction(); 
			}
			pGameObject = pVehicle->GetGameObject();
		}
		break;

	case AIOBJECT_HELICOPTER:
	case AIOBJECT_HELICOPTERCRYSIS2:
		{
			if(!pVehicle)
			{
				GameWarning("RegisterWithAI: no Vehicle for %s (Id %i).", pEntity->GetName(), pEntity->GetId());
				return pH->EndFunction(); 
			}
			pGameObject = pVehicle->GetGameObject();
			params.m_moveAbility.b3DMove = true;
		}
		break;
	case AIOBJECT_PLAYER:
		{
			if(IsDemoPlayback())
				return pH->EndFunction();

			SmartScriptTable pTable;

			if (pH->GetParamCount() > 2)
				pH->GetParam(3,pTable);
			else
				return pH->EndFunction();

			pGameObject = pActor->GetGameObject();

			pTable->GetValue("groupid",params.m_sParamStruct.m_nGroup);       

			const char* faction = 0;
			if (pTable->GetValue("esFaction", faction) && gEnv->pAISystem)
			{
				params.m_sParamStruct.factionID = gEnv->pAISystem->GetFactionMap().GetFactionID(faction);
				if (faction && *faction && (params.m_sParamStruct.factionID == IFactionMap::InvalidFactionID))
				{
					GameWarning("Unknown faction '%s' being set...", faction);
				}
			}
			else
			{
				// Márcio: backwards compatibility
				int species = -1;
				if (!pTable->GetValue("eiSpecies", species))
					pTable->GetValue("species", species);

				if (species > -1)
					params.m_sParamStruct.factionID = species;
			}

			pTable->GetValue("commrange",params.m_sParamStruct.m_fCommRange); //Luciano - added to use GROUPONLY signals

			SmartScriptTable pPerceptionTable;
			if(pTable->GetValue("Perception",pPerceptionTable))
			{
				pPerceptionTable->GetValue( "sightrange", params.m_sParamStruct.m_PerceptionParams.sightRange);
			}
		}
		break;
	case AIOBJECT_SNDSUPRESSOR:
		{
			// (MATT) This doesn't need a proxy? {2008/02/15:19:45:58}
			SmartScriptTable pTable;
			// Properties table
			if (pH->GetParamCount() > 2)
				pH->GetParam(3,pTable);
			else
				return pH->EndFunction();
			if (!pTable->GetValue("radius",params.m_moveAbility.pathRadius))
				params.m_moveAbility.pathRadius = 10.f;
			break;
		}
	case AIOBJECT_WAYPOINT:
		break;
		/*
		// this block is commented out since params.m_sParamStruct is currently ignored in pEntity->RegisterInAISystem()
		// instead of setting the group id here, it will be set from the script right after registering
		default:
		// try to get groupid settings for anchors
		params.m_sParamStruct.m_nGroup = -1;
		params.m_sParamStruct.m_nSpecies = -1;
		{
		SmartScriptTable pTable;
		if ( pH->GetParamCount() > 2 )
		pH->GetParam( 3, pTable );
		if ( *pTable )
		pTable->GetValue( "groupid", params.m_sParamStruct.m_nGroup );
		}
		break;
		*/
	}

	// Remove any existing AI object
	pEntity->RegisterInAISystem(AIObjectParams(0));
 
	// Register in AI to get a new AI object, deregistering the old one in the process
	pEntity->RegisterInAISystem(params);

	// (MATT) ? {2008/02/15:19:46:29}
	// AI object was not created (possibly AI System is disabled)
	if (IAIObject* aiObject = pEntity->GetAI())
	{
		if(type==AIOBJECT_SNDSUPRESSOR)
			aiObject->SetRadius(params.m_moveAbility.pathRadius);
		else if(type>=AIANCHOR_FIRST)	// if anchor - set radius
		{
			SmartScriptTable pTable;
			// Properties table
			if (pH->GetParamCount() > 2)
				pH->GetParam(3,pTable);
			else
				return pH->EndFunction();
			float radius(0.f);
			pTable->GetValue("radius",radius);
			int groupId = -1;
			pTable->GetValue("groupid", groupId);
			aiObject->SetGroupId(groupId);
			aiObject->SetRadius(radius);
		}

		if (IAIActorProxy* proxy = aiObject->GetProxy())
			proxy->UpdateMeAlways(!autoDisable);
	}

	return pH->EndFunction();
}
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);
	}
}