#include "precompiled.h" /* * Globals initialization */ #ifndef HOOK_GAMEDLL CCareerTaskManager *TheCareerTasks = NULL; const TaskInfo taskInfo[] = { { "defuse", EVENT_BOMB_DEFUSED, &CCareerTask::NewTask }, { "plant", EVENT_BOMB_PLANTED, &CCareerTask::NewTask }, { "rescue", EVENT_HOSTAGE_RESCUED, &CCareerTask::NewTask }, { "killall", EVENT_KILL_ALL, &CCareerTask::NewTask }, { "kill", EVENT_KILL, &CCareerTask::NewTask }, { "killwith", EVENT_KILL, &CCareerTask::NewTask }, { "killblind", EVENT_KILL_FLASHBANGED, &CCareerTask::NewTask }, { "killvip", EVENT_KILL, &CCareerTask::NewTask }, { "headshot", EVENT_HEADSHOT, &CCareerTask::NewTask }, { "headshotwith", EVENT_HEADSHOT, &CCareerTask::NewTask }, { "winfast", EVENT_ROUND_WIN, &CCareerTask::NewTask }, { "rescue", EVENT_HOSTAGE_RESCUED, &CCareerTask::NewTask }, { "rescueall", EVENT_ALL_HOSTAGES_RESCUED, &CCareerTask::NewTask }, { "injure", EVENT_PLAYER_TOOK_DAMAGE, &CCareerTask::NewTask }, { "injurewith", EVENT_PLAYER_TOOK_DAMAGE, &CCareerTask::NewTask }, { "killdefuser", EVENT_KILL, &CCareerTask::NewTask }, { "stoprescue", EVENT_KILL, &CCareerTask::NewTask }, { "defendhostages", EVENT_ROUND_WIN, &CCareerTask::NewTask }, { "hostagessurvive", EVENT_ROUND_WIN, &CCareerTask::NewTask }, { "preventdefuse", EVENT_ROUND_WIN, &CPreventDefuseTask::NewTask }, { NULL, EVENT_INVALID, &CCareerTask::NewTask } }; #endif CCareerTask *CPreventDefuseTask::NewTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete) { CPreventDefuseTask *pNewTask = new CPreventDefuseTask(taskName, event, weaponName, n, mustLive, crossRounds, id, isComplete); pNewTask->m_bombPlantedThisRound = false; pNewTask->m_defuseStartedThisRound = false; return reinterpret_cast(pNewTask); } CPreventDefuseTask::CPreventDefuseTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete) { CCareerTask(taskName, event, weaponName, n, mustLive, crossRounds, id, isComplete); m_bombPlantedThisRound = false; m_defuseStartedThisRound = false; } void CPreventDefuseTask::__MAKE_VHOOK(Reset)() { m_bombPlantedThisRound = false; m_defuseStartedThisRound = false; CCareerTask::Reset(); } void CPreventDefuseTask::__MAKE_VHOOK(OnEvent)(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim) { if (IsComplete()) return; if (event == EVENT_BOMB_PLANTED) { m_bombPlantedThisRound = true; } else if (event == EVENT_BOMB_DEFUSING) { m_defuseStartedThisRound = true; } CCareerTask::OnEvent(event, pAttacker, pVictim); if (event >= EVENT_ROUND_DRAW && event <= EVENT_ROUND_LOSS) { m_bombPlantedThisRound = false; m_defuseStartedThisRound = false; } } CCareerTask *CCareerTask::NewTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete) { CCareerTask *pTask = new CCareerTask(taskName, event, weaponName, n, mustLive, crossRounds, id, isComplete); return pTask; } CCareerTask::CCareerTask(const char *taskName, GameEventType event, const char *weaponName, int n, bool mustLive, bool crossRounds, int id, bool isComplete) { m_isComplete = isComplete; m_event = event; m_eventsNeeded = n; m_name = taskName; m_eventsSeen = 0; m_mustLive = mustLive; m_crossRounds = crossRounds; m_diedThisRound = false; m_id = id; m_weaponId = AliasToWeaponID(weaponName); m_weaponClassId = AliasToWeaponClass(weaponName); m_rescuer = (Q_stricmp(taskName, "stoprescue") == 0); m_defuser = (Q_stricmp(taskName, "killdefuser") == 0); m_vip = (Q_stricmp(taskName, "killvip") == 0); if (event == EVENT_ALL_HOSTAGES_RESCUED) { m_mustLive = true; m_crossRounds = false; } if (m_isComplete) { MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKDONE"); WRITE_BYTE(m_id); MESSAGE_END(); } } void CCareerTask::__MAKE_VHOOK(Reset)() { m_eventsSeen = 0; m_isComplete = false; MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKUNDONE"); WRITE_BYTE(m_id); MESSAGE_END(); MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKPART"); WRITE_BYTE(m_id); WRITE_SHORT(m_eventsSeen); MESSAGE_END(); } void CCareerTask::SendPartialNotification() { MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKPART"); WRITE_BYTE(m_id); WRITE_SHORT(m_eventsSeen); MESSAGE_END(); UTIL_LogPrintf("Career Task Partial %d %d\n", m_id, m_eventsSeen); } void CCareerTask::OnWeaponKill(int weaponId, int weaponClassId, bool headshot, bool killerHasShield, CBasePlayer *pAttacker, CBasePlayer *pVictim) { if (m_isComplete || (m_event != EVENT_KILL && (m_event != EVENT_HEADSHOT || !headshot))) return; if (!pVictim || (m_defuser && !pVictim->m_bIsDefusing) || (m_vip && !pVictim->m_bIsVIP)) return; if (m_rescuer) { int hostages_ = 0; CBaseEntity *hostageEntity = NULL; while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL) { if (hostageEntity->pev->takedamage != DAMAGE_YES) continue; CHostage *hostage = static_cast(hostageEntity); if (!hostage->IsFollowingSomeone()) continue; if (hostage->IsValid() && hostage->m_target == pVictim) ++hostages_; } if (!hostages_) return; } if (m_weaponId == WEAPON_SHIELDGUN) { if (!killerHasShield) return; } else if (m_weaponId) { if (m_weaponId != weaponId) return; } else { if (!m_weaponClassId || m_weaponClassId != weaponClassId) return; } ++m_eventsSeen; SendPartialNotification(); } void CCareerTask::OnWeaponInjury(int weaponId, int weaponClassId, bool attackerHasShield, CBasePlayer *pAttacker) { if (m_isComplete || m_event != EVENT_PLAYER_TOOK_DAMAGE) return; if (m_weaponId == WEAPON_SHIELDGUN) { if (!attackerHasShield) return; } else if (m_weaponId) { if (m_weaponId != weaponId) return; } else { if (!m_weaponClassId || m_weaponClassId != weaponClassId) return; } ++m_eventsSeen; SendPartialNotification(); } void CCareerTask::__MAKE_VHOOK(OnEvent)(GameEventType event, CBasePlayer *pVictim, CBasePlayer *pAttacker) { if (m_isComplete) return; if (event == m_event) { if ((m_defuser && !pAttacker->m_bIsDefusing) || (m_vip && !pAttacker->m_bIsVIP)) return; if (m_rescuer) { int hostages_ = 0; CBaseEntity *hostageEntity = NULL; while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL) { if (hostageEntity->pev->takedamage != DAMAGE_YES) continue; CHostage *hostage = static_cast(hostageEntity); if (!hostage->IsFollowingSomeone()) continue; if (hostage->IsValid() && hostage->m_target == pAttacker) ++hostages_; } if (!hostages_) { return; } } if ((m_event != EVENT_KILL || (!m_weaponId && !m_weaponClassId)) && (m_event != EVENT_HEADSHOT || (!m_weaponId && !m_weaponClassId)) && (m_event != EVENT_PLAYER_TOOK_DAMAGE || (!m_weaponId && !m_weaponClassId))) { if (m_event == EVENT_ROUND_WIN) { if (!Q_strcmp(m_name, "defendhostages")) { int hostages_ = 0; CBaseEntity *hostageEntity = NULL; while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL) { if (hostageEntity->pev->takedamage != 1.0f && hostageEntity->pev->deadflag != DEAD_DEAD) ++hostages_; } if (!hostages_) { ++m_eventsSeen; SendPartialNotification(); } } else if (!Q_strcmp(m_name, "hostagessurvive")) { int hostages_ = 0; CBaseEntity *hostageEntity = NULL; while ((hostageEntity = UTIL_FindEntityByClassname(hostageEntity, "hostage_entity")) != NULL) { CHostage *hostage = (CHostage *)hostageEntity; if (hostage && hostage->IsDead()) ++hostages_; } if (!hostages_) { ++m_eventsSeen; SendPartialNotification(); } } else if (!Q_strcmp(m_name, "winfast")) { if (m_eventsNeeded >= TheCareerTasks->GetRoundElapsedTime()) { m_eventsSeen = m_eventsNeeded; SendPartialNotification(); } } else if (IsTaskCompletableThisRound()) { ++m_eventsSeen; SendPartialNotification(); } } else { ++m_eventsSeen; SendPartialNotification(); } } } if (event == m_event && !m_mustLive && m_eventsSeen >= m_eventsNeeded && IsTaskCompletableThisRound()) { CBasePlayer *player = UTIL_GetLocalPlayer(); EMIT_SOUND(ENT(player->pev), CHAN_VOICE, "events/task_complete.wav", VOL_NORM, ATTN_NORM); m_isComplete = true; MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKDONE"); WRITE_BYTE(m_id); MESSAGE_END(); if (TheTutor != NULL) { TheTutor->OnEvent(EVENT_CAREER_TASK_DONE); } UTIL_LogPrintf("Career Task Done %d\n", m_id); if (m_event == EVENT_ROUND_WIN && !Q_strcmp(m_name, "winfast")) { TheCareerTasks->SetFinishedTaskTime(int(TheCareerTasks->GetRoundElapsedTime())); UTIL_GetLocalPlayer()->SyncRoundTimer(); } } else if (event >= EVENT_ROUND_DRAW) { if (event > EVENT_ROUND_LOSS) { if (event == EVENT_DIE && (m_mustLive || m_crossRounds)) { m_eventsSeen = 0; SendPartialNotification(); m_diedThisRound = true; } } else if (m_mustLive) { if (m_eventsSeen >= m_eventsNeeded && !m_diedThisRound && IsTaskCompletableThisRound()) { CBasePlayer *player = UTIL_GetLocalPlayer(); EMIT_SOUND(ENT(player->pev), CHAN_VOICE, "events/task_complete.wav", VOL_NORM, ATTN_NORM); m_isComplete = true; MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKDONE"); WRITE_BYTE(m_id); MESSAGE_END(); UTIL_LogPrintf("Career Task Done %d\n", m_id); if (m_event == EVENT_ROUND_WIN && !Q_strcmp(m_name, "winfast")) { TheCareerTasks->SetFinishedTaskTime(int(TheCareerTasks->GetRoundElapsedTime())); UTIL_GetLocalPlayer()->SyncRoundTimer(); } if (TheTutor != NULL) { TheTutor->OnEvent(EVENT_CAREER_TASK_DONE); } } m_diedThisRound = false; if (m_mustLive) { m_eventsSeen = 0; SendPartialNotification(); } } } } void CCareerTaskManager::Create() { if (TheCareerTasks != NULL) { TheCareerTasks->Reset(); return; } TheCareerTasks = new CCareerTaskManager; } CCareerTaskManager::CCareerTaskManager() { m_taskTime = 0; Reset(); } void CCareerTaskManager::Reset(bool deleteTasks) { if (deleteTasks) { for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) delete (*it); m_tasks.clear(); m_nextId = 0; } else { for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { CCareerTask *pTask = (*it); pTask->Reset(); } } m_finishedTaskTime = 0; m_finishedTaskRound = 0; m_shouldLatchRoundEndMessage = false; m_roundStartTime = gpGlobals->time + CVAR_GET_FLOAT("mp_freezetime"); } void CCareerTaskManager::SetFinishedTaskTime(int val) { m_finishedTaskTime = val; m_finishedTaskRound = CSGameRules()->m_iTotalRoundsPlayed; } void CCareerTaskManager::AddTask(const char *taskName, const char *weaponName, int eventCount, bool mustLive, bool crossRounds, bool isComplete) { ++m_nextId; for (int i = 0; i < ARRAYSIZE(taskInfo); ++i) { const TaskInfo *pTaskInfo = &taskInfo[ i ]; if (pTaskInfo->taskName != NULL) { if (!Q_stricmp(pTaskInfo->taskName, taskName)) { CCareerTask *newTask = pTaskInfo->factory ( pTaskInfo->taskName, pTaskInfo->event, weaponName, eventCount, mustLive, crossRounds, m_nextId, isComplete ); m_tasks.push_back(newTask); if (pTaskInfo->event == EVENT_ROUND_WIN && !Q_strcmp(taskName, "winfast")) { m_taskTime = eventCount; if (isComplete) { m_finishedTaskTime = eventCount; } } return; } } } MESSAGE_BEGIN(MSG_ALL, gmsgCZCareer); WRITE_STRING("TASKDONE"); WRITE_BYTE(m_nextId); MESSAGE_END(); } void CCareerTaskManager::HandleEvent(GameEventType event, CBasePlayer *pAttacker, CBasePlayer *pVictim) { if (event == EVENT_ROUND_START) { m_roundStartTime = gpGlobals->time; return; } if ((event <= EVENT_ROUND_LOSS && event >= EVENT_ROUND_DRAW) && m_shouldLatchRoundEndMessage) { m_roundEndMessage = event; return; } for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { (*it)->OnEvent(event, pAttacker, pVictim); } } void CCareerTaskManager::HandleWeaponKill(int weaponId, int weaponClassId, bool headshot, bool killerHasShield, CBasePlayer *pAttacker, CBasePlayer *pVictim) { for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { (*it)->OnWeaponKill(weaponId, weaponClassId, headshot, killerHasShield, pAttacker, pVictim); } } void CCareerTaskManager::HandleEnemyKill(bool wasBlind, const char *weaponName, bool headshot, bool killerHasShield, CBasePlayer *pAttacker, CBasePlayer *pVictim) { HandleWeaponKill(AliasToWeaponID(weaponName), AliasToWeaponClass(weaponName), headshot, killerHasShield, pAttacker, pVictim); HandleEvent(EVENT_KILL, pAttacker, pVictim); if (headshot) { HandleEvent(EVENT_HEADSHOT, pAttacker, pVictim); } if (wasBlind) { HandleEvent(EVENT_KILL_FLASHBANGED, pAttacker, pVictim); } } void CCareerTaskManager::HandleWeaponInjury(int weaponId, int weaponClassId, bool attackerHasShield, CBasePlayer *pAttacker) { for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { (*it)->OnWeaponInjury(weaponId, weaponClassId, attackerHasShield, pAttacker); } } void CCareerTaskManager::HandleEnemyInjury(const char *weaponName, bool attackerHasShield, CBasePlayer *pAttacker) { HandleWeaponInjury(AliasToWeaponID(weaponName), AliasToWeaponClass(weaponName), attackerHasShield, pAttacker); HandleEvent(EVENT_PLAYER_TOOK_DAMAGE); } void CCareerTaskManager::HandleDeath(int team, CBasePlayer *pAttacker) { int enemyTeam = (Q_strcmp(humans_join_team.string, "CT") != 0) ? CT : TERRORIST; int numEnemies = 0; if (enemyTeam != team) return; for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); if (pPlayer && pPlayer->m_iTeam == enemyTeam && pPlayer->IsAlive()) ++numEnemies; } if (!numEnemies) { HandleEvent(EVENT_KILL_ALL); } } bool CCareerTaskManager::AreAllTasksComplete() { for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { if (!(*it)->IsComplete()) return false; } return true; } int CCareerTaskManager::GetNumRemainingTasks() { int ret = 0; for (CareerTaskListIt it = m_tasks.begin(); it != m_tasks.end(); ++it) { if (!(*it)->IsComplete()) ++ret; } return ret; } float CCareerTaskManager::GetRoundElapsedTime() { return (gpGlobals->time - m_roundStartTime); } void CCareerTaskManager::LatchRoundEndMessage() { m_shouldLatchRoundEndMessage = true; } void CCareerTaskManager::UnlatchRoundEndMessage() { m_shouldLatchRoundEndMessage = false; HandleEvent(m_roundEndMessage); }