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); } } } }
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; }