diff --git a/code/fgame/playerbot.cpp b/code/fgame/playerbot.cpp index 25d6c74f..28e3d525 100644 --- a/code/fgame/playerbot.cpp +++ b/code/fgame/playerbot.cpp @@ -35,45 +35,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *bot_manualmove; -CLASS_DECLARATION(Player, PlayerBot, NULL) { - {&EV_Killed, &PlayerBot::Killed }, - {&EV_GotKill, &PlayerBot::GotKill }, - {&EV_Player_StuffText, &PlayerBot::EventStuffText}, - {NULL, NULL } -}; - -PlayerBot::PlayerBot() -{ - entflags |= ECF_BOT; - controller = NULL; -} - -void PlayerBot::setController(BotController *controlledBy) -{ - controller = controlledBy; -} - -void PlayerBot::Spawned(void) -{ - controller->Spawned(); - - Player::Spawned(); -} - -void PlayerBot::Killed(Event *ev) -{ - Player::Killed(ev); - - controller->Killed(ev); -} - -void PlayerBot::GotKill(Event *ev) -{ - Player::GotKill(ev); - - controller->GotKill(ev); -} - CLASS_DECLARATION(Listener, BotController, NULL) { {NULL, NULL} }; @@ -103,11 +64,6 @@ BotController::BotController() m_botEyes.ofs[1] = 0; m_botEyes.ofs[2] = DEFAULT_VIEWHEIGHT; - m_vAngSpeed = vec_zero; - m_vTargetAng = vec_zero; - m_vCurrentAng = vec_zero; - m_fYawSpeedMult = 1.0f; - m_iCuriousTime = 0; m_iAttackTime = 0; @@ -138,69 +94,6 @@ void BotController::Init(void) InitState_Weapon(&botfuncs[4]); } -float AngleDifference(float ang1, float ang2) -{ - float diff; - - diff = ang1 - ang2; - if (ang1 > ang2) { - if (diff > 180.0) { - diff -= 360.0; - } - } else { - if (diff < -180.0) { - diff += 360.0; - } - } - return diff; -} - -void BotController::TurnThink(void) -{ - float diff, factor, maxchange, anglespeed, desired_speed; - int i; - - if (m_vTargetAng[PITCH] > 180) { - m_vTargetAng[PITCH] -= 360; - } - - factor = 0.25f; - maxchange = 360; - - if (maxchange < 240) { - maxchange = 240; - } - - maxchange *= level.frametime; - - for (i = 0; i < 2; i++) { - //over reaction view model - m_vCurrentAng[i] = AngleMod(m_vCurrentAng[i]); - m_vTargetAng[i] = AngleMod(m_vTargetAng[i]); - diff = AngleDifference(m_vCurrentAng[i], m_vTargetAng[i]); - desired_speed = diff * factor; - - m_vAngSpeed[i] = Q_clamp_float(m_vAngSpeed[i] + (m_vAngSpeed[i] - desired_speed), -180, 180); - anglespeed = Q_clamp_float(m_vAngSpeed[i], -maxchange, maxchange); - - m_vCurrentAng[i] += anglespeed; - m_vCurrentAng[i] = AngleMod(m_vCurrentAng[i]); - - //demping - m_vAngSpeed[i] *= 0.2 * (1 - factor); - } - - if (m_vCurrentAng[PITCH] > 180) { - m_vCurrentAng[PITCH] -= 360; - } - - m_botEyes.angles[0] = m_vCurrentAng[0]; - m_botEyes.angles[1] = m_vCurrentAng[1]; - m_botCmd.angles[0] = ANGLE2SHORT(m_vCurrentAng[0]) - controlledEnt->client->ps.delta_angles[0]; - m_botCmd.angles[1] = ANGLE2SHORT(m_vCurrentAng[1]) - controlledEnt->client->ps.delta_angles[1]; - m_botCmd.angles[2] = ANGLE2SHORT(m_vCurrentAng[2]) - controlledEnt->client->ps.delta_angles[2]; -} - void BotController::GetUsercmd(usercmd_t *ucmd) { *ucmd = m_botCmd; @@ -231,8 +124,7 @@ void BotController::UpdateBotStates(void) } if (controlledEnt->GetTeam() == TEAM_NONE || controlledEnt->GetTeam() == TEAM_SPECTATOR) { - Event *event; - float time; + float time; // Add some delay to avoid telefragging time = controlledEnt->entnum / 20.0; @@ -266,7 +158,7 @@ void BotController::UpdateBotStates(void) CheckStates(); movement.MoveThink(m_botCmd); - TurnThink(); + rotation.TurnThink(m_botCmd, m_botEyes); CheckUse(); } @@ -356,33 +248,6 @@ void BotController::SendCommand(const char *text) } } -/* -==================== -SetTargetAngles - -Set the bot's angle -==================== -*/ -void BotController::SetTargetAngles(Vector vAngles) -{ - m_vTargetAng = vAngles; -} - -/* -==================== -AimAt - -Make the bot face to the specified direction -==================== -*/ -void BotController::AimAt(Vector vPos) -{ - Vector vDelta = vPos - controlledEnt->centroid; - - VectorNormalize(vDelta); - vectoangles(vDelta, m_vTargetAng); -} - /* ==================== AimAtAimNode @@ -400,10 +265,12 @@ void BotController::AimAtAimNode(void) goal = movement.GetCurrentGoal(); if (goal != controlledEnt->origin) { - AimAt(goal); + rotation.AimAt(goal); } - m_vTargetAng[PITCH] = 0; + Vector targetAngles = rotation.GetTargetAngles(); + targetAngles.x = 0; + rotation.SetTargetAngles(targetAngles); } /* @@ -881,13 +748,14 @@ void BotController::State_Attack(void) fMinDistanceSquared = 0; } - AimAt(m_pEnemy->centroid + Vector(G_CRandom(8), G_CRandom(8), G_CRandom(8))); + rotation.AimAt(m_pEnemy->centroid + Vector(G_CRandom(8), G_CRandom(8), G_CRandom(8))); if (bNoMove) { return; } - if ((!movement.MoveToBestAttractivePoint(5) && !movement.IsMoving()) || (m_vOldEnemyPos != m_vLastEnemyPos && !movement.MoveDone())) { + if ((!movement.MoveToBestAttractivePoint(5) && !movement.IsMoving()) + || (m_vOldEnemyPos != m_vLastEnemyPos && !movement.MoveDone())) { if (!bMelee) { if ((controlledEnt->origin - m_vLastEnemyPos).lengthSquared() < fMinDistanceSquared) { Vector vDir = controlledEnt->origin - m_vLastEnemyPos; @@ -1048,6 +916,7 @@ void BotController::setControlledEntity(Player *player) { controlledEnt = player; movement.SetControlledEntity(player); + rotation.SetControlledEntity(player); } Player *BotController::getControlledEntity() const @@ -1123,3 +992,42 @@ void BotControllerManager::ThinkControllers() controller->Think(); } } + +CLASS_DECLARATION(Player, PlayerBot, NULL) { + {&EV_Killed, &PlayerBot::Killed }, + {&EV_GotKill, &PlayerBot::GotKill }, + {&EV_Player_StuffText, &PlayerBot::EventStuffText}, + {NULL, NULL } +}; + +PlayerBot::PlayerBot() +{ + entflags |= ECF_BOT; + controller = NULL; +} + +void PlayerBot::setController(BotController *controlledBy) +{ + controller = controlledBy; +} + +void PlayerBot::Spawned(void) +{ + controller->Spawned(); + + Player::Spawned(); +} + +void PlayerBot::Killed(Event *ev) +{ + Player::Killed(ev); + + controller->Killed(ev); +} + +void PlayerBot::GotKill(Event *ev) +{ + Player::GotKill(ev); + + controller->GotKill(ev); +} diff --git a/code/fgame/playerbot.h b/code/fgame/playerbot.h index 37481757..363ce60f 100644 --- a/code/fgame/playerbot.h +++ b/code/fgame/playerbot.h @@ -36,25 +36,6 @@ typedef struct nodeAttract_s { class BotController; -class PlayerBot : public Player -{ -public: - CLASS_PROTOTYPE(PlayerBot); - -public: - PlayerBot(); - - void setController(BotController *controlledBy); - - void Spawned(void); - - void Killed(Event *ev); - void GotKill(Event *ev); - -private: - BotController *controller; -}; - class BotMovement { public: @@ -109,7 +90,25 @@ private: }; class BotRotation -{}; +{ +public: + BotRotation(); + + void SetControlledEntity(Player *newEntity); + + void TurnThink(usercmd_t& botcmd, usereyes_t& eyeinfo); + const Vector& GetTargetAngles() const; + void SetTargetAngles(Vector vAngles); + void AimAt(Vector vPos); + +private: + SafePtr controlledEntity; + + Vector m_vTargetAng; + Vector m_vCurrentAng; + Vector m_vAngSpeed; + float m_fYawSpeedMult; +}; class BotController : public Listener { @@ -125,6 +124,7 @@ private: static botfunc_t botfuncs[]; BotMovement movement; + BotRotation rotation; // States int m_iCuriousTime; @@ -140,12 +140,6 @@ private: usercmd_t m_botCmd; usereyes_t m_botEyes; - // Direction - Vector m_vTargetAng; - Vector m_vCurrentAng; - Vector m_vAngSpeed; - float m_fYawSpeedMult; - // States int m_StateCount; unsigned int m_StateFlags; @@ -155,7 +149,6 @@ private: int m_iNextTauntTime; private: - void TurnThink(void); void CheckUse(void); void State_DefaultBegin(void); @@ -204,12 +197,10 @@ public: void GetEyeInfo(usereyes_t *eyeinfo); void GetUsercmd(usercmd_t *ucmd); - void SetTargetAngles(Vector vAngles); void UpdateBotStates(void); void CheckReload(void); - void AimAt(Vector vPos); void AimAtAimNode(void); void NoticeEvent(Vector vPos, int iType, Entity *pEnt, float fDistanceSquared, float fRadiusSquared); @@ -274,3 +265,22 @@ private: }; extern BotManager botManager; + +class PlayerBot : public Player +{ +public: + CLASS_PROTOTYPE(PlayerBot); + +public: + PlayerBot(); + + void setController(BotController *controlledBy); + + void Spawned(void); + + void Killed(Event *ev); + void GotKill(Event *ev); + +private: + BotController *controller; +}; diff --git a/code/fgame/playerbot_rotation.cpp b/code/fgame/playerbot_rotation.cpp new file mode 100644 index 00000000..28d913b9 --- /dev/null +++ b/code/fgame/playerbot_rotation.cpp @@ -0,0 +1,139 @@ +/* +=========================================================================== +Copyright (C) 2024 the OpenMoHAA team + +This file is part of OpenMoHAA source code. + +OpenMoHAA source code 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. + +OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// playerbot_rotation.cpp: Manages bot rotation + +#include "playerbot.h" + +BotRotation::BotRotation() +{ + m_vAngSpeed = vec_zero; + m_vTargetAng = vec_zero; + m_vCurrentAng = vec_zero; + m_fYawSpeedMult = 1.0f; +} + +void BotRotation::SetControlledEntity(Player *newEntity) +{ + controlledEntity = newEntity; +} + +float AngleDifference(float ang1, float ang2) +{ + float diff; + + diff = ang1 - ang2; + if (ang1 > ang2) { + if (diff > 180.0) { + diff -= 360.0; + } + } else { + if (diff < -180.0) { + diff += 360.0; + } + } + return diff; +} + +void BotRotation::TurnThink(usercmd_t& botcmd, usereyes_t& eyeinfo) +{ + float diff, factor, maxchange, anglespeed, desired_speed; + int i; + + if (m_vTargetAng[PITCH] > 180) { + m_vTargetAng[PITCH] -= 360; + } + + factor = 0.25f; + maxchange = 360; + + if (maxchange < 240) { + maxchange = 240; + } + + maxchange *= level.frametime; + + for (i = 0; i < 2; i++) { + //over reaction view model + m_vCurrentAng[i] = AngleMod(m_vCurrentAng[i]); + m_vTargetAng[i] = AngleMod(m_vTargetAng[i]); + diff = AngleDifference(m_vCurrentAng[i], m_vTargetAng[i]); + desired_speed = diff * factor; + + m_vAngSpeed[i] = Q_clamp_float(m_vAngSpeed[i] + (m_vAngSpeed[i] - desired_speed), -180, 180); + anglespeed = Q_clamp_float(m_vAngSpeed[i], -maxchange, maxchange); + + m_vCurrentAng[i] += anglespeed; + m_vCurrentAng[i] = AngleMod(m_vCurrentAng[i]); + + //demping + m_vAngSpeed[i] *= 0.2 * (1 - factor); + } + + if (m_vCurrentAng[PITCH] > 180) { + m_vCurrentAng[PITCH] -= 360; + } + + eyeinfo.angles[0] = m_vCurrentAng[0]; + eyeinfo.angles[1] = m_vCurrentAng[1]; + botcmd.angles[0] = ANGLE2SHORT(m_vCurrentAng[0]) - controlledEntity->client->ps.delta_angles[0]; + botcmd.angles[1] = ANGLE2SHORT(m_vCurrentAng[1]) - controlledEntity->client->ps.delta_angles[1]; + botcmd.angles[2] = ANGLE2SHORT(m_vCurrentAng[2]) - controlledEntity->client->ps.delta_angles[2]; +} + +/* +==================== +GetTargetAngles + +Return the target angle +==================== +*/ +const Vector& BotRotation::GetTargetAngles() const +{ + return m_vTargetAng; +} + +/* +==================== +SetTargetAngles + +Set the bot's angle +==================== +*/ +void BotRotation::SetTargetAngles(Vector vAngles) +{ + m_vTargetAng = vAngles; +} + +/* +==================== +AimAt + +Make the bot face to the specified direction +==================== +*/ +void BotRotation::AimAt(Vector vPos) +{ + Vector vDelta = vPos - controlledEntity->centroid; + + VectorNormalize(vDelta); + vectoangles(vDelta, m_vTargetAng); +}