ReGameDLL_CS/regamedll/dlls/bot/cs_bot_init.cpp
Huga a7395b054d
Bot Chatter: Bots will react to enemy snipers presence (#1055)
Friendly fire fixes
Bot Chatter: Bots will react to enemy snipers presence
previously unused chatter on both 1.6 and czero but is used on cs source
Probably fixed where teammate that use sniperrifles looking at bots that don't use sniperrifles got warned
2025-03-28 05:06:17 +07:00

369 lines
11 KiB
C++

/*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#include "precompiled.h"
cvar_t cv_bot_enable = { "bot_enable", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_show_danger = { "bot_show_danger", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_nav_edit = { "bot_nav_edit", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_nav_zdraw = { "bot_nav_zdraw", "4", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_walk = { "bot_walk", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_difficulty = { "bot_difficulty", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_debug = { "bot_debug", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_quicksave = { "bot_quicksave", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_quota = { "bot_quota", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_prefix = { "bot_prefix", "", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_rogues = { "bot_allow_rogues", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_pistols = { "bot_allow_pistols", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_shotguns = { "bot_allow_shotguns", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_sub_machine_guns = { "bot_allow_sub_machine_guns", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_rifles = { "bot_allow_rifles", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_machine_guns = { "bot_allow_machine_guns", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_grenades = { "bot_allow_grenades", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_snipers = { "bot_allow_snipers", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_allow_shield = { "bot_allow_shield", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_join_team = { "bot_join_team", "any", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_join_after_player = { "bot_join_after_player", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_auto_vacate = { "bot_auto_vacate", "1", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_zombie = { "bot_zombie", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_defer_to_human = { "bot_defer_to_human", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_chatter = { "bot_chatter", "normal", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_profile_db = { "bot_profile_db", "BotProfile.db", FCVAR_SERVER, 0.0f, nullptr };
#ifdef REGAMEDLL_ADD
cvar_t cv_bot_deathmatch = { "bot_deathmatch", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_quota_mode = { "bot_quota_mode", "normal", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_join_delay = { "bot_join_delay", "0", FCVAR_SERVER, 0.0f, nullptr };
cvar_t cv_bot_freeze = { "bot_freeze", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_mimic = { "bot_mimic", "0", 0, 0.0f, nullptr };
cvar_t cv_bot_mimic_yaw_offset = { "bot_mimic_yaw_offset", "0", 0, 0.0f, nullptr };
#else
// Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
#endif
void InstallBotControl()
{
if (TheBots)
{
delete TheBots;
}
TheBots = new CCSBotManager;
}
// Engine callback for custom server commands
void Bot_ServerCommand()
{
if (TheBots)
{
const char *pcmd = CMD_ARGV(0);
TheBots->ServerCommand(pcmd);
}
}
void Bot_RegisterCVars()
{
if (!AreBotsAllowed())
return;
CVAR_REGISTER(&cv_bot_traceview);
CVAR_REGISTER(&cv_bot_stop);
CVAR_REGISTER(&cv_bot_show_nav);
CVAR_REGISTER(&cv_bot_show_danger);
CVAR_REGISTER(&cv_bot_nav_edit);
CVAR_REGISTER(&cv_bot_nav_zdraw);
CVAR_REGISTER(&cv_bot_walk);
CVAR_REGISTER(&cv_bot_difficulty);
CVAR_REGISTER(&cv_bot_debug);
CVAR_REGISTER(&cv_bot_quicksave);
CVAR_REGISTER(&cv_bot_quota);
#ifndef REGAMEDLL_ADD
CVAR_REGISTER(&cv_bot_quota_match);
#endif
CVAR_REGISTER(&cv_bot_prefix);
CVAR_REGISTER(&cv_bot_allow_rogues);
CVAR_REGISTER(&cv_bot_allow_pistols);
CVAR_REGISTER(&cv_bot_allow_shotguns);
CVAR_REGISTER(&cv_bot_allow_sub_machine_guns);
CVAR_REGISTER(&cv_bot_allow_rifles);
CVAR_REGISTER(&cv_bot_allow_machine_guns);
CVAR_REGISTER(&cv_bot_allow_grenades);
CVAR_REGISTER(&cv_bot_allow_snipers);
CVAR_REGISTER(&cv_bot_allow_shield);
CVAR_REGISTER(&cv_bot_join_team);
CVAR_REGISTER(&cv_bot_join_after_player);
CVAR_REGISTER(&cv_bot_auto_vacate);
CVAR_REGISTER(&cv_bot_zombie);
CVAR_REGISTER(&cv_bot_defer_to_human);
CVAR_REGISTER(&cv_bot_chatter);
CVAR_REGISTER(&cv_bot_profile_db);
#ifdef REGAMEDLL_ADD
CVAR_REGISTER(&cv_bot_deathmatch);
CVAR_REGISTER(&cv_bot_quota_mode);
CVAR_REGISTER(&cv_bot_join_delay);
CVAR_REGISTER(&cv_bot_freeze);
CVAR_REGISTER(&cv_bot_mimic);
CVAR_REGISTER(&cv_bot_mimic_yaw_offset);
#endif
}
// Constructor
CCSBot::CCSBot() : m_gameState(this), m_chatter(this)
{
;
}
// Prepare bot for action
bool CCSBot::Initialize(const BotProfile *profile)
{
// extend
CBot::Initialize(profile);
// CS bot initialization
m_diedLastRound = false;
m_morale = POSITIVE; // starting a new round makes everyone a little happy
m_combatRange = RANDOM_FLOAT(325, 425);
m_navNodeList = nullptr;
m_currentNode = nullptr;
// set initial safe time guess for this map
m_safeTime = 15.0f + 5.0f * GetProfile()->GetAggression();
m_name[0] = '\0';
ResetValues();
StartNormalProcess();
return true;
}
// Reset internal data to initial state
void CCSBot::ResetValues()
{
m_chatter.Reset();
m_gameState.Reset();
m_avoid = nullptr;
m_avoidTimestamp = 0.0f;
m_hurryTimer.Invalidate();
m_isStuck = false;
m_stuckTimestamp = 0.0f;
m_wiggleTimestamp = 0.0f;
m_stuckJumpTimestamp = 0.0f;
m_pathLength = 0;
m_pathIndex = 0;
m_areaEnteredTimestamp = 0.0f;
m_currentArea = nullptr;
m_lastKnownArea = nullptr;
#ifdef REGAMEDLL_ADD
m_isEnemySniperVisible = false;
m_sawEnemySniperTimer.Invalidate();
#endif
m_avoidFriendTimer.Invalidate();
m_isFriendInTheWay = false;
m_isWaitingBehindFriend = false;
m_disposition = ENGAGE_AND_INVESTIGATE;
m_enemy = nullptr;
m_isWaitingToTossGrenade = false;
m_wasSafe = true;
m_nearbyEnemyCount = 0;
m_enemyPlace = 0;
m_nearbyFriendCount = 0;
m_closestVisibleFriend = nullptr;
m_closestVisibleHumanFriend = nullptr;
for (int w = 0; w < ARRAYSIZE(m_watchInfo); w++)
{
m_watchInfo[w].timestamp = 0.0f;
m_watchInfo[w].isEnemy = false;
}
m_isEnemyVisible = false;
m_visibleEnemyParts = NONE;
m_lastSawEnemyTimestamp = 0.0f;
m_firstSawEnemyTimestamp = 0.0f;
m_currentEnemyAcquireTimestamp = 0.0f;
m_isLastEnemyDead = true;
m_attacker = nullptr;
m_attackedTimestamp = 0.0f;
m_enemyDeathTimestamp = 0.0f;
m_lastVictimID = 0;
m_isAimingAtEnemy = false;
m_fireWeaponTimestamp = 0.0f;
m_equipTimer.Invalidate();
m_isFollowing = false;
m_leader = nullptr;
m_followTimestamp = 0.0f;
m_allowAutoFollowTime = 0.0f;
m_enemyQueueIndex = 0;
m_enemyQueueCount = 0;
m_enemyQueueAttendIndex = 0;
m_bomber = nullptr;
m_lookAroundStateTimestamp = 0.0f;
m_inhibitLookAroundTimestamp = 0.0f;
m_lookPitch = 0.0f;
m_lookPitchVel = 0.0f;
m_lookYaw = 0.0f;
m_lookYawVel = 0.0f;
m_aimOffsetTimestamp = 0.0f;
m_aimSpreadTimestamp = 0.0f;
m_lookAtSpotState = NOT_LOOKING_AT_SPOT;
m_spotEncounter = nullptr;
m_spotCheckTimestamp = 0.0f;
m_peripheralTimestamp = 0.0f;
m_avgVelIndex = 0;
m_avgVelCount = 0;
m_lastOrigin = pev ? pev->origin : Vector(0, 0, 0);
m_lastRadioCommand = EVENT_INVALID;
m_lastRadioRecievedTimestamp = 0.0f;
m_lastRadioSentTimestamp = 0.0f;
m_radioSubject = nullptr;
m_voiceFeedbackEndTimestamp = 0.0f;
m_hostageEscortCount = 0;
m_hostageEscortCountTimestamp = 0.0f;
m_noisePosition = Vector(0, 0, 0);
m_noiseTimestamp = 0.0f;
m_noiseCheckTimestamp = 0.0f;
m_isNoiseTravelRangeChecked = false;
m_stateTimestamp = 0.0f;
m_task = SEEK_AND_DESTROY;
m_taskEntity = nullptr;
m_approachPointCount = 0;
m_approachPointViewPosition = Vector(0, 0, 0);
m_checkedHidingSpotCount = 0;
m_isJumpCrouching = false;
StandUp();
Run();
m_mustRunTimer.Invalidate();
m_repathTimer.Invalidate();
m_pathLadder = nullptr;
m_huntState.ClearHuntArea();
// adjust morale - if we died, our morale decreased,
// but if we live, no adjustement (round win/loss also adjusts morale
if (m_diedLastRound)
DecreaseMorale();
m_diedLastRound = false;
// IsRogue() randomly changes this
m_isRogue = false;
m_surpriseDelay = 0.0f;
m_surpriseTimestamp = 0.0f;
// even though these are EHANDLEs, they need to be NULL-ed
m_goalEntity = nullptr;
m_avoid = nullptr;
m_enemy = nullptr;
#ifdef REGAMEDLL_FIXES
for (int i = 0; i < MAX_ENEMY_QUEUE; i++)
{
m_enemyQueue[i].player = nullptr;
m_enemyQueue[i].isReloading = false;
m_enemyQueue[i].isProtectedByShield = false;
}
#endif
// start in idle state
StopAttacking();
Idle();
}
// Called when bot is placed in map, and when bots are reset after a round ends.
// NOTE: For some reason, this can be called twice when a bot is added.
void CCSBot::SpawnBot()
{
TheCSBots()->ValidateMapData();
ResetValues();
Q_strlcpy(m_name, STRING(pev->netname));
SetState(&m_buyState);
SetTouch(&CCSBot::BotTouch);
if (TheNavAreaList.empty() && !TheCSBots()->IsLearningMap())
{
TheCSBots()->SetLearningMapFlag();
StartLearnProcess();
}
}
void CCSBot::RoundRespawn()
{
// do the normal player spawn process
CBasePlayer::RoundRespawn();
EndVoiceFeedback();
}
void CCSBot::Disconnect()
{
EndVoiceFeedback();
if (m_processMode != PROCESS_NORMAL)
{
hideProgressMeter();
}
}