//-------------------------------------------------------------------------
void CGameRulesObjectiveVictoryConditionsTeam::Update( float frameTime )
{
	IGameRulesStateModule *pStateModule = m_pGameRules->GetStateModule();
	if (pStateModule != NULL && pStateModule->GetGameState() != IGameRulesStateModule::EGRS_InGame)
	{
		return;
	}

	IGameRulesRoundsModule* pRoundsModule=m_pGameRules->GetRoundsModule();
	if (pRoundsModule != NULL && !pRoundsModule->IsInProgress())
	{
		return;
	}

	CGameRulesStandardVictoryConditionsTeam::UpdateTimeLimitSounds();

	if (!gEnv->bServer)
	{
		return;
	}
	
	DebugDrawResolutions();

	SvCheckOpponents();

	if (!CheckObjectives())		// Check objectives first, if the game isn't over then check the time limit
	{
		CheckTimeLimit();
	}
}
void CGameRulesMPActorAction::OnActorAction(IActor *pActor, const ActionId& actionId, int activationMode, float value)
{
	CActor *pActorImpl = static_cast<CActor *>(pActor);
	if (pActorImpl)
	{
		EntityId  pid = pActor->GetEntityId();  // player id

		CGameRules *pGameRules = g_pGame->GetGameRules();
		IGameRulesSpectatorModule *specmod = pGameRules->GetSpectatorModule();

		if (!specmod || (pActorImpl->GetSpectatorMode() <= 0))
		{
			// Not in spectator mode

			if (pActorImpl->IsDead())
			{
				// if dead 

				CRecordingSystem *crs = g_pGame->GetRecordingSystem();

				if (crs != NULL && crs->IsPlayingBack())
				{
					// Recording system playing back 
					if (actionId == g_pGame->Actions().spectate_gen_skipdeathcam && g_pGameCVars->kc_canSkip )
						crs->StopPlayback();
				}
				else if ((actionId == g_pGame->Actions().spectate_gen_spawn || actionId == g_pGame->Actions().hud_mouseclick) && activationMode == eAAM_OnPress && pActorImpl->GetSpectatorState() != CActor::eASS_SpectatorMode)
				{
					// Revive requested.
					//	This may happen immediately or not at all.

					if (IGameRulesSpawningModule* pSpawningModule=pGameRules->GetSpawningModule())
					{
						IGameRulesStateModule*  stateModule = pGameRules->GetStateModule();
						if (!stateModule || (stateModule->GetGameState() != IGameRulesStateModule::EGRS_PostGame))
						{
							CryLog("CGameRulesMPActorAction::OnActorAction() Requesting revive");
							pSpawningModule->ClRequestRevive(pActor->GetEntityId());
						}
					}
				}
				else if ((specmod != NULL && specmod->CanChangeSpectatorMode(pid)) && (((actionId == g_pGame->Actions().spectate_gen_nextmode) || (actionId == g_pGame->Actions().spectate_gen_prevmode)) && (activationMode == eAAM_OnPress)))  
				{
					// get into spectate mode
					if (!crs || !crs->IsPlayingOrQueued())
					{
						specmod->ChangeSpectatorModeBestAvailable(pActor, false);
					}
				}
			}
		}
		else
		{
			// is spectating

			int  curspecmode = pActorImpl->GetSpectatorMode();
			int  curspecstate = pActorImpl->GetSpectatorState();

			const CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem();
			// actions general across almost all spectator modes
			if( (curspecmode == CActor::eASM_Killer && !g_pGameCVars->g_killercam_canSkip) || (pRecordingSystem && pRecordingSystem->IsPlayingBack()) )
			{
				// Can't change mode or respawn-request, when in KillerCam mode or watching Killcam.
			}
			else if ((actionId == g_pGame->Actions().spectate_gen_spawn) && (activationMode == eAAM_OnPress) && pActorImpl->GetSpectatorState() != CActor::eASS_SpectatorMode)
			{
				IGameRulesSpawningModule *pSpawningModule = pGameRules->GetSpawningModule();
				if (pSpawningModule)
				{
					IGameRulesStateModule*  stateModule = pGameRules->GetStateModule();
					if (!stateModule || (stateModule->GetGameState() != IGameRulesStateModule::EGRS_PostGame))
					{
						CryLog("CGameRulesMPActorAction::OnActorAction() Spectating, received spectate_gen_spawn action, requesting revive");
						pSpawningModule->ClRequestRevive(pActor->GetEntityId());
					}			
				}			
			}
			else if (((actionId == g_pGame->Actions().spectate_gen_nextmode) || (actionId == g_pGame->Actions().spectate_gen_prevmode)) && (activationMode == eAAM_OnPress))
			{
				CryLog("[tlh] > changemode button pressed");
				if (specmod->CanChangeSpectatorMode(pid))
				{
					CryLog("[tlh] > can change");
					int  mode;
					EntityId  othEntId;
					mode = specmod->GetNextMode(pid, ((actionId == g_pGame->Actions().spectate_gen_nextmode) ? 1 : -1), &othEntId);
					if (mode != curspecmode)
					{
						CryLog("[tlh] > changing to mode %d with othEnt %d",mode,othEntId);
						specmod->ChangeSpectatorMode(pActor, mode, othEntId, false);
					}
				}
			}
			else
			{
				// actions specific to individual spectator modes

				if (specmod->CanChangeSpectatorMode(pid))  // "CanChangeSpectatorMode?" is essentially "CanInteractWithSpectatorMode?" - ie. we don't want to be able to do any of this on the Join Game screen
				{
					if (curspecmode == CActor::eASM_Fixed)
					{
						int  changeCam = 0;

						if (((actionId == g_pGame->Actions().spectate_cctv_nextcam) || (actionId == g_pGame->Actions().spectate_cctv_prevcam)) && (activationMode == eAAM_OnPress))
						{
							changeCam = (actionId == g_pGame->Actions().spectate_cctv_nextcam ? 1 : -1);
						}
						else if (actionId == g_pGame->Actions().spectate_cctv_changecam_xi)
						{
							if (value >= 1.f)
							{
								changeCam = 1;
							}
							else if (value <= -1.f)
							{
								changeCam = -1;
							}
						}

						if (changeCam != 0)
						{
							EntityId  locationId;

							if (changeCam > 0)
							{
								locationId = specmod->GetNextSpectatorLocation(pActorImpl);
							}
							else
							{
								locationId = specmod->GetPrevSpectatorLocation(pActorImpl);
							}

							pActorImpl->SetSpectatorFixedLocation(locationId);
						}
					}
					else if (curspecmode == CActor::eASM_Free)
					{
						;  // none
					}
					else if (curspecmode == CActor::eASM_Follow)
					{
						int  change = 0;

						const CGameActions& actions = g_pGame->Actions();

						if (((actionId == actions.spectate_3rdperson_nextteammate) || (actionId == actions.spectate_3rdperson_prevteammate)) && (activationMode == eAAM_OnPress))
						{
							change = ((actionId == actions.spectate_3rdperson_nextteammate) ? 1 : -1);
						}
						else if (actionId == actions.spectate_3rdperson_changeteammate_xi)
						{
							if (value >= 1.f)
							{
								change = 1;
							}
							else if (value <= -1.f)
							{
								change = -1;
							}
						}
						else if(actionId == actions.xi_rotateyaw && pActorImpl->CanSpectatorOrbitYaw())
						{
							pActorImpl->SetSpectatorOrbitYawSpeed(fabs(value) > 0.2f ? value : 0.f, false);
						}
						else if(actionId == actions.rotateyaw && pActorImpl->CanSpectatorOrbitYaw())
						{
							pActorImpl->SetSpectatorOrbitYawSpeed(value * g_pGameCVars->g_spectate_follow_orbitMouseSpeedMultiplier, true);
						}
						else if(actionId == actions.xi_rotatepitch && pActorImpl->CanSpectatorOrbitPitch())
						{
							float val = fabs(value) > 0.2f ? value : 0.f;
							if(val && g_pGameCVars->cl_invertController)
							{
								val = -value;
							}
							pActorImpl->SetSpectatorOrbitPitchSpeed(val, false);
						}
						else if(actionId == actions.rotatepitch && pActorImpl->CanSpectatorOrbitPitch())
						{
							float val = fabs(value) > 0.2f ? value : 0.f;
							if(val && g_pGameCVars->cl_invertMouse)
							{
								val = -val;
							}
							pActorImpl->SetSpectatorOrbitPitchSpeed(val * g_pGameCVars->g_spectate_follow_orbitMouseSpeedMultiplier, true);
						}
						else if(actionId == actions.spectate_gen_nextcamera)
						{
							pActorImpl->ChangeCurrentFollowCameraSettings(true);
						}

						if (change != 0)
						{
							if (EntityId newTargetId=specmod->GetNextSpectatorTarget(pid, change))
							{
								pActorImpl->SetSpectatorTarget(newTargetId);
							}
						}
					}
					else if (curspecmode == CActor::eASM_Killer)
					{
						;  // none
					}
				}
			}
		}

		pGameRules->ActorActionInformOnAction(actionId, activationMode, value);
	}
}
Ejemplo n.º 3
0
//------------------------------------------------------------------------
// returns true if entity is killed, false if it is not
bool CGameRulesMPDamageHandling::SvOnHit( const HitInfo &hitInfo )
{
	const HitTypeInfo * pHitTypeInfo = m_pGameRules->GetHitTypeInfo(hitInfo.type);

#if !defined(_RELEASE)
	if(!pHitTypeInfo)
		CryFatalError("By ::SvOnHit() all hit info should have a hit type that is valid and registered in the GameRules. This isn't true of type %d!", hitInfo.type);
#endif

	SDamageHandling damageHandling(&hitInfo, 1.0f);

	float damage = hitInfo.damage;

	IActorSystem* pActorSystem = g_pGame->GetIGameFramework()->GetIActorSystem();
	CActor *pTargetActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.targetId));
	CActor *pShooterActor = static_cast<CActor*>(pActorSystem->GetActor(hitInfo.shooterId));
	CPlayer* pShooterPlayer = (pShooterActor && pShooterActor->IsPlayer()) ? static_cast<CPlayer*>(pShooterActor) : NULL ;

	bool isPlayer = pTargetActor != NULL && pTargetActor->IsPlayer();

#ifndef _RELEASE
	//--- Fix to allow the damage handling to work for these entity classes in the same way as for Players
	static IEntityClass* sDamEntClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("DamageTestEnt");
	isPlayer |= pTargetActor != NULL && pTargetActor->GetEntity()->GetClass() == sDamEntClass;
#endif

	CPlayer* pPlayer = isPlayer ? static_cast<CPlayer*>(pTargetActor) : NULL;
	const bool isMelee = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IsMeleeAttack) != 0);
	const bool checkHeadshots = ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::IgnoreHeadshots) == 0);

	bool bIsHeadShot = false;
	if(pPlayer && hitInfo.partId >= 0 && checkHeadshots)
	{
		bIsHeadShot = pPlayer->IsHeadShot(hitInfo);

		if (!bIsHeadShot && g_pGameCVars->g_mpHeadshotsOnly)
		{
			damage = 0.f;
		}
	}

	//If the player has died more than kTimeToAllowKillsAfterDeath seconds ago, we disallow any damage they apply, unless the hit type is flagged as allowing it.
	static const float kTimeToAllowKillsAfterDeath = 0.05f;
	if(pTargetActor && pShooterPlayer && !hitInfo.hitViaProxy
		&& ((pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::AllowPostDeathDamage) == 0) && pShooterActor->IsDead()
		&& (gEnv->pTimer->GetFrameStartTime().GetSeconds() - pShooterPlayer->GetDeathTime()) > kTimeToAllowKillsAfterDeath)
	{
		damage = 0.0f;
	}

	IGameRulesStateModule *stateModule = m_pGameRules->GetStateModule();
	IGameRulesRoundsModule* pRoundsModule = m_pGameRules->GetRoundsModule();

	if ( (stateModule != NULL && (stateModule->GetGameState() == IGameRulesStateModule::EGRS_PostGame)) || 
		   (pRoundsModule!= NULL && !pRoundsModule->IsInProgress() ))
	{
		// No damage allowed once the game has ended, except in cases where it would cause graphical glitches
		if (hitInfo.type != CGameRules::EHitType::PunishFall)
		{
			damage = 0.0f;
		}
	}

	IEntity *pTarget = gEnv->pEntitySystem->GetEntity(hitInfo.targetId);

#if defined(SERVER_CHECKS)

	if(damage != 0.0f)
	{
		int nNewCheckCounter = m_checkCounter + 1;
		
		if (CItem *pItem = static_cast<CItem *>(g_pGame->GetIGameFramework()->GetIItemSystem()->GetItem(hitInfo.weaponId)))
		{
			if(CWeapon * pWeapon = static_cast<CWeapon*>(pItem->GetIWeapon()))
			{
				int nFireModeFromShotId = GetFireModeFromShotId(hitInfo.shotId);

				static const int kCheckFreq = 7;

				if(pShooterActor &&	nNewCheckCounter == kCheckFreq)
				{
					float fDamageAtXMeters = 0.0f;

					float fDistance2D, fDistanceMax, fNetLagSeconds;
					CServerCheatMonitor::GetHitValidationInfo(*pShooterActor, hitInfo, fDistance2D, fDistanceMax, fNetLagSeconds);

					bool bDoDamageValidation = false;

					if(isMelee)
					{
						if(CMelee * pMelee = pWeapon->GetMelee())
						{
							//This check can't be used for everything because the default firemode returns '0.f' for range and only CMelee extends it
							//	the horizontal player speed is x 2.0f as the players could have potentially immediately turned and run away from each other
							float fMeleeRangeError = fDistance2D - (pMelee->GetRange() + (CServerCheatMonitor::kMaxHorizontalPlayerSpeed * fNetLagSeconds * 2.0f));
							if(fMeleeRangeError > 0.1f)
							{
								g_pGame->GetAntiCheatManager()->FlagActivity(eCT_MeleeRange, pShooterActor->GetChannelId(), fMeleeRangeError);
							}

							fDamageAtXMeters = pMelee->GetDamageAmountAtXMeters(fDistance2D);

							bDoDamageValidation = true;
						}
					}
					else
					{
						//////////////////////////////////////////////////////////////////////
						// Verify that the hit is from a valid shot

						DoShotValidation(hitInfo, pHitTypeInfo, pShooterActor);

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


						CFireMode * pFireMode = static_cast<CFireMode*>(pWeapon->GetFireMode(nFireModeFromShotId));

						if(pFireMode)
						{
							const SFireModeParams * pParams = pFireMode->GetShared();

							char projectileClassName[128];
							g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId);
							IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(projectileClassName);

							if((pProjectileClass && (pProjectileClass == pParams->fireparams.ammo_type_class ||	pProjectileClass == pParams->plantparams.ammo_type_class)))
							{
								float fBulletSpeed = 100.f;
								const SAmmoParams * pAmmoParams = g_pGame->GetWeaponSystem()->GetAmmoParams(pFireMode->GetAmmoType());
								if(pAmmoParams)
								{
									fBulletSpeed = pAmmoParams->speed;
								}

								//Might have been closer when the shot was fired
								const float fMaxTimeSinceShot	= ((fDistanceMax / fBulletSpeed) * 2.0f) + fNetLagSeconds; //Should be less than this. Laaaaarge fudge factor
								float fDistance_Conservative	= fDistance2D - (fMaxTimeSinceShot * CServerCheatMonitor::kMaxHorizontalPlayerSpeed);

								fDamageAtXMeters = pFireMode->GetDamageAmountAtXMeters(fDistance_Conservative); 
							}
						}
						else if(pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired)
						{
							CryStackStringT<char, 256> invalidFireModeMessage;
							invalidFireModeMessage.Format("Invalid fire mode, weapon: '%s', firemode: %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
							g_pGame->GetAntiCheatManager()->FlagActivity(eCT_ValidHitInfo, pShooterActor->GetChannelId(), invalidFireModeMessage.c_str());
						}
					}

					float fDamageFromWeapon = hitInfo.damage;			

					if(fDamageFromWeapon > fDamageAtXMeters && fDamageAtXMeters > 0.0f)
					{
						//Log the ratio of actual damage to expected damage, e.g. 1.2 x expected
						CryStackStringT<char, 256> excessiveDamageMessage;
						excessiveDamageMessage.Format("Weapon '%s', firemode %d", pWeapon->GetEntity()->GetName(), nFireModeFromShotId);
						g_pGame->GetAntiCheatManager()->FlagActivity(eCT_WeaponDamage, pShooterActor->GetChannelId(), fDamageFromWeapon / fDamageAtXMeters, excessiveDamageMessage.c_str());
					}


					if(pTargetActor)
					{
						CServerCheatMonitor::ValidateTargetActorPositionAgainstHit(*pTargetActor, hitInfo, fNetLagSeconds);
					}
					
					nNewCheckCounter = 0;
				}
				else
				{
					nNewCheckCounter = kCheckFreq - 1;
				}
			}
		}
		m_checkCounter = nNewCheckCounter;
	}

	// Update the shotcounter for tracking headshots and traversal times
	if(pShooterPlayer && (pHitTypeInfo->m_flags & CGameRules::EHitTypeFlag::ValidationRequired))
	{
		char netName[128];
		g_pGame->GetIGameFramework()->GetNetworkSafeClassName(netName, sizeof(netName), hitInfo.projectileClassId);
		IEntityClass * pProjectileClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass(netName);
		if (pProjectileClass)
		{
			CShotCounter* pShotCounter = pShooterPlayer->GetShotCounter();
			pShotCounter->RecordHit(hitInfo, bIsHeadShot);
		}
	}
	
#endif // SERVER_CHECKS

	IEntityClass* pTargetClass = pTarget ? pTarget->GetClass() : NULL;

	// Check for friendly fire
	if( bool bCheckFriendlyFire = ((hitInfo.targetId!=hitInfo.shooterId) && (hitInfo.type!=CGameRules::EHitType::EventDamage)) )
	{
		if(IVehicle* pTargetVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(hitInfo.targetId))
		{
			if(IActor* pDriverTargetVehicle = pTargetVehicle->GetDriver())
			{
				// Vehicle driver shot own vehicle (same as shooting yourself), don't do friendly fire.
				bCheckFriendlyFire = pDriverTargetVehicle->GetEntityId()!=hitInfo.shooterId;
			}
		}
		if(bCheckFriendlyFire)
		{
			if (m_pGameRules->GetTeamCount() > 1)
			{
				int shooterTeamId = m_pGameRules->GetTeam(hitInfo.shooterId);
				int targetTeamId = m_pGameRules->GetTeam(hitInfo.targetId);

				if (shooterTeamId && (shooterTeamId == targetTeamId))
				{
					damage = GetFriendlyFireDamage(damage, hitInfo, pTargetActor);
				}
			}
		}
	}

	if (damage <= 0.f)
	{
		// If the hit isn't doing anything bail, this means any hit that gets past here has damage associated with it and thus wants to
		// display a hit indicator
		return false;
	}

	if (pPlayer)
	{
		if(hitInfo.partId >= 0 && !isMelee)
		{
			damageHandling.damageMultiplier *= pPlayer->GetBodyDamageMultiplier(hitInfo);
		}

		if (isMelee)
		{
			damageHandling.damageMultiplier *= g_pGameCVars->pl_melee.damage_multiplier_mp;
		}
	}

	damage *= damageHandling.damageMultiplier;

	HitInfo hitInfoWithDamage = hitInfo;
	hitInfoWithDamage.damage = damage;

	if(pPlayer)
	{
		SActorStats* pStats = pPlayer->GetActorStats();
		float actorHealth = pPlayer->GetHealth();

		if(pStats)
		{
#ifndef _RELEASE
			if (g_pGameCVars->g_LogDamage)
			{
				char weaponClassName[64], projectileClassName[64];

				CryLog ("[DAMAGE] %s '%s' took %.3f '%s' damage (%.3f x %.3f) weapon=%s projectile=%s",
						pPlayer->GetEntity()->GetClass()->GetName(), pPlayer->GetEntity()->GetName(),
						damage, m_pGameRules->GetHitType(hitInfo.type),
						hitInfo.damage, damageHandling.damageMultiplier,
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(weaponClassName, sizeof(weaponClassName), hitInfo.weaponClassId) ? weaponClassName : "none",
						g_pGame->GetIGameFramework()->GetNetworkSafeClassName(projectileClassName, sizeof(projectileClassName), hitInfo.projectileClassId) ? projectileClassName : "none");
			}
#endif

			if(pStats->bStealthKilling && actorHealth <= damage)
			{
				if(pPlayer->GetStealthKill().GetTargetId() != hitInfoWithDamage.shooterId)
				{
					pPlayer->StoreDelayedKillingHitInfo(hitInfoWithDamage);
				}
				
				hitInfoWithDamage.damage = 0;
			}
			else if (pStats->bStealthKilled && hitInfoWithDamage.type != CGameRules::EHitType::StealthKill)
			{
				hitInfoWithDamage.damage = 0;
			}
		}
	}
		
	bool bKilled = SvOnHitScaled(hitInfoWithDamage);

	return bKilled;
}