Add bot_mimic

This commit is contained in:
s1lentq 2024-06-03 01:28:45 +07:00
parent fef9bf3a87
commit ad1c58cef5
12 changed files with 119 additions and 2 deletions

View File

@ -62,6 +62,8 @@ cvar_t cv_bot_deathmatch = { "bot_deathmatch", "0", FCVAR_SERVER, 0.
cvar_t cv_bot_quota_mode = { "bot_quota_mode", "normal", 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_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_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 #else
// Migrated to bot_quota_mode, use "match" // Migrated to bot_quota_mode, use "match"
cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr };
@ -131,6 +133,8 @@ void Bot_RegisterCVars()
CVAR_REGISTER(&cv_bot_quota_mode); CVAR_REGISTER(&cv_bot_quota_mode);
CVAR_REGISTER(&cv_bot_join_delay); CVAR_REGISTER(&cv_bot_join_delay);
CVAR_REGISTER(&cv_bot_freeze); CVAR_REGISTER(&cv_bot_freeze);
CVAR_REGISTER(&cv_bot_mimic);
CVAR_REGISTER(&cv_bot_mimic_yaw_offset);
#endif #endif
} }

View File

@ -62,6 +62,8 @@ extern cvar_t cv_bot_deathmatch;
extern cvar_t cv_bot_quota_mode; extern cvar_t cv_bot_quota_mode;
extern cvar_t cv_bot_join_delay; extern cvar_t cv_bot_join_delay;
extern cvar_t cv_bot_freeze; extern cvar_t cv_bot_freeze;
extern cvar_t cv_bot_mimic;
extern cvar_t cv_bot_mimic_yaw_offset;
#else #else
extern cvar_t cv_bot_quota_match; extern cvar_t cv_bot_quota_match;
#endif #endif

View File

@ -758,6 +758,23 @@ void CCSBotManager::ServerCommand(const char *pcmd)
BOOL CCSBotManager::ClientCommand(CBasePlayer *pPlayer, const char *pcmd) BOOL CCSBotManager::ClientCommand(CBasePlayer *pPlayer, const char *pcmd)
{ {
#ifdef REGAMEDLL_ADD
if (pPlayer->IsBot())
return FALSE;
if (cv_bot_mimic.value == pPlayer->entindex())
{
// Bots mimic our client commands
ForEachPlayer([pPlayer, pcmd](CBasePlayer *bot)
{
if (pPlayer != bot && bot->IsBot())
bot->ClientCommand(pcmd, CMD_ARGV_(1));
return true;
});
}
#endif
return FALSE; return FALSE;
} }

View File

@ -299,6 +299,12 @@ void CCSBot::Attack(CBasePlayer *victim)
if (cv_bot_zombie.value != 0.0f) if (cv_bot_zombie.value != 0.0f)
return; return;
#ifdef REGAMEDLL_ADD
// If mimicing the player, don't attack state
if (cv_bot_mimic.value)
return;
#endif
// cannot attack if we are reloading // cannot attack if we are reloading
if (IsActiveWeaponReloading()) if (IsActiveWeaponReloading())
return; return;

View File

@ -61,6 +61,12 @@ void CCSBot::UpdateLookAngles()
float stiffness; float stiffness;
float damping; float damping;
#ifdef REGAMEDLL_ADD
// If mimicing the player, don't modify the view angles
if (cv_bot_mimic.value > 0)
return;
#endif
// springs are stiffer when attacking, so we can track and move between targets better // springs are stiffer when attacking, so we can track and move between targets better
if (IsAttacking()) if (IsAttacking())
{ {

View File

@ -10717,3 +10717,12 @@ bool CBasePlayer::Kill()
return true; return true;
} }
const usercmd_t *CBasePlayer::GetLastUserCommand() const
{
#ifdef REGAMEDLL_API
return CSPlayer()->GetLastUserCommand();
#else
return nullptr;
#endif
}

View File

@ -500,6 +500,7 @@ public:
void SetClientUserInfoModel(char *infobuffer, char *szNewModel); void SetClientUserInfoModel(char *infobuffer, char *szNewModel);
void SetClientUserInfoModel_api(char *infobuffer, char *szNewModel); void SetClientUserInfoModel_api(char *infobuffer, char *szNewModel);
void SetNewPlayerModel(const char *modelName); void SetNewPlayerModel(const char *modelName);
const usercmd_t *GetLastUserCommand() const;
BOOL SwitchWeapon(CBasePlayerItem *pWeapon); BOOL SwitchWeapon(CBasePlayerItem *pWeapon);
void CheckPowerups(); void CheckPowerups();
bool CanAffordPrimary(); bool CanAffordPrimary();

View File

@ -261,6 +261,18 @@ void CBot::ExecuteCommand()
// Adjust msec to command time interval // Adjust msec to command time interval
adjustedMSec = ThrottledMsec(); adjustedMSec = ThrottledMsec();
// Run mimic command
usercmd_t botCmd;
if (!RunMimicCommand(botCmd))
{
botCmd.forwardmove = m_forwardSpeed;
botCmd.sidemove = m_strafeSpeed;
botCmd.upmove = m_verticalSpeed;
botCmd.buttons = m_buttonFlags;
botCmd.impulse = 0;
botCmd.viewangles = pev->v_angle;
}
// player model is "munged" // player model is "munged"
pev->angles = pev->v_angle; pev->angles = pev->v_angle;
pev->angles.x /= -3.0f; pev->angles.x /= -3.0f;
@ -283,7 +295,49 @@ void CBot::ExecuteCommand()
#endif #endif
// Run the command // Run the command
PLAYER_RUN_MOVE(edict(), pev->v_angle, m_forwardSpeed, m_strafeSpeed, m_verticalSpeed, m_buttonFlags, 0, adjustedMSec); PLAYER_RUN_MOVE(edict(), botCmd.viewangles, botCmd.forwardmove, botCmd.sidemove, botCmd.upmove, botCmd.buttons, 0, adjustedMSec);
}
bool CBot::RunMimicCommand(usercmd_t &botCmd)
{
#ifdef REGAMEDLL_ADD
if (cv_bot_mimic.value <= 0)
return false;
if (cv_bot_mimic.value > gpGlobals->maxClients)
return false;
CBasePlayer *pPlayer = UTIL_PlayerByIndex(cv_bot_mimic.value);
if (!pPlayer)
return false;
if (!UTIL_IsValidPlayer(pPlayer))
return false;
if (!pPlayer->IsAlive())
return false;
if (pPlayer->IsBot())
return false;
const usercmd_t *ucmd = pPlayer->GetLastUserCommand();
if (!ucmd)
return false;
botCmd = *ucmd;
botCmd.viewangles[YAW] += cv_bot_mimic_yaw_offset.value;
float mult = 8.0f;
botCmd.forwardmove *= mult;
botCmd.sidemove *= mult;
botCmd.upmove *= mult;
pev->fixangle = 0;
return true;
#else
return false;
#endif
} }
void CBot::ResetCommand() void CBot::ResetCommand()

View File

@ -259,6 +259,8 @@ private:
void ResetCommand(); void ResetCommand();
byte ThrottledMsec() const; byte ThrottledMsec() const;
bool RunMimicCommand(usercmd_t &botCmd);
// returns current movement speed (for walk/run) // returns current movement speed (for walk/run)
float GetMoveSpeed(); float GetMoveSpeed();

View File

@ -141,7 +141,7 @@ inline bool IsIntersecting2D(const Vector &startA, const Vector &endA, const Vec
// Iterate over all active players in the game, invoking functor on each. // Iterate over all active players in the game, invoking functor on each.
// If functor returns false, stop iteration and return false. // If functor returns false, stop iteration and return false.
template <typename Functor> template <typename Functor>
bool ForEachPlayer(Functor &func) bool ForEachPlayer(Functor func)
{ {
for (int i = 1; i <= gpGlobals->maxClients; i++) for (int i = 1; i <= gpGlobals->maxClients; i++)
{ {

View File

@ -3300,6 +3300,11 @@ void EXT_FUNC __API_HOOK(PM_Move)(struct playermove_s *ppmove, int server)
{ {
pmove->friction = 1.0f; pmove->friction = 1.0f;
} }
#ifdef REGAMEDLL_API
// save the last usercmd
pmoveplayer->SetLastUserCommand(pmove->cmd);
#endif
} }
NOXREF int PM_GetVisEntInfo(int ent) NOXREF int PM_GetVisEntInfo(int ent)

View File

@ -141,6 +141,16 @@ public:
EProtectionState GetProtectionState() const; EProtectionState GetProtectionState() const;
bool CheckActivityInGame(); bool CheckActivityInGame();
const usercmd_t *GetLastUserCommand() const
{
return &m_LastCmd;
}
void SetLastUserCommand(const usercmd_t &ucmd)
{
m_LastCmd = ucmd;
}
public: public:
char m_szModel[32]; char m_szModel[32];
bool m_bForceShowMenu; bool m_bForceShowMenu;
@ -175,6 +185,7 @@ public:
bool m_bPlayerDominated[MAX_CLIENTS]; // [0-31] array of state per other player whether player is dominating other players bool m_bPlayerDominated[MAX_CLIENTS]; // [0-31] array of state per other player whether player is dominating other players
int m_iGibDamageThreshold; // negative health to reach to gib player int m_iGibDamageThreshold; // negative health to reach to gib player
usercmd_t m_LastCmd;
}; };
// Inlines // Inlines