void CLagOMeter::OnClientReceivedKill(const CActor::KillParams &killParams) { CTimeValue currentTime = gEnv->pTimer->GetAsyncTime(); if (killParams.shooterId == g_pGame->GetClientActorId()) { // Try to find the corresponding request hit info to see how far lagged behind we are int index = killParams.lagOMeterHitId; if (index > 0 && index < HIT_HISTORY_COUNT) { SHitRequestHistory& item = m_hitHistory[index]; if (item.requestTime.GetValue() != 0) { CTimeValue diff = currentTime - item.requestTime; CTelemetryCollector* pTelemetryCollector = (CTelemetryCollector*)g_pGame->GetITelemetryCollector(); if (pTelemetryCollector) { pTelemetryCollector->LogEvent("Kill Latency", diff.GetMilliSeconds()); } } } } }
void CMPTutorial::ShowMessage(STutorialEvent& event) { assert(event.m_status == eMS_Waiting); // cancel previous sound if necessary if(m_currentEvent.m_pCurrentSound.get()) { m_currentEvent.m_pCurrentSound->Stop(ESoundStopMode_AtOnce); m_currentEvent.m_pCurrentSound = NULL; } // also play the sound here if(gEnv->pSoundSystem && event.m_soundName.compare("None")) { string soundName = "mp_american/" + event.m_soundName; m_currentEvent.m_pCurrentSound = gEnv->pSoundSystem->CreateSound(soundName.c_str(),FLAG_SOUND_VOICE); if (m_currentEvent.m_pCurrentSound.get()) { m_currentEvent.m_pCurrentSound->AddEventListener(this, "mptutorial"); m_currentEvent.m_msgDisplayTime = 1000.0f; // will be removed by sound finish event m_currentEvent.m_pCurrentSound->Play(); m_currentEvent.m_soundLength = m_currentEvent.m_pCurrentSound->GetLengthMs(); // NB this almost certainly returns 0 as the sound isn't buffered yet :( CTimeValue time = gEnv->pTimer->GetFrameStartTime(); m_currentEvent.m_soundStartTime = time.GetMilliSeconds(); } } else { m_currentEvent.m_msgDisplayTime = MESSAGE_DISPLAY_TIME; } // create the localised text string from enum string msg; wstring localizedString; wstring finalString; ILocalizationManager *pLocalizationMan = gEnv->pSystem->GetLocalizationManager(); if(!pLocalizationMan) return; if(m_currentEvent.m_pCurrentSound) { msg = GetSoundKey(m_currentEvent.m_pCurrentSound->GetName()); pLocalizationMan->GetSubtitle(msg.c_str(), localizedString, true); } else { msg = "@mp_Tut" + event.m_name; pLocalizationMan->LocalizeString(msg, localizedString); } if(localizedString.empty()) return; // fill out keynames if necessary if(!strcmp(event.m_name, "BoardVehicle")) { // special case for this event - has 5 actions associated... string action1 = "@cc_"; string action2 = "@cc_"; string action3 = "@cc_"; string action4 = "@cc_"; string action5 = "@cc_"; action1 += GetKeyName("v_changeseat1"); action2 += GetKeyName("v_changeseat2"); action3 += GetKeyName("v_changeseat3"); action4 += GetKeyName("v_changeseat4"); action5 += GetKeyName("v_changeseat5"); wstring wActions[5]; pLocalizationMan->LocalizeString(action1, wActions[0]); pLocalizationMan->LocalizeString(action2, wActions[1]); pLocalizationMan->LocalizeString(action3, wActions[2]); pLocalizationMan->LocalizeString(action4, wActions[3]); pLocalizationMan->LocalizeString(action5, wActions[4]); const wchar_t* params[] = {wActions[0].c_str(), wActions[1].c_str(), wActions[2].c_str(), wActions[3].c_str(), wActions[4].c_str()}; pLocalizationMan->FormatStringMessage(finalString, localizedString, params, 5); } else if(!event.m_action.empty()) { // first get the key name (eg 'mouse1') and make it into a format the localization system understands string action = "@cc_"; action += GetKeyName(event.m_action.c_str()); wstring wActionString; pLocalizationMan->LocalizeString(action, wActionString); // now place this in the right place in the string. pLocalizationMan->FormatStringMessage(finalString, localizedString, wActionString.c_str()); } else { finalString = localizedString; } // split the text into chunks (to allow super-long strings to fit within the window) CreateTextChunks(finalString); // set status event.m_status = eMS_Displaying; // set message removal condition m_currentEvent.m_msgRemovalCondition = event.m_removal; if(!event.m_soundName.compare("None") && m_currentEvent.m_msgRemovalCondition == eMRC_SoundFinished) m_currentEvent.m_msgRemovalCondition = eMRC_Time; // since for now there're some that don't have audio. }
void CMPTutorial::Update() { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if(!m_enabled && g_pGameCVars->g_PSTutorial_Enabled) EnableTutorialMode(true); else if(m_enabled && !g_pGameCVars->g_PSTutorial_Enabled) EnableTutorialMode(false); m_currentEvent.m_msgDisplayTime -= gEnv->pTimer->GetFrameTime(); if(!m_enabled) { if(m_currentEvent.m_msgDisplayTime < 0.0f && m_currentEvent.m_msgRemovalCondition != eMRC_None) { m_currentEvent.m_msgRemovalCondition = eMRC_None; SAFE_HUD_FUNC(ShowTutorialText(NULL,1)); } } // update the text... must be done even if not enabled, to ensure the 'you may reenable...' // message is shown correctly. if(m_currentEvent.m_numChunks > 0) { // calculate how far through the current sound we are CTimeValue now = gEnv->pTimer->GetFrameStartTime(); float soundTimer = now.GetMilliSeconds() - m_currentEvent.m_soundStartTime; assert(soundTimer >= 0); float soundPercent = 1.0f; if(m_currentEvent.m_soundLength == 0.0f && m_currentEvent.m_pCurrentSound.get()) { m_currentEvent.m_soundLength = m_currentEvent.m_pCurrentSound->GetLengthMs(); } if(m_currentEvent.m_soundLength > 0.0f) { soundPercent = soundTimer / m_currentEvent.m_soundLength; } for(int i=m_currentEvent.m_numChunks-1; i > m_currentEvent.m_currentChunk; --i) { if(m_currentEvent.m_chunks[i].m_startPercent <= soundPercent) { m_currentEvent.m_currentChunk = i; int pos = 2; // 2=bottom, 1=middle IActor *pClientActor = g_pGame->GetIGameFramework()->GetClientActor(); if(pClientActor && pClientActor->GetLinkedVehicle()) { pos = 1; } SAFE_HUD_FUNC(ShowTutorialText(m_currentEvent.m_chunks[i].m_text, pos)); break; } } } if(!m_enabled) return; CPlayer* pPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetClientActor()); if(!pPlayer) return; // don't start until game begins if(pPlayer->GetSpectatorMode() != 0 || g_pGame->GetGameRules()->GetCurrentStateId() != 3) return; if(!m_initialised) { m_initialised = true; if(g_pGame->GetHUD()) { // register as a HUD listener g_pGame->GetHUD()->RegisterListener(this); } // go through entity list and pull out the factories. IEntityItPtr pIt = gEnv->pEntitySystem->GetEntityIterator(); while (!pIt->IsEnd()) { if (IEntity * pEnt = pIt->Next()) { if(pEnt->GetClass() == m_pHQClass) { m_baseList.push_back(pEnt->GetId()); //CryLog("Adding HQ %d to list: %d", pEnt->GetId(), m_baseList.size()); } else if(pEnt->GetClass() == m_pAlienEnergyPointClass) { m_alienEnergyPointList.push_back(pEnt->GetId()); //CryLog("Adding AEP %d to list: %d", pEnt->GetId(), m_alienEnergyPointList.size()); } else if(pEnt->GetClass() == m_pSpawnGroupClass) { m_spawnGroupList.push_back(pEnt->GetId()); //CryLog("Adding spawngroup %d to list: %d", pEnt->GetId(), m_spawnGroupList.size()); } else if(pEnt->GetClass() == m_pFactoryClass) { m_factoryList.push_back(pEnt->GetId()); //CryLog("Adding Factory %d to list: %d", pEnt->GetId(), m_factoryList.size()); } } } } // first the briefing events. These are shown in order. bool showPrompt = CheckBriefingEvents(pPlayer); // player has been killed if(pPlayer->GetHealth() <= 0) { showPrompt = TriggerEvent(eTE_Killed); } else if(!showPrompt) { // check each event type here. Which might take a while. // entering a neutral factory // enter prototype factory // enter hostile factory // find alien crash m_entityCheckTimer -= gEnv->pTimer->GetFrameTime(); if(m_entityCheckTimer < 0.0f) { CheckNearbyEntities(pPlayer); m_entityCheckTimer = ENTITY_CHECK_TIME; } // board vehicle and vehicle tutorials CheckVehicles(pPlayer); // player has been wounded if(pPlayer->GetHealth() < pPlayer->GetMaxHealth()) TriggerEvent(eTE_Wounded); // bases m_baseCheckTimer -= gEnv->pTimer->GetFrameTime(); if(m_baseCheckTimer < 0.0f) { CheckBases(pPlayer); m_baseCheckTimer = ENTITY_CHECK_TIME; } } bool promptShown = false; for(int i=0; i<eTE_NumEvents; ++i) { if(m_events[i].m_status == eMS_Waiting) { if(m_currentEvent.m_msgDisplayTime < -MESSAGE_GAP_TIME) { ShowMessage(m_events[i]); } promptShown = true; break; } } if(!promptShown && (m_currentEvent.m_msgRemovalCondition == eMRC_Time) && (m_currentEvent.m_msgDisplayTime < 0.0f)) { HideMessage(); } }
void CFlowDelayNode::Serialize(SActivationInfo *pActInfo, TSerialize ser) { CTimeValue curTime = gEnv->pTimer->GetFrameStartTime(); ser.BeginGroup("Local"); // Editor mode: map with // key: abs time in ms // data: SDelayData // // Game mode: map with // key: timer id (we don't care about it) // data: SDelayData if (ser.IsWriting()) { // when writing, currently relative values are stored! ser.Value("m_activations", m_activations); #if 0 CryLogAlways("CDelayNode write: current time(ms): %f", curTime.GetMilliSeconds()); Activations::iterator iter = m_activations.begin(); while (iter != m_activations.end()) { CryLogAlways("CDelayNode write: ms=%d timevalue(ms): %f",(*iter).first, (*iter).second.m_timeout.GetMilliSeconds()); ++iter; } #endif } else { // FIXME: should we read the curTime from the file // or is the FrameStartTime already set to the serialized value? // ser.Value("curTime", curTime); // when reading we have to differentiate between Editor and Game Mode if (gEnv->IsEditor()) { // we can directly read into the m_activations array // regular update is handled by CFlowGraph ser.Value("m_activations", m_activations); Activations::iterator iter = m_activations.begin(); #if 0 CryLogAlways("CDelayNode read: current time(ms): %f", curTime.GetMilliSeconds()); while (iter != m_activations.end()) { CryLogAlways("CDelayNode read: ms=%d timevalue(ms): %f",(*iter).first, (*iter).second.m_timeout.GetMilliSeconds()); ++iter; } #endif pActInfo->pGraph->SetRegularlyUpdated(pActInfo->myID, !m_activations.empty()); } else { RemovePendingTimers(); // read serialized activations and re-register at timer Activations::iterator iter; Activations activations; ser.Value("m_activations", activations); for (iter = activations.begin(); iter != activations.end(); ++iter) { CTimeValue relTime = (*iter).second.m_timeout - curTime; IGameFramework::TimerID timerId = CCryAction::GetCryAction()->AddTimer( relTime, false, functor(CFlowDelayNode::OnTimer), this ); m_activations[timerId] = (*iter).second; } } } ser.EndGroup(); }
void CFlowDelayNode::ProcessEvent( EFlowEvent event, SActivationInfo * pActInfo ) { switch (event) { case eFE_Initialize: RemovePendingTimers(); pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); break; case eFE_Activate: // we request a final activation if the input value changed // thus in case we get several inputs in ONE frame, we always only use the LAST one! if (IsPortActive(pActInfo, INP_IN)) { pActInfo->pGraph->RequestFinalActivation(pActInfo->myID); } break; case eFE_FinalActivate: { bool shouldReset = GetShouldReset( pActInfo ); if (gEnv->IsEditor()) { if (shouldReset) m_activations.clear(); const float delay = GetDelayTime(pActInfo); CTimeValue finishTime = gEnv->pTimer->GetFrameStartTime() + delay; m_activations[(int)finishTime.GetMilliSeconds()] = SDelayData(finishTime, pActInfo->pInputPorts[0]); pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, true ); } else { if (shouldReset) { for (Activations::iterator iter = m_activations.begin(); iter != m_activations.end(); ++iter) { IGameFramework::TimerID timerId = (*iter).first; CCryAction::GetCryAction()->RemoveTimer( timerId ); } m_activations.clear(); } const float delay = GetDelayTime(pActInfo); CTimeValue finishTime = gEnv->pTimer->GetFrameStartTime() + delay; IGameFramework::TimerID timerId = CCryAction::GetCryAction()->AddTimer( delay, false, functor(CFlowDelayNode::OnTimer), this ); m_activations[timerId] = SDelayData(finishTime, pActInfo->pInputPorts[0]); } break; } case eFE_Update: CRY_ASSERT( gEnv->IsEditor() ); CRY_ASSERT( !m_activations.empty() ); CTimeValue curTime = gEnv->pTimer->GetFrameStartTime(); while (!m_activations.empty() && m_activations.begin()->second.m_timeout < curTime) { ActivateOutput( pActInfo, 0, m_activations.begin()->second.m_data ); m_activations.erase( m_activations.begin() ); } if (m_activations.empty()) pActInfo->pGraph->SetRegularlyUpdated( pActInfo->myID, false ); break; } }