Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

ai_dmnet.c File Reference

#include "g_local.h"
#include "botlib.h"
#include "be_aas.h"
#include "be_ea.h"
#include "be_ai_char.h"
#include "be_ai_chat.h"
#include "be_ai_gen.h"
#include "be_ai_goal.h"
#include "be_ai_move.h"
#include "be_ai_weap.h"
#include "ai_main.h"
#include "ai_dmq3.h"
#include "ai_chat.h"
#include "ai_cmd.h"
#include "ai_dmnet.h"
#include "ai_team.h"
#include "chars.h"
#include "inv.h"
#include "syn.h"
#include "match.h"
#include "../../ui/menudef.h"

Include dependency graph for ai_dmnet.c:

Include dependency graph

Go to the source code of this file.

Defines

#define GFL_AIR   128
#define LOOKAHEAD_DISTANCE   300

Functions

void AIEnter_Battle_Chase (bot_state_t *bs, char *s)
void AIEnter_Battle_Fight (bot_state_t *bs, char *s)
void AIEnter_Battle_NBG (bot_state_t *bs, char *s)
void AIEnter_Battle_Retreat (bot_state_t *bs, char *s)
void AIEnter_Battle_SuicidalFight (bot_state_t *bs, char *s)
void AIEnter_Intermission (bot_state_t *bs, char *s)
void AIEnter_Observer (bot_state_t *bs, char *s)
void AIEnter_Respawn (bot_state_t *bs, char *s)
void AIEnter_Seek_ActivateEntity (bot_state_t *bs, char *s)
void AIEnter_Seek_LTG (bot_state_t *bs, char *s)
void AIEnter_Seek_NBG (bot_state_t *bs, char *s)
void AIEnter_Stand (bot_state_t *bs, char *s)
int AINode_Battle_Chase (bot_state_t *bs)
int AINode_Battle_Fight (bot_state_t *bs)
int AINode_Battle_NBG (bot_state_t *bs)
int AINode_Battle_Retreat (bot_state_t *bs)
int AINode_Intermission (bot_state_t *bs)
int AINode_Observer (bot_state_t *bs)
int AINode_Respawn (bot_state_t *bs)
int AINode_Seek_ActivateEntity (bot_state_t *bs)
int AINode_Seek_LTG (bot_state_t *bs)
int AINode_Seek_NBG (bot_state_t *bs)
int AINode_Stand (bot_state_t *bs)
void BotClearPath (bot_state_t *bs, bot_moveresult_t *moveresult)
void BotDumpNodeSwitches (bot_state_t *bs)
int BotGetAirGoal (bot_state_t *bs, bot_goal_t *goal)
int BotGetItemLongTermGoal (bot_state_t *bs, int tfl, bot_goal_t *goal)
int BotGetLongTermGoal (bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal)
int BotGoForAir (bot_state_t *bs, int tfl, bot_goal_t *ltg, float range)
int BotLongTermGoal (bot_state_t *bs, int tfl, int retreat, bot_goal_t *goal)
int BotNearbyGoal (bot_state_t *bs, int tfl, bot_goal_t *ltg, float range)
int BotReachedGoal (bot_state_t *bs, bot_goal_t *goal)
void BotRecordNodeSwitch (bot_state_t *bs, char *node, char *str, char *s)
void BotResetNodeSwitches (void)
int BotSelectActivateWeapon (bot_state_t *bs)

Variables

char nodeswitch [MAX_NODESWITCHES+1][144]
int numnodeswitches


Define Documentation

#define GFL_AIR   128
 

Definition at line 60 of file ai_dmnet.c.

#define LOOKAHEAD_DISTANCE   300
 

Definition at line 65 of file ai_dmnet.c.


Function Documentation

void AIEnter_Battle_Chase bot_state_t bs,
char *  s
 

Definition at line 2140 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), bot_state_s::chase_time, FloatTime, and s.

Referenced by AINode_Battle_Fight(), and AINode_Battle_Retreat().

02140                                                     {
02141     BotRecordNodeSwitch(bs, "battle chase", "", s);
02142     bs->chase_time = FloatTime();
02143     bs->ainode = AINode_Battle_Chase;
02144 }

Here is the call graph for this function:

void AIEnter_Battle_Fight bot_state_t bs,
char *  s
 

Definition at line 1963 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), bot_state_s::ms, s, and trap_BotResetLastAvoidReach().

Referenced by AINode_Battle_Chase(), AINode_Battle_NBG(), AINode_Battle_Retreat(), AINode_Seek_ActivateEntity(), AINode_Seek_LTG(), AINode_Seek_NBG(), and AINode_Stand().

01963                                                     {
01964     BotRecordNodeSwitch(bs, "battle fight", "", s);
01965     trap_BotResetLastAvoidReach(bs->ms);
01966     bs->ainode = AINode_Battle_Fight;
01967 }

Here is the call graph for this function:

void AIEnter_Battle_NBG bot_state_t bs,
char *  s
 

Definition at line 2469 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), and s.

Referenced by AINode_Battle_Chase(), AINode_Battle_Retreat(), AINode_Seek_ActivateEntity(), and AINode_Seek_NBG().

02469                                                   {
02470     BotRecordNodeSwitch(bs, "battle NBG", "", s);
02471     bs->ainode = AINode_Battle_NBG;
02472 }

Here is the call graph for this function:

void AIEnter_Battle_Retreat bot_state_t bs,
char *  s
 

Definition at line 2280 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), and s.

Referenced by AINode_Battle_Chase(), AINode_Battle_Fight(), AINode_Battle_NBG(), and AINode_Seek_LTG().

02280                                                       {
02281     BotRecordNodeSwitch(bs, "battle retreat", "", s);
02282     bs->ainode = AINode_Battle_Retreat;
02283 }

Here is the call graph for this function:

void AIEnter_Battle_SuicidalFight bot_state_t bs,
char *  s
 

Definition at line 1974 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), bot_state_s::flags, bot_state_s::ms, s, and trap_BotResetLastAvoidReach().

Referenced by AINode_Battle_Retreat().

01974                                                             {
01975     BotRecordNodeSwitch(bs, "battle fight", "", s);
01976     trap_BotResetLastAvoidReach(bs->ms);
01977     bs->ainode = AINode_Battle_Fight;
01978     bs->flags |= BFL_FIGHTSUICIDAL;
01979 }

Here is the call graph for this function:

void AIEnter_Intermission bot_state_t bs,
char *  s
 

Definition at line 1130 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotChat_EndLevel(), BotRecordNodeSwitch(), BotResetState(), bot_state_s::chatto, bot_state_s::cs, s, and trap_BotEnterChat().

Referenced by AINode_Battle_Chase(), AINode_Battle_Fight(), AINode_Battle_NBG(), AINode_Battle_Retreat(), AINode_Seek_ActivateEntity(), AINode_Seek_LTG(), and AINode_Seek_NBG().

01130                                                     {
01131     BotRecordNodeSwitch(bs, "intermission", "", s);
01132     //reset the bot state
01133     BotResetState(bs);
01134     //check for end level chat
01135     if (BotChat_EndLevel(bs)) {
01136         trap_BotEnterChat(bs->cs, 0, bs->chatto);
01137     }
01138     bs->ainode = AINode_Intermission;
01139 }

Here is the call graph for this function:

void AIEnter_Observer bot_state_t bs,
char *  s
 

Definition at line 1165 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), BotResetState(), and s.

Referenced by AINode_Battle_Chase(), AINode_Battle_Fight(), AINode_Battle_NBG(), AINode_Battle_Retreat(), AINode_Seek_ActivateEntity(), AINode_Seek_LTG(), and AINode_Seek_NBG().

01165                                                 {
01166     BotRecordNodeSwitch(bs, "observer", "", s);
01167     //reset the bot state
01168     BotResetState(bs);
01169     bs->ainode = AINode_Observer;
01170 }

Here is the call graph for this function:

void AIEnter_Respawn bot_state_t bs,
char *  s
 

Definition at line 1234 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotChat_Death(), BotChatTime(), BotRecordNodeSwitch(), FloatTime, bot_state_s::gs, bot_state_s::ms, random, bot_state_s::respawn_time, bot_state_s::respawn_wait, bot_state_s::respawnchat_time, s, trap_BotResetAvoidGoals(), trap_BotResetAvoidReach(), trap_BotResetGoalState(), and trap_BotResetMoveState().

Referenced by AINode_Battle_Chase(), AINode_Battle_Fight(), AINode_Battle_NBG(), AINode_Battle_Retreat(), AINode_Seek_ActivateEntity(), AINode_Seek_LTG(), and AINode_Seek_NBG().

01234                                                {
01235     BotRecordNodeSwitch(bs, "respawn", "", s);
01236     //reset some states
01237     trap_BotResetMoveState(bs->ms);
01238     trap_BotResetGoalState(bs->gs);
01239     trap_BotResetAvoidGoals(bs->gs);
01240     trap_BotResetAvoidReach(bs->ms);
01241     //if the bot wants to chat
01242     if (BotChat_Death(bs)) {
01243         bs->respawn_time = FloatTime() + BotChatTime(bs);
01244         bs->respawnchat_time = FloatTime();
01245     }
01246     else {
01247         bs->respawn_time = FloatTime() + 1 + random();
01248         bs->respawnchat_time = 0;
01249     }
01250     //set respawn state
01251     bs->respawn_wait = qfalse;
01252     bs->ainode = AINode_Respawn;
01253 }

Here is the call graph for this function:

void AIEnter_Seek_ActivateEntity bot_state_t bs,
char *  s
 

Definition at line 1433 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), and s.

Referenced by BotGoForActivateGoal().

01433                                                            {
01434     BotRecordNodeSwitch(bs, "activate entity", "", s);
01435     bs->ainode = AINode_Seek_ActivateEntity;
01436 }

Here is the call graph for this function:

void AIEnter_Seek_LTG bot_state_t bs,
char *  s
 

Definition at line 1776 of file ai_dmnet.c.

References bot_state_s::ainode, bot_goal_t, bot_state_t, BotRecordNodeSwitch(), bot_state_s::gs, bot_goal_s::number, s, trap_BotGetTopGoal(), and trap_BotGoalName().

Referenced by AINode_Battle_Chase(), AINode_Battle_Fight(), AINode_Battle_Retreat(), AINode_Respawn(), AINode_Seek_NBG(), AINode_Stand(), and BotDeathmatchAI().

01776                                                 {
01777     bot_goal_t goal;
01778     char buf[144];
01779 
01780     if (trap_BotGetTopGoal(bs->gs, &goal)) {
01781         trap_BotGoalName(goal.number, buf, 144);
01782         BotRecordNodeSwitch(bs, "seek LTG", buf, s);
01783     }
01784     else {
01785         BotRecordNodeSwitch(bs, "seek LTG", "no goal", s);
01786     }
01787     bs->ainode = AINode_Seek_LTG;
01788 }

Here is the call graph for this function:

void AIEnter_Seek_NBG bot_state_t bs,
char *  s
 

Definition at line 1643 of file ai_dmnet.c.

References bot_state_s::ainode, bot_goal_t, bot_state_t, BotRecordNodeSwitch(), bot_state_s::gs, bot_goal_s::number, s, trap_BotGetTopGoal(), and trap_BotGoalName().

Referenced by AINode_Battle_NBG(), AINode_Seek_ActivateEntity(), AINode_Seek_LTG(), and BotGetLongTermGoal().

01643                                                 {
01644     bot_goal_t goal;
01645     char buf[144];
01646 
01647     if (trap_BotGetTopGoal(bs->gs, &goal)) {
01648         trap_BotGoalName(goal.number, buf, 144);
01649         BotRecordNodeSwitch(bs, "seek NBG", buf, s);
01650     }
01651     else {
01652         BotRecordNodeSwitch(bs, "seek NBG", "no goal", s);
01653     }
01654     bs->ainode = AINode_Seek_NBG;
01655 }

Here is the call graph for this function:

void AIEnter_Stand bot_state_t bs,
char *  s
 

Definition at line 1190 of file ai_dmnet.c.

References bot_state_s::ainode, bot_state_t, BotRecordNodeSwitch(), FloatTime, s, and bot_state_s::standfindenemy_time.

Referenced by AINode_Battle_Fight(), AINode_Intermission(), AINode_Observer(), AINode_Seek_LTG(), BotCheckConsoleMessages(), and BotDeathmatchAI().

01190                                              {
01191     BotRecordNodeSwitch(bs, "stand", "", s);
01192     bs->standfindenemy_time = FloatTime() + 1;
01193     bs->ainode = AINode_Stand;
01194 }

Here is the call graph for this function:

int AINode_Battle_Chase bot_state_t bs  ) 
 

Definition at line 2151 of file ai_dmnet.c.

References AIEnter_Battle_Fight(), AIEnter_Battle_NBG(), AIEnter_Battle_Retreat(), AIEnter_Intermission(), AIEnter_Observer(), AIEnter_Respawn(), AIEnter_Seek_LTG(), bot_goal_s::areanum, bot_state_s::areanum, bot_goal_t, bot_grapple, bot_moveresult_t, bot_state_t, BotAIBlocked(), BotAimAtEnemy(), BotCanAndWantsToRocketJump(), BotEntityVisible(), BotFindEnemy(), BotInLavaOrSlime(), BotIntermission(), BotIsDead(), BotIsObserver(), BotMapScripts(), BotNearbyGoal(), BotSetupForMovement(), BotUpdateBattleInventory(), BotWantsToRetreat(), bot_state_s::chase_time, bot_state_s::check_time, bot_state_s::enemy, bot_state_s::entitynum, bot_goal_s::entitynum, bot_state_s::eye, bot_moveresult_s::failure, bot_moveresult_s::flags, bot_state_s::flags, FloatTime, bot_moveresult_s::ideal_viewangles, bot_state_s::ideal_viewangles, vmCvar_t::integer, bot_state_s::lastenemyareanum, bot_state_s::lastenemyorigin, bot_state_s::ltg_time, bot_goal_s::maxs, bot_goal_s::mins, bot_moveresult_s::movedir, MOVERESULT_MOVEMENTVIEW, MOVERESULT_MOVEMENTVIEWSET, bot_state_s::ms, bot_state_s::nbg_time, bot_goal_s::origin, bot_state_s::origin, qfalse, range, bot_state_s::tfl, TFL_LAVA, trap_BotMovementViewTarget(), trap_BotMoveToGoal(), trap_BotResetAvoidReach(), trap_BotResetLastAvoidReach(), trap_BotTouchingGoal(), vec3_t, vectoangles(), VectorCopy, VectorSet, VectorSubtract, bot_state_s::viewangles, bot_moveresult_s::weapon, and bot_state_s::weaponnum.

02152 {
02153     bot_goal_t goal;
02154     vec3_t target, dir;
02155     bot_moveresult_t moveresult;
02156     float range;
02157 
02158     if (BotIsObserver(bs)) {
02159         AIEnter_Observer(bs, "battle chase: observer");
02160         return qfalse;
02161     }
02162     //if in the intermission
02163     if (BotIntermission(bs)) {
02164         AIEnter_Intermission(bs, "battle chase: intermission");
02165         return qfalse;
02166     }
02167     //respawn if dead
02168     if (BotIsDead(bs)) {
02169         AIEnter_Respawn(bs, "battle chase: bot dead");
02170         return qfalse;
02171     }
02172     //if no enemy
02173     if (bs->enemy < 0) {
02174         AIEnter_Seek_LTG(bs, "battle chase: no enemy");
02175         return qfalse;
02176     }
02177     //if the enemy is visible
02178     if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
02179         AIEnter_Battle_Fight(bs, "battle chase");
02180         return qfalse;
02181     }
02182     //if there is another enemy
02183     if (BotFindEnemy(bs, -1)) {
02184         AIEnter_Battle_Fight(bs, "battle chase: better enemy");
02185         return qfalse;
02186     }
02187     //there is no last enemy area
02188     if (!bs->lastenemyareanum) {
02189         AIEnter_Seek_LTG(bs, "battle chase: no enemy area");
02190         return qfalse;
02191     }
02192     //
02193     bs->tfl = TFL_DEFAULT;
02194     if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
02195     //if in lava or slime the bot should be able to get out
02196     if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
02197     //
02198     if (BotCanAndWantsToRocketJump(bs)) {
02199         bs->tfl |= TFL_ROCKETJUMP;
02200     }
02201     //map specific code
02202     BotMapScripts(bs);
02203     //create the chase goal
02204     goal.entitynum = bs->enemy;
02205     goal.areanum = bs->lastenemyareanum;
02206     VectorCopy(bs->lastenemyorigin, goal.origin);
02207     VectorSet(goal.mins, -8, -8, -8);
02208     VectorSet(goal.maxs, 8, 8, 8);
02209     //if the last seen enemy spot is reached the enemy could not be found
02210     if (trap_BotTouchingGoal(bs->origin, &goal)) bs->chase_time = 0;
02211     //if there's no chase time left
02212     if (!bs->chase_time || bs->chase_time < FloatTime() - 10) {
02213         AIEnter_Seek_LTG(bs, "battle chase: time out");
02214         return qfalse;
02215     }
02216     //check for nearby goals periodicly
02217     if (bs->check_time < FloatTime()) {
02218         bs->check_time = FloatTime() + 1;
02219         range = 150;
02220         //
02221         if (BotNearbyGoal(bs, bs->tfl, &goal, range)) {
02222             //the bot gets 5 seconds to pick up the nearby goal item
02223             bs->nbg_time = FloatTime() + 0.1 * range + 1;
02224             trap_BotResetLastAvoidReach(bs->ms);
02225             AIEnter_Battle_NBG(bs, "battle chase: nbg");
02226             return qfalse;
02227         }
02228     }
02229     //
02230     BotUpdateBattleInventory(bs, bs->enemy);
02231     //initialize the movement state
02232     BotSetupForMovement(bs);
02233     //move towards the goal
02234     trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
02235     //if the movement failed
02236     if (moveresult.failure) {
02237         //reset the avoid reach, otherwise bot is stuck in current area
02238         trap_BotResetAvoidReach(bs->ms);
02239         //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
02240         bs->ltg_time = 0;
02241     }
02242     //
02243     BotAIBlocked(bs, &moveresult, qfalse);
02244     //
02245     if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET|MOVERESULT_MOVEMENTVIEW|MOVERESULT_SWIMVIEW)) {
02246         VectorCopy(moveresult.ideal_viewangles, bs->ideal_viewangles);
02247     }
02248     else if (!(bs->flags & BFL_IDEALVIEWSET)) {
02249         if (bs->chase_time > FloatTime() - 2) {
02250             BotAimAtEnemy(bs);
02251         }
02252         else {
02253             if (trap_BotMovementViewTarget(bs->ms, &goal, bs->tfl, 300, target)) {
02254                 VectorSubtract(target, bs->origin, dir);
02255                 vectoangles(dir, bs->ideal_viewangles);
02256             }
02257             else {
02258                 vectoangles(moveresult.movedir, bs->ideal_viewangles);
02259             }
02260         }
02261         bs->ideal_viewangles[2] *= 0.5;
02262     }
02263     //if the weapon is used for the bot movement
02264     if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs->weaponnum = moveresult.weapon;
02265     //if the bot is in the area the enemy was last seen in
02266     if (bs->areanum == bs->lastenemyareanum) bs->chase_time = 0;
02267     //if the bot wants to retreat (the bot could have been damage during the chase)
02268     if (BotWantsToRetreat(bs)) {
02269         AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat");
02270         return qtrue;
02271     }
02272     return qtrue;
02273 }

Here is the call graph for this function:

int AINode_Battle_Fight bot_state_t bs  ) 
 

Definition at line 1986 of file ai_dmnet.c.

References aas_entityinfo_t, AIEnter_Battle_Chase(), AIEnter_Battle_Retreat(), AIEnter_Intermission(), AIEnter_Observer(), AIEnter_Respawn(), AIEnter_Seek_LTG(), AIEnter_Stand(), bot_grapple, bot_moveresult_t, bot_state_t, BotAI_Print(), BotAIBlocked(), BotAimAtEnemy(), BotAttackMove(), BotBattleUseItems(), BotCanAndWantsToRocketJump(), BotChat_EnemySuicide(), BotChat_HitNoDeath(), BotChat_HitNoKill(), BotChat_Kill(), BotChatTime(), BotCheckAttack(), BotChooseWeapon(), BotEntityInfo(), BotEntityVisible(), BotFindEnemy(), BotInLavaOrSlime(), BotIntermission(), BotIsDead(), BotIsObserver(), BotPointAreaNum(), BotUpdateBattleInventory(), BotWantsToChase(), BotWantsToRetreat(), bot_state_s::cur_ps, bot_state_s::enemy, bot_state_s::enemydeath_time, bot_state_s::enemysuicide, EntityIsDead(), EntityIsInvisible(), EntityIsShooting(), bot_state_s::entitynum, bot_state_s::eye, bot_moveresult_s::failure, bot_state_s::flags, FloatTime, vmCvar_t::integer, bot_state_s::inventory, bot_state_s::lastenemyareanum, bot_state_s::lastenemyorigin, bot_state_s::lastframe_health, bot_state_s::lasthitcount, bot_state_s::lastkilledplayer, bot_state_s::ltg_time, bot_state_s::ms, aas_entityinfo_s::origin, playerState_s::persistant, PRT_MESSAGE, qfalse, random, bot_state_s::stand_time, bot_state_s::tfl, TFL_LAVA, trap_AAS_AreaReachability(), trap_BotResetAvoidReach(), vec3_t, VectorCopy, and bot_state_s::viewangles.

01986                                          {
01987     int areanum;
01988     vec3_t target;
01989     aas_entityinfo_t entinfo;
01990     bot_moveresult_t moveresult;
01991 
01992     if (BotIsObserver(bs)) {
01993         AIEnter_Observer(bs, "battle fight: observer");
01994         return qfalse;
01995     }
01996 
01997     //if in the intermission
01998     if (BotIntermission(bs)) {
01999         AIEnter_Intermission(bs, "battle fight: intermission");
02000         return qfalse;
02001     }
02002     //respawn if dead
02003     if (BotIsDead(bs)) {
02004         AIEnter_Respawn(bs, "battle fight: bot dead");
02005         return qfalse;
02006     }
02007     //if there is another better enemy
02008     if (BotFindEnemy(bs, bs->enemy)) {
02009 #ifdef DEBUG
02010         BotAI_Print(PRT_MESSAGE, "found new better enemy\n");
02011 #endif
02012     }
02013     //if no enemy
02014     if (bs->enemy < 0) {
02015         AIEnter_Seek_LTG(bs, "battle fight: no enemy");
02016         return qfalse;
02017     }
02018     //
02019     BotEntityInfo(bs->enemy, &entinfo);
02020     //if the enemy is dead
02021     if (bs->enemydeath_time) {
02022         if (bs->enemydeath_time < FloatTime() - 1.0) {
02023             bs->enemydeath_time = 0;
02024             if (bs->enemysuicide) {
02025                 BotChat_EnemySuicide(bs);
02026             }
02027             if (bs->lastkilledplayer == bs->enemy && BotChat_Kill(bs)) {
02028                 bs->stand_time = FloatTime() + BotChatTime(bs);
02029                 AIEnter_Stand(bs, "battle fight: enemy dead");
02030             }
02031             else {
02032                 bs->ltg_time = 0;
02033                 AIEnter_Seek_LTG(bs, "battle fight: enemy dead");
02034             }
02035             return qfalse;
02036         }
02037     }
02038     else {
02039         if (EntityIsDead(&entinfo)) {
02040             bs->enemydeath_time = FloatTime();
02041         }
02042     }
02043     //if the enemy is invisible and not shooting the bot looses track easily
02044     if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
02045         if (random() < 0.2) {
02046             AIEnter_Seek_LTG(bs, "battle fight: invisible");
02047             return qfalse;
02048         }
02049     }
02050     //
02051     VectorCopy(entinfo.origin, target);
02052     // if not a player enemy
02053     if (bs->enemy >= MAX_CLIENTS) {
02054 #ifdef MISSIONPACK
02055         // if attacking an obelisk
02056         if ( bs->enemy == redobelisk.entitynum ||
02057             bs->enemy == blueobelisk.entitynum ) {
02058             target[2] += 16;
02059         }
02060 #endif
02061     }
02062     //update the reachability area and origin if possible
02063     areanum = BotPointAreaNum(target);
02064     if (areanum && trap_AAS_AreaReachability(areanum)) {
02065         VectorCopy(target, bs->lastenemyorigin);
02066         bs->lastenemyareanum = areanum;
02067     }
02068     //update the attack inventory values
02069     BotUpdateBattleInventory(bs, bs->enemy);
02070     //if the bot's health decreased
02071     if (bs->lastframe_health > bs->inventory[INVENTORY_HEALTH]) {
02072         if (BotChat_HitNoDeath(bs)) {
02073             bs->stand_time = FloatTime() + BotChatTime(bs);
02074             AIEnter_Stand(bs, "battle fight: chat health decreased");
02075             return qfalse;
02076         }
02077     }
02078     //if the bot hit someone
02079     if (bs->cur_ps.persistant[PERS_HITS] > bs->lasthitcount) {
02080         if (BotChat_HitNoKill(bs)) {
02081             bs->stand_time = FloatTime() + BotChatTime(bs);
02082             AIEnter_Stand(bs, "battle fight: chat hit someone");
02083             return qfalse;
02084         }
02085     }
02086     //if the enemy is not visible
02087     if (!BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
02088         if (BotWantsToChase(bs)) {
02089             AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight");
02090             return qfalse;
02091         }
02092         else {
02093             AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight");
02094             return qfalse;
02095         }
02096     }
02097     //use holdable items
02098     BotBattleUseItems(bs);
02099     //
02100     bs->tfl = TFL_DEFAULT;
02101     if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
02102     //if in lava or slime the bot should be able to get out
02103     if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
02104     //
02105     if (BotCanAndWantsToRocketJump(bs)) {
02106         bs->tfl |= TFL_ROCKETJUMP;
02107     }
02108     //choose the best weapon to fight with
02109     BotChooseWeapon(bs);
02110     //do attack movements
02111     moveresult = BotAttackMove(bs, bs->tfl);
02112     //if the movement failed
02113     if (moveresult.failure) {
02114         //reset the avoid reach, otherwise bot is stuck in current area
02115         trap_BotResetAvoidReach(bs->ms);
02116         //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
02117         bs->ltg_time = 0;
02118     }
02119     //
02120     BotAIBlocked(bs, &moveresult, qfalse);
02121     //aim at the enemy
02122     BotAimAtEnemy(bs);
02123     //attack the enemy if possible
02124     BotCheckAttack(bs);
02125     //if the bot wants to retreat
02126     if (!(bs->flags & BFL_FIGHTSUICIDAL)) {
02127         if (BotWantsToRetreat(bs)) {
02128             AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat");
02129             return qtrue;
02130         }
02131     }
02132     return qtrue;
02133 }

Here is the call graph for this function:

int AINode_Battle_NBG bot_state_t bs  ) 
 

Definition at line 2479 of file ai_dmnet.c.

References aas_entityinfo_t, AIEnter_Battle_Fight(), AIEnter_Battle_Retreat(), AIEnter_Intermission(), AIEnter_Observer(), AIEnter_Respawn(), AIEnter_Seek_NBG(), bot_goal_t, bot_grapple, bot_moveresult_t, bot_state_t, BotAIBlocked(), BotAimAtEnemy(), BotCanAndWantsToRocketJump(), BotCheckAttack(), BotChooseWeapon(), BotEntityInfo(), BotEntityVisible(), BotInLavaOrSlime(), BotIntermission(), BotIsDead(), BotIsObserver(), BotMapScripts(), BotPointAreaNum(), BotReachedGoal(), BotSetupForMovement(), BotUpdateBattleInventory(), bot_state_s::character, CHARACTERISTIC_ATTACK_SKILL, bot_state_s::enemy, bot_state_s::enemyvisible_time, EntityIsDead(), bot_state_s::entitynum, bot_state_s::eye, bot_moveresult_s::failure, bot_moveresult_s::flags, bot_state_s::flags, FloatTime, bot_state_s::gs, bot_moveresult_s::ideal_viewangles, bot_state_s::ideal_viewangles, vmCvar_t::integer, bot_state_s::lastenemyareanum, bot_state_s::lastenemyorigin, bot_moveresult_s::movedir, MOVERESULT_MOVEMENTVIEW, bot_state_s::ms, bot_state_s::nbg_time, aas_entityinfo_s::origin, bot_state_s::origin, qfalse, bot_state_s::tfl, TFL_LAVA, trap_AAS_AreaReachability(), trap_BotGetTopGoal(), trap_BotMovementViewTarget(), trap_BotMoveToGoal(), trap_BotPopGoal(), trap_BotResetAvoidReach(), trap_Characteristic_BFloat(), vec3_t, vectoangles(), VectorCopy, VectorSubtract, bot_state_s::viewangles, bot_moveresult_s::weapon, and bot_state_s::weaponnum.

02479                                        {
02480     int areanum;
02481     bot_goal_t goal;
02482     aas_entityinfo_t entinfo;
02483     bot_moveresult_t moveresult;
02484     float attack_skill;
02485     vec3_t target, dir;
02486 
02487     if (BotIsObserver(bs)) {
02488         AIEnter_Observer(bs, "battle nbg: observer");
02489         return qfalse;
02490     }
02491     //if in the intermission
02492     if (BotIntermission(bs)) {
02493         AIEnter_Intermission(bs, "battle nbg: intermission");
02494         return qfalse;
02495     }
02496     //respawn if dead
02497     if (BotIsDead(bs)) {
02498         AIEnter_Respawn(bs, "battle nbg: bot dead");
02499         return qfalse;
02500     }
02501     //if no enemy
02502     if (bs->enemy < 0) {
02503         AIEnter_Seek_NBG(bs, "battle nbg: no enemy");
02504         return qfalse;
02505     }
02506     //
02507     BotEntityInfo(bs->enemy, &entinfo);
02508     if (EntityIsDead(&entinfo)) {
02509         AIEnter_Seek_NBG(bs, "battle nbg: enemy dead");
02510         return qfalse;
02511     }
02512     //
02513     bs->tfl = TFL_DEFAULT;
02514     if (bot_grapple.integer) bs->tfl |= TFL_GRAPPLEHOOK;
02515     //if in lava or slime the bot should be able to get out
02516     if (BotInLavaOrSlime(bs)) bs->tfl |= TFL_LAVA|TFL_SLIME;
02517     //
02518     if (BotCanAndWantsToRocketJump(bs)) {
02519         bs->tfl |= TFL_ROCKETJUMP;
02520     }
02521     //map specific code
02522     BotMapScripts(bs);
02523     //update the last time the enemy was visible
02524     if (BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, bs->enemy)) {
02525         bs->enemyvisible_time = FloatTime();
02526         VectorCopy(entinfo.origin, target);
02527         // if not a player enemy
02528         if (bs->enemy >= MAX_CLIENTS) {
02529 #ifdef MISSIONPACK
02530             // if attacking an obelisk
02531             if ( bs->enemy == redobelisk.entitynum ||
02532                 bs->enemy == blueobelisk.entitynum ) {
02533                 target[2] += 16;
02534             }
02535 #endif
02536         }
02537         //update the reachability area and origin if possible
02538         areanum = BotPointAreaNum(target);
02539         if (areanum && trap_AAS_AreaReachability(areanum)) {
02540             VectorCopy(target, bs->lastenemyorigin);
02541             bs->lastenemyareanum = areanum;
02542         }
02543     }
02544     //if the bot has no goal or touches the current goal
02545     if (!trap_BotGetTopGoal(bs->gs, &goal)) {
02546         bs->nbg_time = 0;
02547     }
02548     else if (BotReachedGoal(bs, &goal)) {
02549         bs->nbg_time = 0;
02550     }
02551     //
02552     if (bs->nbg_time < FloatTime()) {
02553         //pop the current goal from the stack
02554         trap_BotPopGoal(bs->gs);
02555         //if the bot still has a goal
02556         if (trap_BotGetTopGoal(bs->gs, &goal))
02557             AIEnter_Battle_Retreat(bs, "battle nbg: time out");
02558         else
02559             AIEnter_Battle_Fight(bs, "battle nbg: time out");
02560         //
02561         return qfalse;
02562     }
02563     //initialize the movement state
02564     BotSetupForMovement(bs);
02565     //move towards the goal
02566     trap_BotMoveToGoal(&moveresult, bs->ms, &goal, bs->tfl);
02567     //if the movement failed
02568     if (moveresult.failure) {
02569         //reset the avoid reach, otherwise bot is stuck in current area
02570         trap_BotResetAvoidReach(bs->ms);
02571         //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
02572         bs->nbg_time = 0;
02573     }
02574