// BotAI_Battle_Retreat.cpp // #pragma hdrstop #include "precompiled.h" #include "../Game_local.h" /* ===================== rvmBot::state_Retreat ===================== */ stateResult_t rvmBot::state_Retreat(stateParms_t* parms) { bot_goal_t goal; idPlayer* entinfo; rvmBot* owner; idVec3 target, dir; float attack_skill, range; // respawn if dead. if( BotIsDead( &bs ) ) { stateThread.SetState("state_Respawn"); return SRESULT_DONE_FRAME; } // 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; } // Ensure the target is a player. entinfo = gameLocal.entities[bs.enemy]->Cast(); if( !entinfo ) { stateThread.SetState("state_SeekLTG"); return SRESULT_DONE_FRAME; } owner = gameLocal.entities[bs.entitynum]->Cast(); // If our enemy is dead, search for another LTG. if( EntityIsDead( entinfo ) ) { stateThread.SetState("state_SeekLTG"); return SRESULT_DONE_FRAME; } //if there is another better enemy if( BotFindEnemy( &bs, bs.enemy ) ) { common->DPrintf( "found new better enemy\n" ); } //update the attack inventory values BotUpdateBattleInventory( &bs, bs.enemy ); BotChooseWeapon( &bs ); // Before switching back to chase, opportunistically grab a nearby tactical // pickup. This keeps the bot from running past a rocket launcher, shells, or // health while it is already committed to a fight. if( bs.check_time < Bot_Time() ) { bs.check_time = Bot_Time() + 0.5f; bot_goal_t pickupAnchor; pickupAnchor.Reset(); pickupAnchor.entitynum = bs.enemy; pickupAnchor.origin = entinfo->GetOrigin(); pickupAnchor.mins = idVec3( -8.0f, -8.0f, -8.0f ); pickupAnchor.maxs = idVec3( 8.0f, 8.0f, 8.0f ); if( BotNearbyGoal( &bs, 0, &pickupAnchor, 260.0f ) ) { bs.nbg_time = Bot_Time() + 18.0f; stateThread.SetState("state_BattleNBG"); return SRESULT_DONE_FRAME; } } //if the bot doesn't want to retreat anymore... probably picked up some nice items if( BotWantsToChase( &bs ) ) { //empty the goal stack, when chasing, only the enemy is the goal botGoalManager.BotEmptyGoalStack( bs.gs ); //go chase the enemy //AIEnter_Battle_Chase(bs, "battle retreat: wants to chase"); stateThread.SetState("state_Chase"); return SRESULT_DONE_FRAME; } //update the last time the enemy was visible if( BotEntityVisible( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy ) ) { bs.enemyvisible_time = Bot_Time(); target = entinfo->GetOrigin(); bs.lastenemyorigin = target; bs.last_enemy_visible_position = target; } //if the enemy is NOT visible for 4 seconds if( bs.enemyvisible_time < Bot_Time() - 4 ) { stateThread.SetState("state_SeekLTG"); return SRESULT_DONE_FRAME; } //else if the enemy is NOT visible else if( bs.enemyvisible_time < Bot_Time() ) { //if there is another enemy if( BotFindEnemy( &bs, -1 ) ) { //AIEnter_Battle_Fight(bs, "battle retreat: another enemy"); stateThread.SetState("state_BattleFight"); return SRESULT_DONE_FRAME; } } //use holdable items BotBattleUseItems( &bs ); //get the current long term goal while retreating if( !BotGetItemLongTermGoal( &bs, 0, &bs.currentGoal ) ) { //AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out"); stateThread.SetState("state_BattleFight"); bs.flags |= BFL_FIGHTSUICIDAL; return SRESULT_DONE_FRAME; } //check for nearby goals periodically while retreating along the long-term item path if( bs.check_time < Bot_Time() ) { bs.check_time = Bot_Time() + 0.5f; range = 260.0f; if( BotNearbyGoal( &bs, 0, &goal, range ) ) { bs.nbg_time = Bot_Time() + 18.0f; stateThread.SetState("state_BattleNBG"); return SRESULT_DONE_FRAME; } } MoveToCoverPoint(); if (bot_skill.GetInteger() > 1) { bs.firethrottlewait_time = 0; } BotChooseWeapon( &bs ); BotAimAtEnemy( &bs ); //attack the enemy if possible BotCheckAttack( &bs ); return SRESULT_WAIT; }