Ejemplo n.º 1
0
void CVTOLVehicleManager::Update(float frameTime)
{
	// Update logic goes here
	if(CGameRules* pGameRules = g_pGame->GetGameRules())
	{
		CGameRules::TPlayers players;
		pGameRules->GetPlayers(players);

		for (TVTOLList::iterator iter=m_vtolList.begin(), end=m_vtolList.end(); iter!=end; ++iter)
		{
			SVTOLInfo& info = iter->second;
			IVehicle* pVehicle = m_pVehicleSystem->GetVehicle( info.entityId );
			if(pVehicle)
			{
				info.stateTime += frameTime;

				// Find difference in rotation
				Quat newRotation = pVehicle->GetEntity()->GetWorldRotation();
				newRotation.Normalize();
				Quat rotationDifference = newRotation*info.location.q.GetInverted();
				rotationDifference.Normalize();

				// Store new rotation + position
				info.location.q = newRotation;
				info.location.t = pVehicle->GetEntity()->GetWorldPos();

				if(info.state==EVS_Normal)
				{
					pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics);

					if(CVehicleMovementMPVTOL* pMovement = static_cast<CVehicleMovementMPVTOL*>(pVehicle->GetMovement()))
					{
						const uint8 pathComplete = pMovement->GetPathComplete();
						if(pathComplete==1)
						{
							if(CMPPathFollowingManager* pMPPathFollowingManager = g_pGame->GetGameRules()->GetMPPathFollowingManager())
							{
								pMPPathFollowingManager->NotifyListenersOfPathCompletion(info.entityId);
							}
							pMovement->SetPathCompleteNotified();
						}
					}
				}

				// Check status
				if(info.state==EVS_Normal && pVehicle->GetDamageRatio() >= 1.f)
				{
					if(gEnv->bServer)
					{
						DestructionDamageRatioReached(pVehicle, info, frameTime);
					}
				}
				else if(info.state == EVS_Invisible)
				{
					if(info.stateTime > g_pGameCVars->g_VTOLRespawnTime)
					{
						RespawnVTOL(pVehicle, info);
					}
				}

				//Process players
				TPlayerList& currentPlayerList = info.playersInside;
				TPlayerList oldPlayerList = currentPlayerList;
				currentPlayerList.clear();

				CGameRules::TPlayers::iterator iterPlayer = players.begin();
				const CGameRules::TPlayers::const_iterator endPlayer = players.end();
				while(iterPlayer != endPlayer)
				{
					// Adding safeguard to protect against cases where user alt-f4 quits program. 
					UpdateEntityInVTOL(info, *iterPlayer); 
					++iterPlayer;
				}
				
				//Find out who has been inside since the last update, who has just entered, and who has left
				TPlayerStatusList playerStatusList;
				int currentId;
				for(unsigned int prev = 0; prev < currentPlayerList.size(); ++prev)
				{
					currentId = currentPlayerList[prev];
					bool found = false;
					TPlayerList::iterator oldIter = oldPlayerList.begin();
					TPlayerList::iterator oldEnd = oldPlayerList.end();
					while(oldIter != oldEnd)
					{
						if(currentId == *oldIter) //In both lists so still inside
						{
							found = true;
							playerStatusList.push_back( TPlayerStatus(currentId, E_PEVS_StillInside) );
							oldPlayerList.erase(oldIter);
							break;
						}
						++oldIter;
					}
					if(!found) //Only in current list so entered
					{
						playerStatusList.push_back( TPlayerStatus(currentId, E_PEVS_Entered) );
					}
				}
				//Those remaining in old list have exited
				for(unsigned int old = 0; old < oldPlayerList.size(); ++old) 
				{
					playerStatusList.push_back( TPlayerStatus(oldPlayerList[old], E_PEVS_Exited) );
				}

				//Act based on current state
				TPlayerStatusList::iterator statusIter = playerStatusList.begin();
				TPlayerStatusList::iterator statusEnd = playerStatusList.end();
				while(statusIter != statusEnd)
				{
					switch(statusIter->second)
					{
					case E_PEVS_Entered:
						{
							OnPlayerEntered(statusIter->first);
						}
						break;
					case E_PEVS_Exited:
						{
							OnPlayerExited(statusIter->first);
						}
						break;
					}
					++statusIter;
				}

				UpdateRotationOfInternalPlayers(info, playerStatusList, rotationDifference);
			}
		}
	}
}
Ejemplo n.º 2
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;
}