#include "precompiled.h" CBaseTutor *TheTutor = nullptr; TutorMessageEvent::TutorMessageEvent(int mid, int duplicateID, float time, float lifetime, int priority) { m_messageID = mid; m_duplicateID = duplicateID; m_activationTime = time; m_lifetime = lifetime; m_priority = priority; m_paramList = nullptr; m_numParameters = 0; m_next = nullptr; } TutorMessageEvent::~TutorMessageEvent() { ; } bool TutorMessageEvent::IsActive(float time) { return (m_lifetime + m_activationTime >= time); } int TutorMessageEvent::GetPriority() { return m_priority; } float TutorMessageEvent::GetTimeActive(float time) { return (time - m_activationTime); } void TutorMessageEvent::SetActivationTime(float time) { m_activationTime = time; } int TutorMessageEvent::GetID() { return m_messageID; } int TutorMessageEvent::GetDuplicateID() { return m_duplicateID; } void TutorMessageEvent::SetNext(TutorMessageEvent *next) { m_next = next; } TutorMessageEvent *TutorMessageEvent::GetNext() { return m_next; } void TutorMessageEvent::AddParameter(char *str) { if (str == nullptr) return; TutorMessageEventParam *param = new TutorMessageEventParam; param->m_next = nullptr; param->m_data = new char[Q_strlen(str) + 1]; if (param->m_data) { Q_strcpy(param->m_data, str); param->m_data[Q_strlen(str)] = '\0'; m_numParameters++; if (m_paramList) { TutorMessageEventParam *temp = m_paramList; while (temp->m_next) temp = temp->m_next; temp->m_next = param; } else m_paramList = param; } } char *TutorMessageEvent::GetNextParameter(char *buf, int buflen) { TutorMessageEventParam *param = m_paramList; if (!param) { return nullptr; } m_numParameters--; m_paramList = param->m_next; Q_strncpy(buf, param->m_data, buflen); #ifdef REGAMEDLL_FIXES buf[buflen] = '\0'; #endif delete param; return buf; } int TutorMessageEvent::GetNumParameters() { return m_numParameters; } CBaseTutor::CBaseTutor() { m_eventList = nullptr; m_deadAirStartTime = 0; m_roundStartTime = 0; } CBaseTutor::~CBaseTutor() { TutorMessageEvent *event = m_eventList; while (event) { TutorMessageEvent *temp = event; event = event->GetNext(); delete temp; } } void CBaseTutor::OnEvent(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOther) { CallEventHandler(event, pEntity, pOther); CheckForStateTransition(event, pEntity, pOther); } void CBaseTutor::ShotFired(Vector source, Vector target) { HandleShotFired(source, target); } void CBaseTutor::CheckForStateTransition(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOther) { if (m_stateSystem->UpdateState(event, pEntity, pOther)) { DisplayNewStateDescriptionToPlayer(); } } void CBaseTutor::StartFrame(float time) { TutorThink(time); } void CBaseTutor::DisplayMessageToPlayer(CBasePlayer *pPlayer, int id, const char *szMessage, TutorMessageEvent *event) { TutorMessage *definition; int numArgs; char param[512]; numArgs = event->GetNumParameters(); definition = GetTutorMessageDefinition(event->GetID()); MESSAGE_BEGIN(MSG_ONE, gmsgTutorText, nullptr, pPlayer->pev); WRITE_STRING(szMessage); WRITE_BYTE(numArgs); for (int arg = 0; arg < numArgs; arg++) { char *str = event->GetNextParameter(param, sizeof(param)); if (str) WRITE_STRING(str); else WRITE_STRING(""); } WRITE_SHORT(id); WRITE_SHORT(pPlayer->IsAlive() == FALSE); if (definition) WRITE_SHORT(definition->m_type); else WRITE_SHORT(TUTORMESSAGETYPE_DEFAULT); MESSAGE_END(); m_deadAirStartTime = -1.0f; if (definition) { if (gpGlobals->time - m_roundStartTime > 1.0f) { switch (definition->m_type) { case TUTORMESSAGETYPE_FRIEND_DEATH: EMIT_SOUND_DYN(ENT(pPlayer->pev), CHAN_ITEM, "events/friend_died.wav", VOL_NORM, ATTN_NORM, 0, 120); break; case TUTORMESSAGETYPE_ENEMY_DEATH: EMIT_SOUND_DYN(ENT(pPlayer->pev), CHAN_ITEM, "events/enemy_died.wav", VOL_NORM, ATTN_NORM, 0, 85); break; default: EMIT_SOUND_DYN(ENT(pPlayer->pev), CHAN_ITEM, "events/tutor_msg.wav", VOL_NORM, ATTN_NORM, 0, 100); break; } } if (definition->m_decay) { REGISTER_TUTOR_MESSAGE_SHOWN(id); } } } NOXREF void CBaseTutor::DrawLineToEntity(CBasePlayer *pPlayer, int entindex, int id) { MESSAGE_BEGIN(MSG_ONE, gmsgTutorLine, nullptr, pPlayer->pev); WRITE_SHORT(entindex); WRITE_SHORT(id); MESSAGE_END(); } void CBaseTutor::DisplayNewStateDescriptionToPlayer() { CBasePlayer *pLocalPlayer = UTIL_GetLocalPlayer(); if (!pLocalPlayer) { return; } auto desc = m_stateSystem->GetCurrentStateString(); if (!desc) { MESSAGE_BEGIN(MSG_ONE, gmsgTutorState, nullptr, pLocalPlayer->pev); WRITE_STRING(nullptr); MESSAGE_END(); } } void CBaseTutor::CloseCurrentWindow() { CBasePlayer *pLocalPlayer = UTIL_GetLocalPlayer(); if (pLocalPlayer) { MESSAGE_BEGIN(MSG_ONE, gmsgTutorClose, nullptr, pLocalPlayer->pev); MESSAGE_END(); m_deadAirStartTime = gpGlobals->time; } } void CBaseTutor::CalculatePathForObjective(CBaseEntity *pPlayer) { ; } bool CBaseTutor::IsEntityInViewOfPlayer(CBaseEntity *pEntity, CBasePlayer *pPlayer) { if (!pEntity || !pPlayer) return false; if (cv_tutor_view_distance.value < (pEntity->pev->origin - pPlayer->pev->origin).Length()) return false; if (pPlayer->FInViewCone(pEntity)) { TraceResult result; Vector eye = pPlayer->pev->view_ofs + pPlayer->pev->origin; UTIL_TraceLine(eye, pEntity->pev->origin, ignore_monsters, ignore_glass, pPlayer->pev->pContainingEntity, &result); if (result.flFraction == 1.0f) { return true; } } return false; } bool CBaseTutor::IsPlayerLookingAtPosition(Vector *origin, CBasePlayer *pPlayer) { if (!origin || !pPlayer) return false; if (cv_tutor_look_distance.value < (*origin - pPlayer->pev->origin).Length()) return false; if (pPlayer->IsLookingAtPosition(origin, cv_tutor_look_angle.value)) { TraceResult result; Vector eye = pPlayer->pev->origin + pPlayer->pev->view_ofs; UTIL_TraceLine(eye, *origin, ignore_monsters, ignore_glass, ENT(pPlayer->pev), &result); if (result.flFraction == 1.0f) return true; } return false; } bool CBaseTutor::IsPlayerLookingAtEntity(CBaseEntity *pEntity, CBasePlayer *pPlayer) { if (!pEntity || !pPlayer) return false; UTIL_MakeVectors(pPlayer->pev->v_angle); Vector srcVec = pPlayer->pev->view_ofs + pPlayer->pev->origin; Vector destVec = gpGlobals->v_forward * cv_tutor_look_distance.value + srcVec; TraceResult result; UTIL_TraceLine(srcVec, destVec, dont_ignore_monsters, ignore_glass, ENT(pPlayer->pev), &result); if (result.pHit) { if (!FNullEnt(result.pHit) && CBaseEntity::Instance(result.pHit) == pEntity) { return true; } } return false; } bool CBaseTutor::IsBombsiteInViewOfPlayer(CBaseEntity *pEntity, CBasePlayer *pPlayer) { if (!pEntity || !pPlayer) return false; Vector bombSiteCenter = pEntity->Center(); if (cv_tutor_view_distance.value < (bombSiteCenter - pPlayer->pev->origin).Length()) return false; if (pPlayer->FInViewCone(pEntity)) { TraceResult result; Vector eye = pPlayer->pev->origin + pPlayer->pev->view_ofs; UTIL_TraceLine(eye, bombSiteCenter, ignore_monsters, ignore_glass, ENT(pPlayer->pev), &result); if (result.flFraction == 1.0f) { return true; } } return false; } bool CBaseTutor::IsEntityInBombsite(CBaseEntity *bombsite, CBaseEntity *pEntity) { if (!bombsite || !pEntity) return false; return bombsite->Intersects(pEntity); } bool CBaseTutor::DoMessagesHaveSameID(int id1, int id2) { if (id1 == id2) return true; TutorMessage *message1 = GetTutorMessageDefinition(id1); TutorMessage *message2 = GetTutorMessageDefinition(id2); if (!message1 || !message2) return false; if (message1->m_duplicateID && message2->m_duplicateID) return true; return false; }