#include "precompiled.h" /* * Globals initialization */ #ifndef HOOK_GAMEDLL // 30 times per second, just like human clients float g_flBotCommandInterval = 1.0 / 30.0; // full AI only 10 times per second float g_flBotFullThinkInterval = 1.0 / 10.0; // Nasty Hack. See client.cpp/ClientCommand() const char *BotArgs[4] = { NULL }; bool UseBotArgs = false; #else // HOOK_GAMEDLL float g_flBotCommandInterval; float g_flBotFullThinkInterval; const char *BotArgs[4]; bool UseBotArgs; #endif // HOOK_GAMEDLL /* <48fed0> ../game_shared/bot/bot.cpp:28 */ CBot::CBot(void) { // the profile will be attached after this instance is constructed m_profile = NULL; // assign this bot a unique ID static unsigned int nextID = 1; // wraparound (highly unlikely) if (nextID == 0) ++nextID; m_id = nextID++; m_postureStackIndex = 0; } // Prepare bot for action /* <48f6ef> ../game_shared/bot/bot.cpp:50 */ bool CBot::__MAKE_VHOOK(Initialize)(const BotProfile *profile) { m_profile = profile; return true; } /* <48fbbd> ../game_shared/bot/bot.cpp:57 */ void CBot::__MAKE_VHOOK(Spawn)(void) { // Let CBasePlayer set some things up CBasePlayer::Spawn(); // Make sure everyone knows we are a bot pev->flags |= (FL_CLIENT | FL_FAKECLIENT); // Bots use their own thinking mechanism SetThink(NULL); pev->nextthink = -1; m_flNextBotThink = gpGlobals->time + g_flBotCommandInterval; m_flNextFullBotThink = gpGlobals->time + g_flBotFullThinkInterval; m_flPreviousCommandTime = gpGlobals->time; m_isRunning = true; m_isCrouching = false; m_postureStackIndex = 0; m_jumpTimestamp = 0.0f; // Command interface variable initialization ResetCommand(); // Allow derived classes to setup at spawn time SpawnBot(); } /* <48fa37> ../game_shared/bot/bot.cpp:88 */ Vector CBot::__MAKE_VHOOK(GetAutoaimVector)(float flDelta) { UTIL_MakeVectors(pev->v_angle + pev->punchangle); return gpGlobals->v_forward; } /* <48ffa8> ../game_shared/bot/bot.cpp:97 */ void CBot::BotThink(void) { if (gpGlobals->time >= m_flNextBotThink) { m_flNextBotThink = gpGlobals->time + g_flBotCommandInterval; Upkeep(); if (gpGlobals->time >= m_flNextFullBotThink) { m_flNextFullBotThink = gpGlobals->time + g_flBotFullThinkInterval; ResetCommand(); Update(); } ExecuteCommand(); } } /* <48f723> ../game_shared/bot/bot.cpp:119 */ void CBot::__MAKE_VHOOK(MoveForward)(void) { m_forwardSpeed = GetMoveSpeed(); m_buttonFlags |= IN_FORWARD; // make mutually exclusive m_buttonFlags &= ~IN_BACK; } /* <48f761> ../game_shared/bot/bot.cpp:130 */ void CBot::__MAKE_VHOOK(MoveBackward)(void) { m_forwardSpeed = -GetMoveSpeed(); m_buttonFlags |= IN_BACK; // make mutually exclusive m_buttonFlags &= ~IN_FORWARD; } /* <48f79f> ../game_shared/bot/bot.cpp:140 */ void CBot::__MAKE_VHOOK(StrafeLeft)(void) { m_strafeSpeed = -GetMoveSpeed(); m_buttonFlags |= IN_MOVELEFT; // make mutually exclusive m_buttonFlags &= ~IN_MOVERIGHT; } /* <48f7dd> ../game_shared/bot/bot.cpp:150 */ void CBot::__MAKE_VHOOK(StrafeRight)(void) { m_strafeSpeed = GetMoveSpeed(); m_buttonFlags |= IN_MOVERIGHT; // make mutually exclusive m_buttonFlags &= ~IN_MOVELEFT; } /* <48fe00> ../game_shared/bot/bot.cpp:160 */ bool CBot::__MAKE_VHOOK(Jump)(bool mustJump) { if (IsJumping() || IsCrouching()) return false; if (!mustJump) { const float minJumpInterval = 0.9f; // 1.5f; if (gpGlobals->time - m_jumpTimestamp < minJumpInterval) return false; } // still need sanity check for jumping frequency const float sanityInterval = 0.3f; if (gpGlobals->time - m_jumpTimestamp < sanityInterval) return false; // jump m_buttonFlags |= IN_JUMP; m_jumpTimestamp = gpGlobals->time; return true; } // Zero any MoveForward(), Jump(), etc /* <48f81b> ../game_shared/bot/bot.cpp:187 */ void CBot::__MAKE_VHOOK(ClearMovement)(void) { ResetCommand(); } // Returns true if we are in the midst of a jump /* <48ffe7> ../game_shared/bot/bot.cpp:196 */ bool CBot::IsJumping(void) { // if long time after last jump, we can't be jumping if (gpGlobals->time - m_jumpTimestamp > 3.0f) return false; // if we just jumped, we're still jumping if (gpGlobals->time - m_jumpTimestamp < 1.0f) return true; // a little after our jump, we're jumping until we hit the ground if (pev->flags & FL_ONGROUND) return false; return true; } /* <48f859> ../game_shared/bot/bot.cpp:214 */ void CBot::__MAKE_VHOOK(Crouch)(void) { m_isCrouching = true; } /* <48f87f> ../game_shared/bot/bot.cpp:220 */ void CBot::__MAKE_VHOOK(StandUp)(void) { m_isCrouching = false; } /* <48f8a5> ../game_shared/bot/bot.cpp:227 */ void CBot::__MAKE_VHOOK(UseEnvironment)(void) { m_buttonFlags |= IN_USE; } /* <48f8cb> ../game_shared/bot/bot.cpp:234 */ void CBot::__MAKE_VHOOK(PrimaryAttack)(void) { m_buttonFlags |= IN_ATTACK; } /* <48f8f1> ../game_shared/bot/bot.cpp:240 */ void CBot::__MAKE_VHOOK(ClearPrimaryAttack)(void) { m_buttonFlags &= ~IN_ATTACK; } /* <48f917> ../game_shared/bot/bot.cpp:246 */ void CBot::__MAKE_VHOOK(TogglePrimaryAttack)(void) { if (m_buttonFlags & IN_ATTACK) m_buttonFlags &= ~IN_ATTACK; else m_buttonFlags |= IN_ATTACK; } /* <48f93d> ../game_shared/bot/bot.cpp:260 */ void CBot::__MAKE_VHOOK(SecondaryAttack)(void) { m_buttonFlags |= IN_ATTACK2; } /* <48f963> ../game_shared/bot/bot.cpp:266 */ void CBot::__MAKE_VHOOK(Reload)(void) { m_buttonFlags |= IN_RELOAD; } // Returns ratio of ammo left to max ammo (1 = full clip, 0 = empty) /* <490008> ../game_shared/bot/bot.cpp:275 */ float CBot::GetActiveWeaponAmmoRatio(void) const { CBasePlayerWeapon *weapon = GetActiveWeapon(); if (!weapon) return 0.0f; // weapons with no ammo are always full if (weapon->m_iClip < 0) return 1.0f; return (float)weapon->m_iClip / (float)weapon->iMaxClip(); } // Return true if active weapon has an empty clip /* <490058> ../game_shared/bot/bot.cpp:293 */ bool CBot::IsActiveWeaponClipEmpty(void) const { CBasePlayerWeapon *weapon = GetActiveWeapon(); if (weapon != NULL && weapon->m_iClip == 0) return true; return false; } // Return true if active weapon has no ammo at all /* <490096> ../game_shared/bot/bot.cpp:307 */ bool CBot::IsActiveWeaponOutOfAmmo(void) const { CBasePlayerWeapon *gun = GetActiveWeapon(); if (gun == NULL) return true; if (gun->m_iClip < 0) return false; if (gun->m_iClip == 0 && m_rgAmmo[ gun->m_iPrimaryAmmoType ] <= 0) return true; return false; } // Return true if looking thru weapon's scope /* <4900d4> ../game_shared/bot/bot.cpp:327 */ bool CBot::IsUsingScope(void) const { // if our field of view is less than 90, we're looking thru a scope (maybe only true for CS...) if (m_iFOV < 90.0f) return true; return false; } /* <48f989> ../game_shared/bot/bot.cpp:338 */ void CBot::__MAKE_VHOOK(ExecuteCommand)(void) { byte adjustedMSec; // Adjust msec to command time interval adjustedMSec = ThrottledMsec(); // player model is "munged" pev->angles = pev->v_angle; pev->angles.x /= -3.0f; // save the command time m_flPreviousCommandTime = gpGlobals->time; if (IsCrouching()) { m_buttonFlags |= IN_DUCK; } // Run the command PLAYER_RUN_MOVE(edict(), pev->v_angle, m_forwardSpeed, m_strafeSpeed, m_verticalSpeed, m_buttonFlags, 0, adjustedMSec); } /* <4900fa> ../game_shared/bot/bot.cpp:362 */ void CBot::ResetCommand(void) { m_forwardSpeed = 0.0f; m_strafeSpeed = 0.0f; m_verticalSpeed = 0.0f; m_buttonFlags = 0; } /* <49011b> ../game_shared/bot/bot.cpp:372 */ byte CBot::ThrottledMsec(void) const { int iNewMsec; // Estimate Msec to use for this command based on time passed from the previous command iNewMsec = (int)((gpGlobals->time - m_flPreviousCommandTime) * 1000); // Doh, bots are going to be slower than they should if this happens. // Upgrade that CPU or use less bots! if (iNewMsec > 255) iNewMsec = 255; return (byte)iNewMsec; } // Do a "client command" - useful for invoking menu choices, etc. /* <49016e> ../game_shared/bot/bot.cpp:389 */ void CBot::ClientCommand(const char *cmd, const char *arg1, const char *arg2, const char *arg3) { BotArgs[0] = cmd; BotArgs[1] = arg1; BotArgs[2] = arg2; BotArgs[3] = arg3; UseBotArgs = true; ::ClientCommand(ENT(pev)); UseBotArgs = false; } // Returns TRUE if given entity is our enemy /* <4901ac> ../game_shared/bot/bot.cpp:410 */ bool CBot::IsEnemy(CBaseEntity *ent) const { // only Players (real and AI) can be enemies if (!ent->IsPlayer()) return false; // corpses are no threat if (!ent->IsAlive()) return false; CBasePlayer *player = static_cast(ent); // if they are on our team, they are our friends if (player->m_iTeam == m_iTeam) return false; // yep, we hate 'em return true; } // Return number of enemies left alive /* <49021a> ../game_shared/bot/bot.cpp:434 */ int CBot::GetEnemiesRemaining(void) const { int count = 0; for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBaseEntity *player = UTIL_PlayerByIndex(i); if (player == NULL) continue; if (FNullEnt(player->pev)) continue; if (FStrEq(STRING(player->pev->netname), "")) continue; if (!IsEnemy(player)) continue; if (!player->IsAlive()) continue; count++; } return count; } // Return number of friends left alive /* <490338> ../game_shared/bot/bot.cpp:467 */ int CBot::GetFriendsRemaining(void) const { int count = 0; for (int i = 1; i <= gpGlobals->maxClients; ++i) { CBaseEntity *player = UTIL_PlayerByIndex(i); if (player == NULL) continue; if (FNullEnt(player->pev)) continue; if (FStrEq(STRING(player->pev->netname), "")) continue; if (IsEnemy(player)) continue; if (!player->IsAlive()) continue; if (player == static_cast(const_cast(this))) continue; count++; } return count; } /* <490489> ../game_shared/bot/bot.cpp:503 */ bool CBot::IsLocalPlayerWatchingMe(void) const { // avoid crash during spawn if (pev == NULL) return false; int myIndex = const_cast(this)->entindex(); CBasePlayer *player = UTIL_GetLocalPlayer(); if (player == NULL) return false; if ((player->pev->flags & FL_SPECTATOR || player->m_iTeam == SPECTATOR) && player->pev->iuser2 == myIndex) { switch (player->pev->iuser1) { case OBS_CHASE_LOCKED: case OBS_CHASE_FREE: case OBS_IN_EYE: return true; } } return false; } /* <4904f2> ../game_shared/bot/bot.cpp:536 */ NOXREF void CBot::Print(char *format, ...) const { va_list varg; char buffer[1024]; // prefix the message with the bot's name Q_sprintf(buffer, "%s: ", STRING(pev->netname)); SERVER_PRINT(buffer); va_start(varg, format); vsprintf(buffer, format, varg); va_end(varg); SERVER_PRINT(buffer); } /* <490561> ../game_shared/bot/bot.cpp:557 */ void CBot::PrintIfWatched(char *format, ...) const { if (!cv_bot_debug.value) return; if ((IsLocalPlayerWatchingMe() && (cv_bot_debug.value == 1 || cv_bot_debug.value == 3)) || (cv_bot_debug.value == 2 || cv_bot_debug.value == 4)) { va_list varg; char buffer[1024]; // prefix the message with the bot's name (this can be NULL if bot was just added) const char *name; if (pev == NULL) name = "(NULL pev)"; else name = STRING(pev->netname); Q_sprintf(buffer, "%s: ", (name != NULL) ? name : "(NULL netname)"); SERVER_PRINT(buffer); va_start(varg, format); vsprintf(buffer, format, varg); va_end(varg); SERVER_PRINT(buffer); } } /* <49066c> ../game_shared/bot/bot.cpp:588 */ ActiveGrenade::ActiveGrenade(int weaponID, CGrenade *grenadeEntity) { m_id = weaponID; m_entity = grenadeEntity; m_detonationPosition = grenadeEntity->pev->origin; m_dieTimestamp = 0; } /* <49069d> ../game_shared/bot/bot.cpp:597 */ void ActiveGrenade::OnEntityGone(void) { if (m_id == WEAPON_SMOKEGRENADE) { // smoke lingers after grenade is gone const float smokeLingerTime = 4.0f; m_dieTimestamp = gpGlobals->time + smokeLingerTime; } m_entity = NULL; } /* <4906e1> ../game_shared/bot/bot.cpp:610 */ bool ActiveGrenade::IsValid(void) const { if (!m_entity) { if (gpGlobals->time > m_dieTimestamp) return false; } return true; } /* <490710> ../game_shared/bot/bot.cpp:622 */ const Vector *ActiveGrenade::GetPosition(void) const { return &m_entity->pev->origin; } #ifdef HOOK_GAMEDLL void CBot::Spawn(void) { Spawn_(); } Vector CBot::GetAutoaimVector(float flDelta) { return GetAutoaimVector_(flDelta); } bool CBot::Initialize(const BotProfile *profile) { return Initialize_(profile); } void CBot::Crouch(void) { Crouch_(); } void CBot::StandUp(void) { StandUp_(); } void CBot::MoveForward(void) { MoveForward_(); } void CBot::MoveBackward(void) { MoveBackward_(); } void CBot::StrafeLeft(void) { StrafeLeft_(); } void CBot::StrafeRight(void) { StrafeRight_(); } bool CBot::Jump(bool mustJump) { return Jump_(mustJump); } void CBot::ClearMovement(void) { ClearMovement_(); } void CBot::UseEnvironment(void) { UseEnvironment_(); } void CBot::PrimaryAttack(void) { PrimaryAttack_(); } void CBot::ClearPrimaryAttack(void) { ClearPrimaryAttack_(); } void CBot::TogglePrimaryAttack(void) { TogglePrimaryAttack_(); } void CBot::SecondaryAttack(void) { SecondaryAttack_(); } void CBot::Reload(void) { Reload_(); } void CBot::ExecuteCommand(void) { ExecuteCommand_(); } #endif // HOOK_GAMEDLL