Files
DoomRTX/neo/doom3/game/bots/BotAI_Battle_Fight.cpp
Justin Marshall 31a3805769 Bot fixes.
2026-05-20 09:10:15 -07:00

177 lines
4.0 KiB
C++

// BotAI_Battle_Fight.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_BattleFight
=====================
*/
stateResult_t rvmBot::state_BattleFight(stateParms_t* parms)
{
idVec3 target;
idPlayer* entinfo;
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
//if there is another better enemy
if( BotFindEnemy( &bs, bs.enemy ) )
{
common->DPrintf( "found new better enemy\n" );
}
//if no enemy
if( bs.enemy < 0 || bs.enemy >= gameLocal.num_entities || gameLocal.entities[bs.enemy] == NULL )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
entinfo = gameLocal.entities[bs.enemy]->Cast<idPlayer>();
if( entinfo == NULL )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//if the enemy is dead
if( bs.enemydeath_time )
{
if( bs.enemydeath_time < Bot_Time() - 1.0 )
{
bs.enemydeath_time = 0;
bs.ltg_time = 0;
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
}
else if( EntityIsDead( entinfo ) )
{
bs.enemydeath_time = Bot_Time();
}
target = entinfo->GetOrigin();
//update the attack inventory values
BotUpdateBattleInventory( &bs, bs.enemy );
//if the enemy is not visible
if( !BotEntityVisible( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy ) )
{
if( BotWantsToChase( &bs ) )
{
bs.chase_time = Bot_Time() + 10.0f;
stateThread.SetState("state_Chase");
return SRESULT_DONE_FRAME;
}
else
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
}
bs.enemyvisible_time = Bot_Time();
bs.lastenemyorigin = target;
bs.last_enemy_visible_position = target;
//use holdable items
BotBattleUseItems( &bs );
//choose the best weapon to fight with
BotChooseWeapon( &bs );
// Opportunistic combat pickup: keep fighting, but route through a nearby item
// instead of throwing the current goal away and random-strafing forever. The
// NBG selector itself expands this range when the bot is stuck on pistol/dry
// ammo, and otherwise keeps the detour short.
if( bs.check_time < Bot_Time() )
{
bs.check_time = Bot_Time() + 0.45f;
bot_goal_t pickupAnchor;
pickupAnchor.Reset();
pickupAnchor.entitynum = bs.enemy;
pickupAnchor.origin = target;
pickupAnchor.mins = idVec3( -8.0f, -8.0f, -8.0f );
pickupAnchor.maxs = idVec3( 8.0f, 8.0f, 8.0f );
const float pickupRange = 260.0f;
if( BotNearbyGoal( &bs, 0, &pickupAnchor, pickupRange ) )
{
bs.nbg_time = Bot_Time() + 18.0f;
stateThread.SetState("state_BattleNBG");
return SRESULT_DONE_FRAME;
}
}
// Fight like a deathmatch bot: keep pressure on the enemy while changing
// strafe direction often enough to be hard to track.
if( bs.attackstrafe_time < Bot_Time() )
{
bs.attackstrafe_time = Bot_Time() + idMath::FRandRange( 0.65f, 1.35f );
if( rvmBotUtil::random() < 0.5f )
{
bs.flags ^= BFL_STRAFERIGHT;
}
}
idVec3 toEnemy = target - bs.origin;
toEnemy[2] = 0.0f;
const float enemyDist = toEnemy.Length();
if( enemyDist > 1.0f )
{
toEnemy /= enemyDist;
idVec3 strafeDir = ( bs.flags & BFL_STRAFERIGHT ) ? idVec3( -toEnemy[1], toEnemy[0], 0.0f ) : idVec3( toEnemy[1], -toEnemy[0], 0.0f );
idVec3 moveDir = strafeDir;
if( enemyDist > 520.0f )
{
moveDir += toEnemy * 0.65f;
}
else if( enemyDist < 170.0f )
{
moveDir -= toEnemy * 0.75f;
}
moveDir.Normalize();
bs.botinput.dir = moveDir;
bs.botinput.speed = pm_runspeed.GetInteger();
if( enemyDist < 420.0f && rvmBotUtil::random() < 0.025f )
{
bs.botinput.actionflags |= ACTION_JUMP;
}
}
else
{
BotMoveInRandomDirection(&bs);
}
//aim at the enemy
BotAimAtEnemy( &bs );
//attack the enemy if possible
BotCheckAttack( &bs );
//if the bot wants to retreat
if( !( bs.flags & BFL_FIGHTSUICIDAL ) )
{
if( BotWantsToRetreat( &bs ) )
{
stateThread.SetState("state_Retreat");
return SRESULT_DONE_FRAME;
}
}
return SRESULT_WAIT;
}