codemp/game/ai_main.h File Reference

#include "bg_saga.h"
#include "../namespace_begin.h"
#include "../namespace_end.h"

Go to the source code of this file.

Data Structures

struct  bot_state_s
struct  botattachment_s
struct  boteventtracker_s
struct  botskills_s
struct  nodeobject_s

Defines

#define DEFAULT_FORCEPOWERS   "5-1-000000000000000000"
#define MAX_CHAT_BUFFER_SIZE   8192
#define MAX_CHAT_LINE_SIZE   128
#define TABLE_BRANCH_DISTANCE   32
#define MAX_NODETABLE_SIZE   16384
#define MAX_LOVED_ONES   4
#define MAX_ATTACHMENT_NAME   64
#define MAX_FORCE_INFO_SIZE   2048
#define WPFLAG_JUMP   0x00000010
#define WPFLAG_DUCK   0x00000020
#define WPFLAG_NOVIS   0x00000400
#define WPFLAG_SNIPEORCAMPSTAND   0x00000800
#define WPFLAG_WAITFORFUNC   0x00001000
#define WPFLAG_SNIPEORCAMP   0x00002000
#define WPFLAG_ONEWAY_FWD   0x00004000
#define WPFLAG_ONEWAY_BACK   0x00008000
#define WPFLAG_GOALPOINT   0x00010000
#define WPFLAG_RED_FLAG   0x00020000
#define WPFLAG_BLUE_FLAG   0x00040000
#define WPFLAG_SIEGE_REBELOBJ   0x00080000
#define WPFLAG_SIEGE_IMPERIALOBJ   0x00100000
#define WPFLAG_NOMOVEFUNC   0x00200000
#define WPFLAG_CALCULATED   0x00400000
#define WPFLAG_NEVERONEWAY   0x00800000
#define LEVELFLAG_NOPOINTPREDICTION   1
#define LEVELFLAG_IGNOREINFALLBACK   2
#define LEVELFLAG_IMUSTNTRUNAWAY   4
#define WP_KEEP_FLAG_DIST   128
#define BWEAPONRANGE_MELEE   1
#define BWEAPONRANGE_MID   2
#define BWEAPONRANGE_LONG   3
#define BWEAPONRANGE_SABER   4
#define MELEE_ATTACK_RANGE   256
#define SABER_ATTACK_RANGE   128
#define MAX_CHICKENWUSS_TIME   10000
#define BOT_RUN_HEALTH   40
#define BOT_WPTOUCH_DISTANCE   32
#define ENEMY_FORGET_MS   10000
#define BOT_PLANT_DISTANCE   256
#define BOT_PLANT_INTERVAL   15000
#define BOT_PLANT_BLOW_DISTANCE   256
#define BOT_MAX_WEAPON_GATHER_TIME   1000
#define BOT_MAX_WEAPON_CHASE_TIME   15000
#define BOT_MAX_WEAPON_CHASE_CTF   5000
#define BOT_MIN_SIEGE_GOAL_SHOOT   1024
#define BOT_MIN_SIEGE_GOAL_TRAVEL   128
#define BASE_GUARD_DISTANCE   256
#define BASE_FLAGWAIT_DISTANCE   256
#define BASE_GETENEMYFLAG_DISTANCE   256
#define BOT_FLAG_GET_DISTANCE   256
#define BOT_SABER_THROW_RANGE   800
#define FloatTime()   floattime

Typedefs

typedef botattachment_s botattachment_t
typedef nodeobject_s nodeobject_t
typedef boteventtracker_s boteventtracker_t
typedef botskills_s botskills_t
typedef bot_state_s bot_state_t

Enumerations

enum  bot_ctf_state_t {
  CTFSTATE_NONE, CTFSTATE_ATTACKER, CTFSTATE_DEFENDER, CTFSTATE_RETRIEVAL,
  CTFSTATE_GUARDCARRIER, CTFSTATE_GETFLAGHOME, CTFSTATE_MAXCTFSTATES
}
enum  bot_siege_state_t { SIEGESTATE_NONE, SIEGESTATE_ATTACKER, SIEGESTATE_DEFENDER, SIEGESTATE_MAXSIEGESTATES }
enum  bot_teamplay_state_t {
  TEAMPLAYSTATE_NONE, TEAMPLAYSTATE_FOLLOWING, TEAMPLAYSTATE_ASSISTING, TEAMPLAYSTATE_REGROUP,
  TEAMPLAYSTATE_MAXTPSTATES
}

Functions

void * B_TempAlloc (int size)
void B_TempFree (int size)
void * B_Alloc (int size)
void B_Free (void *ptr)
void BotResetState (bot_state_t *bs)
int NumBots (void)
void BotUtilizePersonality (bot_state_t *bs)
int BotDoChat (bot_state_t *bs, char *section, int always)
void StandardBotAI (bot_state_t *bs, float thinktime)
void BotWaypointRender (void)
int OrgVisibleBox (vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore)
int BotIsAChickenWuss (bot_state_t *bs)
int GetNearestVisibleWP (vec3_t org, int ignore)
int GetBestIdleGoal (bot_state_t *bs)
char * ConcatArgs (int start)

Variables

vmCvar_t bot_forcepowers
vmCvar_t bot_forgimmick
vmCvar_t bot_honorableduelacceptance
vmCvar_t bot_attachments
vmCvar_t bot_camp
vmCvar_t bot_wp_info
vmCvar_t bot_wp_edit
vmCvar_t bot_wp_clearweight
vmCvar_t bot_wp_distconnect
vmCvar_t bot_wp_visconnect
wpobject_tflagRed
wpobject_toFlagRed
wpobject_tflagBlue
wpobject_toFlagBlue
gentity_teFlagRed
gentity_teFlagBlue
char gBotChatBuffer [MAX_CLIENTS][MAX_CHAT_BUFFER_SIZE]
float gWPRenderTime
float gDeactivated
float gBotEdit
int gWPRenderedFrame
wpobject_tgWPArray [MAX_WPARRAY_SIZE]
int gWPNum
int gLastPrintedIndex
nodeobject_t nodetable [MAX_NODETABLE_SIZE]
int nodenum
int gLevelFlags
float floattime


Define Documentation

#define BASE_FLAGWAIT_DISTANCE   256
 

Definition at line 74 of file ai_main.h.

Referenced by BotGetFlagHome().

#define BASE_GETENEMYFLAG_DISTANCE   256
 

Definition at line 75 of file ai_main.h.

Referenced by BotGetEnemyFlag().

#define BASE_GUARD_DISTANCE   256
 

Definition at line 73 of file ai_main.h.

Referenced by BotDefendFlag().

#define BOT_FLAG_GET_DISTANCE   256
 

Definition at line 77 of file ai_main.h.

Referenced by CTFFlagMovement().

#define BOT_MAX_WEAPON_CHASE_CTF   5000
 

Definition at line 68 of file ai_main.h.

Referenced by CTFTakesPriority().

#define BOT_MAX_WEAPON_CHASE_TIME   15000
 

Definition at line 66 of file ai_main.h.

Referenced by SiegeTakesPriority().

#define BOT_MAX_WEAPON_GATHER_TIME   1000
 

Definition at line 65 of file ai_main.h.

Referenced by CTFTakesPriority(), and SiegeTakesPriority().

#define BOT_MIN_SIEGE_GOAL_SHOOT   1024
 

Definition at line 70 of file ai_main.h.

Referenced by Siege_TargetClosestObjective().

#define BOT_MIN_SIEGE_GOAL_TRAVEL   128
 

Definition at line 71 of file ai_main.h.

Referenced by Siege_TargetClosestObjective().

#define BOT_PLANT_BLOW_DISTANCE   256
 

Definition at line 63 of file ai_main.h.

Referenced by BotCheckDetPacks().

#define BOT_PLANT_DISTANCE   256
 

Definition at line 61 of file ai_main.h.

Referenced by StandardBotAI().

#define BOT_PLANT_INTERVAL   15000
 

Definition at line 62 of file ai_main.h.

Referenced by StandardBotAI().

#define BOT_RUN_HEALTH   40
 

Definition at line 55 of file ai_main.h.

Referenced by BotIsAChickenWuss().

#define BOT_SABER_THROW_RANGE   800
 

Definition at line 79 of file ai_main.h.

Referenced by StandardBotAI().

#define BOT_WPTOUCH_DISTANCE   32
 

Definition at line 56 of file ai_main.h.

Referenced by StandardBotAI().

#define BWEAPONRANGE_LONG   3
 

Definition at line 48 of file ai_main.h.

Referenced by BotGetWeaponRange(), GetIdealDestination(), and StandardBotAI().

#define BWEAPONRANGE_MELEE   1
 

Definition at line 46 of file ai_main.h.

Referenced by BotGetWeaponRange(), BotIsAChickenWuss(), BotTrace_Jump(), CombatBotAI(), GetIdealDestination(), Siege_TargetClosestObjective(), and StandardBotAI().

#define BWEAPONRANGE_MID   2
 

Definition at line 47 of file ai_main.h.

Referenced by BotGetWeaponRange(), GetIdealDestination(), and StandardBotAI().

#define BWEAPONRANGE_SABER   4
 

Definition at line 49 of file ai_main.h.

Referenced by BotGetWeaponRange(), BotIsAChickenWuss(), BotTrace_Jump(), CombatBotAI(), GetIdealDestination(), Siege_TargetClosestObjective(), and StandardBotAI().

#define DEFAULT_FORCEPOWERS   "5-1-000000000000000000"
 

Definition at line 3 of file ai_main.h.

#define ENEMY_FORGET_MS   10000
 

Definition at line 57 of file ai_main.h.

Referenced by BotDamageNotification(), GetNearestBadThing(), and StandardBotAI().

 
#define FloatTime  )     floattime
 

Definition at line 411 of file ai_main.h.

Referenced by BotAIRegularUpdate(), and BotAISetupClient().

#define LEVELFLAG_IGNOREINFALLBACK   2
 

Definition at line 41 of file ai_main.h.

Referenced by PassStandardEnemyChecks().

#define LEVELFLAG_IMUSTNTRUNAWAY   4
 

Definition at line 42 of file ai_main.h.

Referenced by BotIsAChickenWuss().

#define LEVELFLAG_NOPOINTPREDICTION   1
 

Definition at line 40 of file ai_main.h.

Referenced by LoadPath_ThisLevel(), and StandardBotAI().

#define MAX_ATTACHMENT_NAME   64
 

Definition at line 18 of file ai_main.h.

#define MAX_CHAT_BUFFER_SIZE   8192
 

Definition at line 10 of file ai_main.h.

Referenced by BotDoChat(), BotUtilizePersonality(), and ReadChatGroups().

#define MAX_CHAT_LINE_SIZE   128
 

Definition at line 12 of file ai_main.h.

Referenced by BotDoChat().

#define MAX_CHICKENWUSS_TIME   10000
 

Definition at line 53 of file ai_main.h.

Referenced by BotIsAChickenWuss().

#define MAX_FORCE_INFO_SIZE   2048
 

Definition at line 20 of file ai_main.h.

#define MAX_LOVED_ONES   4
 

Definition at line 17 of file ai_main.h.

Referenced by ParseEmotionalAttachments().

#define MAX_NODETABLE_SIZE   16384
 

Definition at line 15 of file ai_main.h.

Referenced by ConnectTrail(), and G_RMGPathing().

#define MELEE_ATTACK_RANGE   256
 

Definition at line 51 of file ai_main.h.

Referenced by CombatBotAI(), and StandardBotAI().

#define SABER_ATTACK_RANGE   128
 

Definition at line 52 of file ai_main.h.

Referenced by CombatBotAI(), and StandardBotAI().

#define TABLE_BRANCH_DISTANCE   32
 

Definition at line 14 of file ai_main.h.

Referenced by ConnectTrail().

#define WP_KEEP_FLAG_DIST   128
 

Definition at line 44 of file ai_main.h.

Referenced by GetNewFlagPoint().

#define WPFLAG_BLUE_FLAG   0x00040000
 

Definition at line 32 of file ai_main.h.

Referenced by CreateNewWP_FromObject(), FlagObjects(), GetFlagStr(), PassWayCheck(), and StandardBotAI().

#define WPFLAG_CALCULATED   0x00400000
 

Definition at line 37 of file ai_main.h.

Referenced by ConnectTrail(), and RepairPaths().

#define WPFLAG_DUCK   0x00000020
 

Definition at line 23 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), and WPConstantRoutine().

#define WPFLAG_GOALPOINT   0x00010000
 

Definition at line 30 of file ai_main.h.

Referenced by AcceptBotCommand(), CalculateWeightGoals(), GetBestIdleGoal(), and GetFlagStr().

#define WPFLAG_JUMP   0x00000010
 

Definition at line 22 of file ai_main.h.

Referenced by AcceptBotCommand(), CalculateJumpRoutes(), GetFlagStr(), RepairPaths(), WPConstantRoutine(), and WPTouchRoutine().

#define WPFLAG_NEVERONEWAY   0x00800000
 

Definition at line 38 of file ai_main.h.

Referenced by ConnectTrail(), and G_RMGPathing().

#define WPFLAG_NOMOVEFUNC   0x00200000
 

Definition at line 35 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), StandardBotAI(), and WPTouchRoutine().

#define WPFLAG_NOVIS   0x00000400
 

Definition at line 24 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), RepairPaths(), and StandardBotAI().

#define WPFLAG_ONEWAY_BACK   0x00008000
 

Definition at line 29 of file ai_main.h.

Referenced by AcceptBotCommand(), ConnectTrail(), GetFlagStr(), OpposingEnds(), PassWayCheck(), and TotalTrailDistance().

#define WPFLAG_ONEWAY_FWD   0x00004000
 

Definition at line 28 of file ai_main.h.

Referenced by AcceptBotCommand(), ConnectTrail(), GetFlagStr(), OpposingEnds(), PassWayCheck(), and TotalTrailDistance().

#define WPFLAG_RED_FLAG   0x00020000
 

Definition at line 31 of file ai_main.h.

Referenced by CreateNewWP_FromObject(), FlagObjects(), GetFlagStr(), PassWayCheck(), and StandardBotAI().

#define WPFLAG_SIEGE_IMPERIALOBJ   0x00100000
 

Definition at line 34 of file ai_main.h.

Referenced by CalculateSiegeGoals(), GetFlagStr(), and SiegeTakesPriority().

#define WPFLAG_SIEGE_REBELOBJ   0x00080000
 

Definition at line 33 of file ai_main.h.

Referenced by CalculateSiegeGoals(), GetFlagStr(), and SiegeTakesPriority().

#define WPFLAG_SNIPEORCAMP   0x00002000
 

Definition at line 27 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), and WPTouchRoutine().

#define WPFLAG_SNIPEORCAMPSTAND   0x00000800
 

Definition at line 25 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), and WPTouchRoutine().

#define WPFLAG_WAITFORFUNC   0x00001000
 

Definition at line 26 of file ai_main.h.

Referenced by AcceptBotCommand(), GetFlagStr(), and StandardBotAI().


Typedef Documentation

typedef struct bot_state_s bot_state_t
 

Referenced by AltFiring(), Bot_SetForcedMovement(), BotAI(), BotAimLeading(), BotAimOffsetGoalAngles(), BotAISetupClient(), BotAIShutdownClient(), BotCanHear(), BotChangeViewAngles(), BotCheckDetPacks(), BotCTFGuardDuty(), BotDamageNotification(), BotDeathNotify(), BotDefendFlag(), BotDoChat(), BotDoTeamplayAI(), BotFallbackNavigation(), BotGetEnemyFlag(), BotGetFlagBack(), BotGetFlagHome(), BotGetWeaponRange(), BotGuardFlagCarrier(), BotHasAssociated(), BotIsAChickenWuss(), BotLovedOneDied(), BotReplyGreetings(), BotReportStatus(), BotResetState(), BotScanForLeader(), BotSelectChoiceWeapon(), BotSelectIdealWeapon(), BotSelectMelee(), BotStraightTPOrderCheck(), BotSurfaceNear(), BotTrace_Duck(), BotTrace_Jump(), BotTrace_Strafe(), BotTryAnotherWeapon(), BotUpdateInput(), BotUseInventoryItem(), BotUtilizePersonality(), BotWeaponCanLead(), BotWeaponSelectable(), CheckForFriendInLOF(), CheckForShorterRoutes(), CombatBotAI(), CommanderBotAI(), CommanderBotCTFAI(), CommanderBotSiegeAI(), CommanderBotTeamplayAI(), CTFFlagMovement(), CTFTakesPriority(), GetBestIdleGoal(), GetIdealDestination(), GetLoveLevel(), GetNearestBadThing(), JMTakesPriority(), KeepAltFromFiring(), KeepPrimFromFiring(), MeleeCombatHandling(), MoveTowardIdealAngles(), ParseEmotionalAttachments(), PassLovedOneCheck(), PassStandardEnemyChecks(), PassWayCheck(), PrimFiring(), ReadChatGroups(), SaberCombatHandling(), ScanForEnemies(), ShouldSecondaryFire(), Siege_CountDefenders(), Siege_CountTeammates(), Siege_DefendFromAttackers(), Siege_TargetClosestObjective(), SiegeTakesPriority(), StandardBotAI(), StrafeTracing(), TotalTrailDistance(), WaitingForNow(), WPConstantRoutine(), and WPTouchRoutine().

typedef struct botattachment_s botattachment_t
 

typedef struct boteventtracker_s boteventtracker_t
 

typedef struct botskills_s botskills_t
 

typedef struct nodeobject_s nodeobject_t
 


Enumeration Type Documentation

enum bot_ctf_state_t
 

Enumeration values:
CTFSTATE_NONE 
CTFSTATE_ATTACKER 
CTFSTATE_DEFENDER 
CTFSTATE_RETRIEVAL 
CTFSTATE_GUARDCARRIER 
CTFSTATE_GETFLAGHOME 
CTFSTATE_MAXCTFSTATES 

Definition at line 81 of file ai_main.h.

enum bot_siege_state_t
 

Enumeration values:
SIEGESTATE_NONE 
SIEGESTATE_ATTACKER 
SIEGESTATE_DEFENDER 
SIEGESTATE_MAXSIEGESTATES 

Definition at line 92 of file ai_main.h.

enum bot_teamplay_state_t
 

Enumeration values:
TEAMPLAYSTATE_NONE 
TEAMPLAYSTATE_FOLLOWING 
TEAMPLAYSTATE_ASSISTING 
TEAMPLAYSTATE_REGROUP 
TEAMPLAYSTATE_MAXTPSTATES 

Definition at line 100 of file ai_main.h.


Function Documentation

void* B_Alloc int  size  ) 
 

Definition at line 25 of file ai_util.c.

References BG_Alloc(), G_Printf(), and NULL.

Referenced by BotAISetupClient(), CreateNewWP(), CreateNewWP_FromObject(), CreateNewWP_InsertUnder(), CreateNewWP_InTrail(), and TransferWPData().

00026 {
00027 #ifdef BOT_ZMALLOC
00028         void *ptr = NULL;
00029         int i = 0;
00030 
00031 #ifdef BOTMEMTRACK
00032         int free = 0;
00033         int used = 0;
00034 
00035         while (i < MAX_BALLOC)
00036         {
00037                 if (!BAllocList[i])
00038                 {
00039                         free++;
00040                 }
00041                 else
00042                 {
00043                         used++;
00044                 }
00045 
00046                 i++;
00047         }
00048 
00049         G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00050 
00051         i = 0;
00052 #endif
00053 
00054         ptr = trap_BotGetMemoryGame(size);
00055 
00056         while (i < MAX_BALLOC)
00057         {
00058                 if (!BAllocList[i])
00059                 {
00060                         BAllocList[i] = ptr;
00061                         break;
00062                 }
00063                 i++;
00064         }
00065 
00066         if (i == MAX_BALLOC)
00067         {
00068                 //If this happens we'll have to rely on this chunk being freed manually with B_Free, which it hopefully will be
00069 #ifdef DEBUG
00070                 G_Printf("WARNING: MAXIMUM B_ALLOC ALLOCATIONS EXCEEDED\n");
00071 #endif
00072         }
00073 
00074         return ptr;
00075 #else
00076 
00077         return BG_Alloc(size);
00078 
00079 #endif
00080 }

void B_Free void *  ptr  ) 
 

Definition at line 82 of file ai_util.c.

References G_Printf(), and NULL.

00083 {
00084 #ifdef BOT_ZMALLOC
00085         int i = 0;
00086 
00087 #ifdef BOTMEMTRACK
00088         int free = 0;
00089         int used = 0;
00090 
00091         while (i < MAX_BALLOC)
00092         {
00093                 if (!BAllocList[i])
00094                 {
00095                         free++;
00096                 }
00097                 else
00098                 {
00099                         used++;
00100                 }
00101 
00102                 i++;
00103         }
00104 
00105         G_Printf("Allocations used: %i\nFree allocation slots: %i\n", used, free);
00106 
00107         i = 0;
00108 #endif
00109 
00110         while (i < MAX_BALLOC)
00111         {
00112                 if (BAllocList[i] == ptr)
00113                 {
00114                         BAllocList[i] = NULL;
00115                         break;
00116                 }
00117 
00118                 i++;
00119         }
00120 
00121         if (i == MAX_BALLOC)
00122         {
00123                 //Likely because the limit was exceeded and we're now freeing the chunk manually as we hoped would happen
00124 #ifdef DEBUG
00125                 G_Printf("WARNING: Freeing allocation which is not in the allocation structure\n");
00126 #endif
00127         }
00128 
00129         trap_BotFreeMemoryGame(ptr);
00130 #endif
00131 }

void* B_TempAlloc int  size  ) 
 

Definition at line 14 of file ai_util.c.

References BG_TempAlloc().

Referenced by BotDoChat(), BotUtilizePersonality(), GetFlagStr(), LoadPathData(), and SavePathData().

00015 {
00016         return BG_TempAlloc(size);
00017 }

void B_TempFree int  size  ) 
 

Definition at line 19 of file ai_util.c.

References BG_TempFree().

Referenced by BotDoChat(), BotUtilizePersonality(), BotWaypointRender(), LoadPathData(), and SavePathData().

00020 {
00021         BG_TempFree(size);
00022 }

int BotDoChat bot_state_t bs,
char *  section,
int  always
 

Definition at line 328 of file ai_util.c.

References B_TempAlloc(), B_TempFree(), bot_state_t, bot_state_s::canChat, bot_state_s::chatAltObject, bot_state_s::chatFrequency, bot_state_s::chatObject, bot_state_s::chatTeam, bot_state_s::chatTime, bot_state_s::chatTime_stored, bot_state_s::client, gentity_s::client, bot_state_s::currentChat, bot_state_s::doChat, gBotChatBuffer, gentity_t, GetValueGroup(), level, MAX_CHAT_BUFFER_SIZE, MAX_CHAT_LINE_SIZE, clientPersistant_t::netname, NULL, gclient_s::pers, Q_irand(), strcmp(), strlen(), level_locals_t::time, and trap_Cvar_VariableIntegerValue().

Referenced by BotAISetupClient(), BotLovedOneDied(), BotOrder(), BotReplyGreetings(), and StandardBotAI().

00329 {
00330         char *chatgroup;
00331         int rVal;
00332         int inc_1;
00333         int inc_2;
00334         int inc_n;
00335         int lines;
00336         int checkedline;
00337         int getthisline;
00338         gentity_t *cobject;
00339 
00340         if (!bs->canChat)
00341         {
00342                 return 0;
00343         }
00344 
00345         if (bs->doChat)
00346         { //already have a chat scheduled
00347                 return 0;
00348         }
00349 
00350         if (trap_Cvar_VariableIntegerValue("se_language"))
00351         { //no chatting unless English.
00352                 return 0;
00353         }
00354 
00355         if (Q_irand(1, 10) > bs->chatFrequency && !always)
00356         {
00357                 return 0;
00358         }
00359 
00360         bs->chatTeam = 0;
00361 
00362         chatgroup = (char *)B_TempAlloc(MAX_CHAT_BUFFER_SIZE);
00363 
00364         rVal = GetValueGroup(gBotChatBuffer[bs->client], section, chatgroup);
00365 
00366         if (!rVal) //the bot has no group defined for the specified chat event
00367         {
00368                 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00369                 return 0;
00370         }
00371 
00372         inc_1 = 0;
00373         inc_2 = 2;
00374 
00375         while (chatgroup[inc_2] && chatgroup[inc_2] != '\0')
00376         {
00377                 if (chatgroup[inc_2] != 13 && chatgroup[inc_2] != 9)
00378                 {
00379                         chatgroup[inc_1] = chatgroup[inc_2];
00380                         inc_1++;
00381                 }
00382                 inc_2++;
00383         }
00384         chatgroup[inc_1] = '\0';
00385 
00386         inc_1 = 0;
00387 
00388         lines = 0;
00389 
00390         while (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00391         {
00392                 if (chatgroup[inc_1] == '\n')
00393                 {
00394                         lines++;
00395                 }
00396                 inc_1++;
00397         }
00398 
00399         if (!lines)
00400         {
00401                 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00402                 return 0;
00403         }
00404 
00405         getthisline = Q_irand(0, (lines+1));
00406 
00407         if (getthisline < 1)
00408         {
00409                 getthisline = 1;
00410         }
00411         if (getthisline > lines)
00412         {
00413                 getthisline = lines;
00414         }
00415 
00416         checkedline = 1;
00417 
00418         inc_1 = 0;
00419 
00420         while (checkedline != getthisline)
00421         {
00422                 if (chatgroup[inc_1] && chatgroup[inc_1] != '\0')
00423                 {
00424                         if (chatgroup[inc_1] == '\n')
00425                         {
00426                                 inc_1++;
00427                                 checkedline++;
00428                         }
00429                 }
00430 
00431                 if (checkedline == getthisline)
00432                 {
00433                         break;
00434                 }
00435 
00436                 inc_1++;
00437         }
00438 
00439         //we're at the starting position of the desired line here
00440         inc_2 = 0;
00441 
00442         while (chatgroup[inc_1] != '\n')
00443         {
00444                 chatgroup[inc_2] = chatgroup[inc_1];
00445                 inc_2++;
00446                 inc_1++;
00447         }
00448         chatgroup[inc_2] = '\0';
00449 
00450         //trap_EA_Say(bs->client, chatgroup);
00451         inc_1 = 0;
00452         inc_2 = 0;
00453 
00454         if (strlen(chatgroup) > MAX_CHAT_LINE_SIZE)
00455         {
00456                 B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00457                 return 0;
00458         }
00459 
00460         while (chatgroup[inc_1])
00461         {
00462                 if (chatgroup[inc_1] == '%' && chatgroup[inc_1+1] != '%')
00463                 {
00464                         inc_1++;
00465 
00466                         if (chatgroup[inc_1] == 's' && bs->chatObject)
00467                         {
00468                                 cobject = bs->chatObject;
00469                         }
00470                         else if (chatgroup[inc_1] == 'a' && bs->chatAltObject)
00471                         {
00472                                 cobject = bs->chatAltObject;
00473                         }
00474                         else
00475                         {
00476                                 cobject = NULL;
00477                         }
00478 
00479                         if (cobject && cobject->client)
00480                         {
00481                                 inc_n = 0;
00482 
00483                                 while (cobject->client->pers.netname[inc_n])
00484                                 {
00485                                         bs->currentChat[inc_2] = cobject->client->pers.netname[inc_n];
00486                                         inc_2++;
00487                                         inc_n++;
00488                                 }
00489                                 inc_2--; //to make up for the auto-increment below
00490                         }
00491                 }
00492                 else
00493                 {
00494                         bs->currentChat[inc_2] = chatgroup[inc_1];
00495                 }
00496                 inc_2++;
00497                 inc_1++;
00498         }
00499         bs->currentChat[inc_2] = '\0';
00500 
00501         if (strcmp(section, "GeneralGreetings") == 0)
00502         {
00503                 bs->doChat = 2;
00504         }
00505         else
00506         {
00507                 bs->doChat = 1;
00508         }
00509         bs->chatTime_stored = (strlen(bs->currentChat)*45)+Q_irand(1300, 1500);
00510         bs->chatTime = level.time + bs->chatTime_stored;
00511 
00512         B_TempFree(MAX_CHAT_BUFFER_SIZE); //chatgroup
00513 
00514         return 1;
00515 }

int BotIsAChickenWuss bot_state_t bs  ) 
 

Definition at line 2301 of file ai_main.c.

References BOT_RUN_HEALTH, bot_state_t, BotGetWeaponRange(), BWEAPONRANGE_MELEE, BWEAPONRANGE_SABER, bot_state_s::chickenWussCalculationTime, bot_state_s::client, gentity_s::client, bot_state_s::cur_ps, bot_state_s::currentEnemy, playerState_s::electrifyTime, playerState_s::fd, forcedata_s::forcePowersActive, FP_RAGE, bot_state_s::frame_Enemy_Len, g_entities, g_gametype, gLevelFlags, GT_CTF, GT_JEDIMASTER, GT_SINGLE_PLAYER, gentity_s::health, vmCvar_t::integer, playerState_s::isJediMaster, level, LEVELFLAG_IMUSTNTRUNAWAY, MAX_CHICKENWUSS_TIME, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_REDFLAG, bot_state_s::saberSpecialist, level_locals_t::time, playerState_s::weapon, WP_BRYAR_PISTOL, WP_ROCKET_LAUNCHER, and WP_SABER.

Referenced by GetIdealDestination(), and WPTouchRoutine().

02302 {
02303         int bWRange;
02304 
02305         if (gLevelFlags & LEVELFLAG_IMUSTNTRUNAWAY)
02306         { //The level says we mustn't run away!
02307                 return 0;
02308         }
02309 
02310         if (g_gametype.integer == GT_SINGLE_PLAYER)
02311         { //"coop" (not really)
02312                 return 0;
02313         }
02314 
02315         if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster)
02316         { //Then you may know no fear.
02317                 //Well, unless he's strong.
02318                 if (bs->currentEnemy && bs->currentEnemy->client &&
02319                         bs->currentEnemy->client->ps.isJediMaster &&
02320                         bs->currentEnemy->health > 40 &&
02321                         bs->cur_ps.weapon < WP_ROCKET_LAUNCHER)
02322                 { //explosive weapons are most effective against the Jedi Master
02323                         goto jmPass;
02324                 }
02325                 return 0;
02326         }
02327 
02328         if (g_gametype.integer == GT_CTF && bs->currentEnemy && bs->currentEnemy->client)
02329         {
02330                 if (bs->currentEnemy->client->ps.powerups[PW_REDFLAG] ||
02331                         bs->currentEnemy->client->ps.powerups[PW_BLUEFLAG])
02332                 { //don't be afraid of flag carriers, they must die!
02333                         return 0;
02334                 }
02335         }
02336 
02337 jmPass:
02338         if (bs->chickenWussCalculationTime > level.time)
02339         {
02340                 return 2; //don't want to keep going between two points...
02341         }
02342 
02343         if (bs->cur_ps.fd.forcePowersActive & (1 << FP_RAGE))
02344         { //don't run while raging
02345                 return 0;
02346         }
02347 
02348         if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster)
02349         { //be frightened of the jedi master? I guess in this case.
02350                 return 1;
02351         }
02352 
02353         bs->chickenWussCalculationTime = level.time + MAX_CHICKENWUSS_TIME;
02354 
02355         if (g_entities[bs->client].health < BOT_RUN_HEALTH)
02356         { //we're low on health, let's get away
02357                 return 1;
02358         }
02359 
02360         bWRange = BotGetWeaponRange(bs);
02361 
02362         if (bWRange == BWEAPONRANGE_MELEE || bWRange == BWEAPONRANGE_SABER)
02363         {
02364                 if (bWRange != BWEAPONRANGE_SABER || !bs->saberSpecialist)
02365                 { //run away if we're using melee, or if we're using a saber and not a "saber specialist"
02366                         return 1;
02367                 }
02368         }
02369 
02370         if (bs->cur_ps.weapon == WP_BRYAR_PISTOL)
02371         { //the bryar is a weak weapon, so just try to find a new one if it's what you're having to use
02372                 return 1;
02373         }
02374 
02375         if (bs->currentEnemy && bs->currentEnemy->client &&
02376                 bs->currentEnemy->client->ps.weapon == WP_SABER &&
02377                 bs->frame_Enemy_Len < 512 && bs->cur_ps.weapon != WP_SABER)
02378         { //if close to an enemy with a saber and not using a saber, then try to back off
02379                 return 1;
02380         }
02381 
02382         if ((level.time-bs->cur_ps.electrifyTime) < 16000)
02383         { //lightning is dangerous.
02384                 return 1;
02385         }
02386 
02387         //didn't run, reset the timer
02388         bs->chickenWussCalculationTime = 0;
02389 
02390         return 0;
02391 }

void BotResetState bot_state_t bs  ) 
 

Definition at line 924 of file ai_main.c.

References bot_settings_t, bot_state_t, bot_state_s::client, client, bot_state_s::cur_ps, bot_state_s::entergame_time, bot_state_s::entitynum, bot_state_s::gs, bot_state_s::inuse, memcpy(), memset(), bot_state_s::ms, playerState_t, bot_state_s::settings, trap_BotResetAvoidGoals(), trap_BotResetAvoidReach(), trap_BotResetGoalState(), trap_BotResetMoveState(), trap_BotResetWeaponState(), and bot_state_s::ws.

Referenced by BotAILoadMap().

00924                                     {
00925         int client, entitynum, inuse;
00926         int movestate, goalstate, weaponstate;
00927         bot_settings_t settings;
00928         playerState_t ps;                                                       //current player state
00929         float entergame_time;
00930 
00931         //save some things that should not be reset here
00932         memcpy(&settings, &bs->settings, sizeof(bot_settings_t));
00933         memcpy(&ps, &bs->cur_ps, sizeof(playerState_t));
00934         inuse = bs->inuse;
00935         client = bs->client;
00936         entitynum = bs->entitynum;
00937         movestate = bs->ms;
00938         goalstate = bs->gs;
00939         weaponstate = bs->ws;
00940         entergame_time = bs->entergame_time;
00941         //reset the whole state
00942         memset(bs, 0, sizeof(bot_state_t));
00943         //copy back some state stuff that should not be reset
00944         bs->ms = movestate;
00945         bs->gs = goalstate;
00946         bs->ws = weaponstate;
00947         memcpy(&bs->cur_ps, &ps, sizeof(playerState_t));
00948         memcpy(&bs->settings, &settings, sizeof(bot_settings_t));
00949         bs->inuse = inuse;
00950         bs->client = client;
00951         bs->entitynum = entitynum;
00952         bs->entergame_time = entergame_time;
00953         //reset several states
00954         if (bs->ms) trap_BotResetMoveState(bs->ms);
00955         if (bs->gs) trap_BotResetGoalState(bs->gs);
00956         if (bs->ws) trap_BotResetWeaponState(bs->ws);
00957         if (bs->gs) trap_BotResetAvoidGoals(bs->gs);
00958         if (bs->ms) trap_BotResetAvoidReach(bs->ms);
00959 }

void BotUtilizePersonality bot_state_t bs  ) 
 

Definition at line 614 of file ai_util.c.

References botskills_s::accuracy, atof(), atoi(), B_TempAlloc(), B_TempFree(), bot_state_t, bot_state_s::botWeaponWeights, bot_state_s::canChat, bot_state_s::chatFrequency, bot_state_s::client, Com_sprintf(), DEFAULT_FORCEPOWERS, fileHandle_t, bot_state_s::forceinfo, FS_READ, G_Printf(), gBotChatBuffer, GetPairedValue(), GetValueGroup(), bot_state_s::isCamper, bot_state_s::loved_death_thresh, bot_state_s::lovednum, MAX_CHAT_BUFFER_SIZE, botskills_s::maxturn, ParseEmotionalAttachments(), botskills_s::perfectaim, bot_settings_s::personalityfile, ReadChatGroups(), botskills_s::reflex, S_COLOR_RED, bot_state_s::saberSpecialist, bot_state_s::settings, bot_state_s::skills, trap_FS_FCloseFile(), trap_FS_FOpenFile(), trap_FS_Read(), botskills_s::turnspeed, botskills_s::turnspeed_combat, WP_BLASTER, WP_BOWCASTER, WP_BRYAR_PISTOL, WP_DEMP2, WP_DET_PACK, WP_DISRUPTOR, WP_FLECHETTE, WP_MELEE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_STUN_BATON, WP_THERMAL, and WP_TRIP_MINE.

Referenced by BotAISetupClient().

00615 {
00616         fileHandle_t f;
00617         int len, rlen;
00618         int failed;
00619         int i;
00620         //char buf[131072];
00621         char *buf = (char *)B_TempAlloc(131072);
00622         char *readbuf, *group;
00623 
00624         len = trap_FS_FOpenFile(bs->settings.personalityfile, &f, FS_READ);
00625 
00626         failed = 0;
00627 
00628         if (!f)
00629         {
00630                 G_Printf(S_COLOR_RED "Error: Specified personality not found\n");
00631                 B_TempFree(131072); //buf
00632                 return;
00633         }
00634 
00635         if (len >= 131072)
00636         {
00637                 G_Printf(S_COLOR_RED "Personality file exceeds maximum length\n");
00638                 B_TempFree(131072); //buf
00639                 return;
00640         }
00641 
00642         trap_FS_Read(buf, len, f);
00643 
00644         rlen = len;
00645 
00646         while (len < 131072)
00647         { //kill all characters after the file length, since sometimes FS_Read doesn't do that entirely (or so it seems)
00648                 buf[len] = '\0';
00649                 len++;
00650         }
00651 
00652         len = rlen;
00653 
00654         readbuf = (char *)B_TempAlloc(1024);
00655         group = (char *)B_TempAlloc(65536);
00656 
00657         if (!GetValueGroup(buf, "GeneralBotInfo", group))
00658         {
00659                 G_Printf(S_COLOR_RED "Personality file contains no GeneralBotInfo group\n");
00660                 failed = 1; //set failed so we know to set everything to default values
00661         }
00662 
00663         if (!failed && GetPairedValue(group, "reflex", readbuf))
00664         {
00665                 bs->skills.reflex = atoi(readbuf);
00666         }
00667         else
00668         {
00669                 bs->skills.reflex = 100; //default
00670         }
00671 
00672         if (!failed && GetPairedValue(group, "accuracy", readbuf))
00673         {
00674                 bs->skills.accuracy = atof(readbuf);
00675         }
00676         else
00677         {
00678                 bs->skills.accuracy = 10; //default
00679         }
00680 
00681         if (!failed && GetPairedValue(group, "turnspeed", readbuf))
00682         {
00683                 bs->skills.turnspeed = atof(readbuf);
00684         }
00685         else
00686         {
00687                 bs->skills.turnspeed = 0.01f; //default
00688         }
00689 
00690         if (!failed && GetPairedValue(group, "turnspeed_combat", readbuf))
00691         {
00692                 bs->skills.turnspeed_combat = atof(readbuf);
00693         }
00694         else
00695         {
00696                 bs->skills.turnspeed_combat = 0.05f; //default
00697         }
00698 
00699         if (!failed && GetPairedValue(group, "maxturn", readbuf))
00700         {
00701                 bs->skills.maxturn = atof(readbuf);
00702         }
00703         else
00704         {
00705                 bs->skills.maxturn = 360; //default
00706         }
00707 
00708         if (!failed && GetPairedValue(group, "perfectaim", readbuf))
00709         {
00710                 bs->skills.perfectaim = atoi(readbuf);
00711         }
00712         else
00713         {
00714                 bs->skills.perfectaim = 0; //default
00715         }
00716 
00717         if (!failed && GetPairedValue(group, "chatability", readbuf))
00718         {
00719                 bs->canChat = atoi(readbuf);
00720         }
00721         else
00722         {
00723                 bs->canChat = 0; //default
00724         }
00725 
00726         if (!failed && GetPairedValue(group, "chatfrequency", readbuf))
00727         {
00728                 bs->chatFrequency = atoi(readbuf);
00729         }
00730         else
00731         {
00732                 bs->chatFrequency = 5; //default
00733         }
00734 
00735         if (!failed && GetPairedValue(group, "hatelevel", readbuf))
00736         {
00737                 bs->loved_death_thresh = atoi(readbuf);
00738         }
00739         else
00740         {
00741                 bs->loved_death_thresh = 3; //default
00742         }
00743 
00744         if (!failed && GetPairedValue(group, "camper", readbuf))
00745         {
00746                 bs->isCamper = atoi(readbuf);
00747         }
00748         else
00749         {
00750                 bs->isCamper = 0; //default
00751         }
00752 
00753         if (!failed && GetPairedValue(group, "saberspecialist", readbuf))
00754         {
00755                 bs->saberSpecialist = atoi(readbuf);
00756         }
00757         else
00758         {
00759                 bs->saberSpecialist = 0; //default
00760         }
00761 
00762         if (!failed && GetPairedValue(group, "forceinfo", readbuf))
00763         {
00764                 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", readbuf);
00765         }
00766         else
00767         {
00768                 Com_sprintf(bs->forceinfo, sizeof(bs->forceinfo), "%s\0", DEFAULT_FORCEPOWERS);
00769         }
00770 
00771         i = 0;
00772 
00773         while (i < MAX_CHAT_BUFFER_SIZE)
00774         { //clear out the chat buffer for this bot
00775                 gBotChatBuffer[bs->client][i] = '\0';
00776                 i++;
00777         }
00778 
00779         if (bs->canChat)
00780         {
00781                 if (!ReadChatGroups(bs, buf))
00782                 {
00783                         bs->canChat = 0;
00784                 }
00785         }
00786 
00787         if (GetValueGroup(buf, "BotWeaponWeights", group))
00788         {
00789                 if (GetPairedValue(group, "WP_STUN_BATON", readbuf))
00790                 {
00791                         bs->botWeaponWeights[WP_STUN_BATON] = atoi(readbuf);
00792                         bs->botWeaponWeights[WP_MELEE] = bs->botWeaponWeights[WP_STUN_BATON];
00793                 }
00794 
00795                 if (GetPairedValue(group, "WP_SABER", readbuf))
00796                 {
00797                         bs->botWeaponWeights[WP_SABER] = atoi(readbuf);
00798                 }
00799 
00800                 if (GetPairedValue(group, "WP_BRYAR_PISTOL", readbuf))
00801                 {
00802                         bs->botWeaponWeights[WP_BRYAR_PISTOL] = atoi(readbuf);
00803                 }
00804 
00805                 if (GetPairedValue(group, "WP_BLASTER", readbuf))
00806                 {
00807                         bs->botWeaponWeights[WP_BLASTER] = atoi(readbuf);
00808                 }
00809 
00810                 if (GetPairedValue(group, "WP_DISRUPTOR", readbuf))
00811                 {
00812                         bs->botWeaponWeights[WP_DISRUPTOR] = atoi(readbuf);
00813                 }
00814 
00815                 if (GetPairedValue(group, "WP_BOWCASTER", readbuf))
00816                 {
00817                         bs->botWeaponWeights[WP_BOWCASTER] = atoi(readbuf);
00818                 }
00819 
00820                 if (GetPairedValue(group, "WP_REPEATER", readbuf))
00821                 {
00822                         bs->botWeaponWeights[WP_REPEATER] = atoi(readbuf);
00823                 }
00824 
00825                 if (GetPairedValue(group, "WP_DEMP2", readbuf))
00826                 {
00827                         bs->botWeaponWeights[WP_DEMP2] = atoi(readbuf);
00828                 }
00829 
00830                 if (GetPairedValue(group, "WP_FLECHETTE", readbuf))
00831                 {
00832                         bs->botWeaponWeights[WP_FLECHETTE] = atoi(readbuf);
00833                 }
00834 
00835                 if (GetPairedValue(group, "WP_ROCKET_LAUNCHER", readbuf))
00836                 {
00837                         bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = atoi(readbuf);
00838                 }
00839 
00840                 if (GetPairedValue(group, "WP_THERMAL", readbuf))
00841                 {
00842                         bs->botWeaponWeights[WP_THERMAL] = atoi(readbuf);
00843                 }
00844 
00845                 if (GetPairedValue(group, "WP_TRIP_MINE", readbuf))
00846                 {
00847                         bs->botWeaponWeights[WP_TRIP_MINE] = atoi(readbuf);
00848                 }
00849 
00850                 if (GetPairedValue(group, "WP_DET_PACK", readbuf))
00851                 {
00852                         bs->botWeaponWeights[WP_DET_PACK] = atoi(readbuf);
00853                 }
00854         }
00855 
00856         bs->lovednum = 0;
00857 
00858         if (GetValueGroup(buf, "EmotionalAttachments", group))
00859         {
00860                 ParseEmotionalAttachments(bs, group);
00861         }
00862 
00863         B_TempFree(131072); //buf
00864         B_TempFree(1024); //readbuf
00865         B_TempFree(65536); //group
00866         trap_FS_FCloseFile(f);
00867 }

void BotWaypointRender void   ) 
 

Definition at line 224 of file ai_wpnav.c.

References B_TempFree(), bot_wp_info, gentity_s::client, EV_SCOREPLUM, wpneighbor_s::forceJumpTo, g_entities, G_Printf(), G_TempEntity(), G_TestLine(), gBotEdit, gentity_t, GetFlagStr(), gLastPrintedIndex, gWPArray, gWPNum, gWPRenderedFrame, gWPRenderTime, wpobject_s::inuse, level, wpobject_s::neighbornum, wpobject_s::neighbors, wpneighbor_s::num, playerState_s::origin, wpobject_s::origin, gclient_s::ps, gentity_s::r, gentity_s::s, S_COLOR_YELLOW, SVF_BROADCAST, entityShared_t::svFlags, level_locals_t::time, entityState_s::time, vmCvar_t::value, vec3_t, and VectorSubtract.

Referenced by BotAIStartFrame().

00225 {
00226         int i, n;
00227         int inc_checker;
00228         int bestindex;
00229         int gotbestindex;
00230         float bestdist;
00231         float checkdist;
00232         gentity_t *plum;
00233         gentity_t *viewent;
00234         char *flagstr;
00235         vec3_t a;
00236 
00237         if (!gBotEdit)
00238         {
00239                 return;
00240         }
00241 
00242         bestindex = 0;
00243 
00244         if (gWPRenderTime > level.time)
00245         {
00246                 goto checkprint;
00247         }
00248 
00249         gWPRenderTime = level.time + 100;
00250 
00251         i = gWPRenderedFrame;
00252         inc_checker = gWPRenderedFrame;
00253 
00254         while (i < gWPNum)
00255         {
00256                 if (gWPArray[i] && gWPArray[i]->inuse)
00257                 {
00258                         plum = G_TempEntity( gWPArray[i]->origin, EV_SCOREPLUM );
00259                         plum->r.svFlags |= SVF_BROADCAST;
00260                         plum->s.time = i;
00261                         
00262                         n = 0;
00263 
00264                         while (n < gWPArray[i]->neighbornum)
00265                         {
00266                                 if (gWPArray[i]->neighbors[n].forceJumpTo && gWPArray[gWPArray[i]->neighbors[n].num])
00267                                 {
00268                                         G_TestLine(gWPArray[i]->origin, gWPArray[gWPArray[i]->neighbors[n].num]->origin, 0x0000ff, 5000);
00269                                 }
00270                                 n++;
00271                         }
00272 
00273                         gWPRenderedFrame++;
00274                 }
00275                 else
00276                 {
00277                         gWPRenderedFrame = 0;
00278                         break;
00279                 }
00280 
00281                 if ((i - inc_checker) > 4)
00282                 {
00283                         break; //don't render too many at once
00284                 }
00285                 i++;
00286         }
00287 
00288         if (i >= gWPNum)
00289         {
00290                 gWPRenderTime = level.time + 1500; //wait a bit after we finish doing the whole trail
00291                 gWPRenderedFrame = 0;
00292         }
00293 
00294 checkprint:
00295 
00296         if (!bot_wp_info.value)
00297         {
00298                 return;
00299         }
00300 
00301         viewent = &g_entities[0]; //only show info to the first client
00302 
00303         if (!viewent || !viewent->client)
00304         { //client isn't in the game yet?
00305                 return;
00306         }
00307 
00308         bestdist = 256; //max distance for showing point info
00309         gotbestindex = 0;
00310 
00311         i = 0;
00312 
00313         while (i < gWPNum)
00314         {
00315                 if (gWPArray[i] && gWPArray[i]->inuse)
00316                 {
00317                         VectorSubtract(viewent->client->ps.origin, gWPArray[i]->origin, a);
00318 
00319                         checkdist = VectorLength(a);
00320 
00321                         if (checkdist < bestdist)
00322                         {
00323                                 bestdist = checkdist;
00324                                 bestindex = i;
00325                                 gotbestindex = 1;
00326                         }
00327                 }
00328                 i++;
00329         }
00330 
00331         if (gotbestindex && bestindex != gLastPrintedIndex)
00332         {
00333                 flagstr = GetFlagStr(gWPArray[bestindex]->flags);
00334                 gLastPrintedIndex = bestindex;
00335                 G_Printf(S_COLOR_YELLOW "Waypoint %i\nFlags - %i (%s) (w%f)\nOrigin - (%i %i %i)\n", (int)(gWPArray[bestindex]->index), (int)(gWPArray[bestindex]->flags), flagstr, gWPArray[bestindex]->weight, (int)(gWPArray[bestindex]->origin[0]), (int)(gWPArray[bestindex]->origin[1]), (int)(gWPArray[bestindex]->origin[2]));
00336                 //GetFlagStr allocates 128 bytes for this, if it's changed then obviously this must be as well
00337                 B_TempFree(128); //flagstr
00338 
00339                 plum = G_TempEntity( gWPArray[bestindex]->origin, EV_SCOREPLUM );
00340                 plum->r.svFlags |= SVF_BROADCAST;
00341                 plum->s.time = bestindex; //render it once
00342         }
00343         else if (!gotbestindex)
00344         {
00345                 gLastPrintedIndex = -1;
00346         }
00347 }

char* ConcatArgs int  start  ) 
 

Definition at line 127 of file g_cmds.c.

00127                                  {
00128         int             i, c, tlen;
00129         static char     line[MAX_STRING_CHARS];
00130         int             len;
00131         char    arg[MAX_STRING_CHARS];
00132 
00133         len = 0;
00134         c = trap_Argc();
00135         for ( i = start ; i < c ; i++ ) {
00136                 trap_Argv( i, arg, sizeof( arg ) );
00137                 tlen = strlen( arg );
00138                 if ( len + tlen >= MAX_STRING_CHARS - 1 ) {
00139                         break;
00140                 }
00141                 memcpy( line + len, arg, tlen );
00142                 len += tlen;
00143                 if ( i != c - 1 ) {
00144                         line[len] = ' ';
00145                         len++;
00146                 }
00147         }
00148 
00149         line[len] = 0;
00150 
00151         return line;
00152 }

int GetBestIdleGoal bot_state_t bs  ) 
 

Definition at line 3559 of file ai_main.c.

References bot_state_t, BotHasAssociated(), wpobject_s::flags, gWPArray, gWPNum, wpobject_s::index, wpobject_s::inuse, bot_state_s::isCamper, level, Q_irand(), bot_state_s::randomNav, bot_state_s::randomNavTime, level_locals_t::time, TotalTrailDistance(), wpobject_s::weight, bot_state_s::wpCurrent, and WPFLAG_GOALPOINT.

Referenced by CTFTakesPriority(), GetIdealDestination(), and SiegeTakesPriority().

03560 {
03561         int i = 0;
03562         int highestweight = 0;
03563         int desiredindex = -1;
03564         int dist_to_weight = 0;
03565         int traildist;
03566 
03567         if (!bs->wpCurrent)
03568         {
03569                 return -1;
03570         }
03571 
03572         if (bs->isCamper != 2)
03573         {
03574                 if (bs->randomNavTime < level.time)
03575                 {
03576                         if (Q_irand(1, 10) < 5)
03577                         {
03578                                 bs->randomNav = 1;
03579                         }
03580                         else
03581                         {
03582                                 bs->randomNav = 0;
03583                         }
03584                         
03585                         bs->randomNavTime = level.time + Q_irand(5000, 15000);
03586                 }
03587         }
03588 
03589         if (bs->randomNav)
03590         { //stop looking for items and/or camping on them
03591                 return -1;
03592         }
03593 
03594         while (i < gWPNum)
03595         {
03596                 if (gWPArray[i] &&
03597                         gWPArray[i]->inuse &&
03598                         (gWPArray[i]->flags & WPFLAG_GOALPOINT) &&
03599                         gWPArray[i]->weight > highestweight &&
03600                         !BotHasAssociated(bs, gWPArray[i]))
03601                 {
03602                         traildist = TotalTrailDistance(bs->wpCurrent->index, i, bs);
03603 
03604                         if (traildist != -1)
03605                         {
03606                                 dist_to_weight = (int)traildist/10000;
03607                                 dist_to_weight = (gWPArray[i]->weight)-dist_to_weight;
03608 
03609                                 if (dist_to_weight > highestweight)
03610                                 {
03611                                         highestweight = dist_to_weight;
03612                                         desiredindex = i;
03613                                 }
03614                         }
03615                 }
03616 
03617                 i++;
03618         }
03619 
03620         return desiredindex;
03621 }

int GetNearestVisibleWP vec3_t  org,
int  ignore
 

Definition at line 1104 of file ai_main.c.

References BotPVSCheck(), g_RMG, gWPArray, gWPNum, vmCvar_t::integer, wpobject_s::inuse, OrgVisibleBox(), vec3_t, and VectorSubtract.

Referenced by BotGetFlagBack(), BotGuardFlagCarrier(), CalculateSiegeGoals(), GetIdealDestination(), JMTakesPriority(), Siege_DefendFromAttackers(), and StandardBotAI().

01105 {
01106         int i;
01107         float bestdist;
01108         float flLen;
01109         int bestindex;
01110         vec3_t a, mins, maxs;
01111 
01112         i = 0;
01113         if (g_RMG.integer)
01114         {
01115                 bestdist = 300;
01116         }
01117         else
01118         {
01119                 bestdist = 800;//99999;
01120                                    //don't trace over 800 units away to avoid GIANT HORRIBLE SPEED HITS ^_^
01121         }
01122         bestindex = -1;
01123 
01124         mins[0] = -15;
01125         mins[1] = -15;
01126         mins[2] = -1;
01127         maxs[0] = 15;
01128         maxs[1] = 15;
01129         maxs[2] = 1;
01130 
01131         while (i < gWPNum)
01132         {
01133                 if (gWPArray[i] && gWPArray[i]->inuse)
01134                 {
01135                         VectorSubtract(org, gWPArray[i]->origin, a);
01136                         flLen = VectorLength(a);
01137 
01138                         if (flLen < bestdist && (g_RMG.integer || BotPVSCheck(org, gWPArray[i]->origin)) && OrgVisibleBox(org, mins, maxs, gWPArray[i]->origin, ignore))
01139                         {
01140                                 bestdist = flLen;
01141                                 bestindex = i;
01142                         }
01143                 }
01144 
01145                 i++;
01146         }
01147 
01148         return bestindex;
01149 }

int NumBots void   ) 
 

Definition at line 416 of file ai_main.c.

References numbots.

00416                   {
00417         return numbots;
00418 }

int OrgVisibleBox vec3_t  org1,
vec3_t  mins,
vec3_t  maxs,
vec3_t  org2,
int  ignore
 

Definition at line 1029 of file ai_main.c.

References trace_t::allsolid, trace_t::fraction, g_RMG, vmCvar_t::integer, MASK_SOLID, NULL, trace_t::startsolid, trap_Trace(), and vec3_t.

Referenced by CalculatePaths(), GetNearestVisibleWP(), and GetNearestVisibleWPToItem().

01030 {
01031         trace_t tr;
01032 
01033         if (g_RMG.integer)
01034         {
01035                 trap_Trace(&tr, org1, NULL, NULL, org2, ignore, MASK_SOLID);
01036         }
01037         else
01038         {
01039                 trap_Trace(&tr, org1, mins, maxs, org2, ignore, MASK_SOLID);
01040         }
01041 
01042         if (tr.fraction == 1 && !tr.startsolid && !tr.allsolid)
01043         {
01044                 return 1;
01045         }
01046 
01047         return 0;
01048 }

void StandardBotAI bot_state_t bs,
float  thinktime
 

Definition at line 5931 of file ai_main.c.

References entityShared_t::absmax, entityShared_t::absmin, botskills_s::accuracy, AltFiring(), playerState_s::ammo, bot_state_s::beStill, bot_forcepowers, bot_forgimmick, bot_getinthecarrr, bot_honorableduelacceptance, BOT_PLANT_DISTANCE, BOT_PLANT_INTERVAL, BOT_SABER_THROW_RANGE, bot_state_t, BOT_WPTOUCH_DISTANCE, BotAimLeading(), BotAimOffsetGoalAngles(), bot_state_s::botChallengingTime, BotCheckDetPacks(), BotDeathNotify(), BotDoChat(), BotDoTeamplayAI(), BotFallbackNavigation(), BotGetWeaponRange(), BotMindTricked(), BotReplyGreetings(), BotScanForLeader(), BotSelectChoiceWeapon(), BotSelectIdealWeapon(), botstates, BotSurfaceNear(), BotTrace_Duck(), BotTrace_Jump(), BotTrace_Strafe(), BotTryAnotherWeapon(), BotUseInventoryItem(), BotWeaponBlockable(), BotWeaponCanLead(), BWEAPONRANGE_LONG, BWEAPONRANGE_MELEE, BWEAPONRANGE_MID, BWEAPONRANGE_SABER, CA_ACTIVE, CA_AUTHORIZING, bot_state_s::campStanding, bot_state_s::chatAltObject, bot_state_s::chatObject, bot_state_s::chatTeam, bot_state_s::chatTime, CheckForFriendInLOF(), CheckForFunc(), CLASS_VEHICLE, client, gentity_s::client, bot_state_s::client, level_locals_t::clients, Cmd_EngageDuel_f(), Cmd_SaberAttackCycle_f(), Cmd_ToggleSaber_f(), CombatBotAI(), CommanderBotAI(), clientPersistant_t::connected, CTFFlagMovement(), bot_state_s::cur_ps, bot_state_s::currentChat, bot_state_s::currentEnemy, entityShared_t::currentOrigin, bot_state_s::dangerousObject, bot_state_s::deathActivitiesDone, bot_state_s::destinationGrabTime, bot_state_s::doAltAttack, bot_state_s::doAttack, bot_state_s::doChat, bot_state_s::doForcePush, bot_state_s::doingFallback, bot_state_s::duckTime, playerState_s::duelIndex, playerState_s::duelInProgress, playerState_s::duelTime, playerState_s::electrifyTime, ENEMY_FORGET_MS, bot_state_s::enemySeenTime, ENTITYNUM_NONE, EntityVisibleBox(), ET_NPC, entityState_s::eType, bot_state_s::eye, playerState_s::fd, wpobject_s::flags, FORCE_DARKSIDE, FORCE_LEVEL_1, FORCE_LIGHTNING_RADIUS, FORCE_LIGHTSIDE, forcedata_s::forceGripBeingGripped, forcedata_s::forceGripCripple, bot_state_s::forceJumpChargeTime, bot_state_s::forceJumping, bot_state_s::forceMove_Forward, bot_state_s::forceMove_Right, bot_state_s::forceMove_Up, forcedata_s::forcePower, forcedata_s::forcePowerLevel, forcePowerNeeded, forcedata_s::forcePowersActive, forcedata_s::forcePowersKnown, ForcePowerUsableOn(), forcedata_s::forceSide, bot_state_s::forceWeaponSelect, FP_ABSORB, FP_DRAIN, FP_GRIP, FP_HEAL, FP_LEVITATION, FP_LIGHTNING, FP_PROTECT, FP_PULL, FP_PUSH, FP_RAGE, FP_SABER_OFFENSE, FP_SABERTHROW, FP_SEE, FP_SPEED, FP_TEAM_FORCE, FP_TEAM_HEAL, FP_TELEPATHY, bot_state_s::frame_Enemy_Len, bot_state_s::frame_Enemy_Vis, bot_state_s::frame_Waypoint_Len, bot_state_s::frame_Waypoint_Vis, g_entities, g_forcePowerDisable, g_gametype, g_privateDuel, g_RMG, gDeactivated, gentity_t, GetIdealDestination(), GetNearestVisibleWP(), gJMSaberEnt, gLevelFlags, bot_state_s::goalAngles, bot_state_s::goalMovedir, bot_state_s::goalPosition, GT_JEDIMASTER, GT_SINGLE_PLAYER, GT_TEAM, gWPArray, gWPNum, playerState_s::hasDetPackPlanted, gentity_s::health, bot_state_s::hereWhenSpotted, bot_state_s::hitSpotted, bot_state_s::iHaveNoIdeaWhereIAmGoing, wpobject_s::index, InFieldOfVision(), vmCvar_t::integer, wpobject_s::inuse, gentity_s::inuse, bot_state_s::isCamping, playerState_s::isJediMaster, bot_state_s::isSquadLeader, bot_state_s::jDelay, bot_state_s::jmState, bot_state_s::jumpHoldTime, bot_state_s::jumpPrep, bot_state_s::jumpTime, KeepAltFromFiring(), KeepPrimFromFiring(), bot_state_s::lastAttacked, bot_state_s::lastDeadTime, bot_state_s::lastEnemySpotted, bot_state_s::lastHurt, bot_state_s::lastSignificantAreaChange, bot_state_s::lastSignificantChangeTime, bot_state_s::lastVisibleEnemyIndex, level, LEVELFLAG_NOPOINTPREDICTION, playerState_s::m_iVehicleNum, gentity_s::m_pVehicle, MAX_DRAIN_DISTANCE, MAX_GENTITIES, MAX_GRIP_DISTANCE, MAX_TRICK_DISTANCE, MELEE_ATTACK_RANGE, MeleeCombatHandling(), bot_state_s::meleeStrafeDir, bot_state_s::meleeStrafeDisable, MoveTowardIdealAngles(), bot_state_s::noUseTime, entityState_s::NPC_class, NULL, entityState_s::number, OrgVisible(), entityState_s::origin, wpobject_s::origin, bot_state_s::origin, playerState_s::origin, PassLovedOneCheck(), PassStandardEnemyChecks(), PassWayCheck(), gclient_s::pers, PITCH, bot_state_s::plantContinue, bot_state_s::plantDecided, bot_state_s::plantKillEmAll, bot_state_s::plantTime, playerState_s::pm_flags, PMF_JUMP_HELD, PrimFiring(), gclient_s::ps, Q_irand(), qboolean, qfalse, qtrue, gentity_s::r, rand(), botskills_s::reflex, bot_state_s::revengeEnemy, bot_state_s::revengeHateLevel, gentity_s::s, SABER_ATTACK_RANGE, forcedata_s::saberAnimLevel, SaberCombatHandling(), bot_state_s::saberDefending, playerState_s::saberEntityNum, playerState_s::saberHolstered, playerState_s::saberInFlight, playerState_s::saberLockTime, bot_state_s::saberPower, bot_state_s::saberPowerTime, bot_state_s::saberThrowTime, ScanForEnemies(), bot_state_s::settings, bot_state_s::shootGoal, bot_settings_s::skill, bot_state_s::skills, bot_state_s::squadCannotLead, bot_state_s::squadLeader, SS_DUAL, SS_FAST, SS_MEDIUM, SS_STAFF, SS_STRONG, STRAFEAROUND_LEFT, STRAFEAROUND_RIGHT, StrafeTracing(), gentity_s::takedamage, TEAM_SPECTATOR, level_locals_t::time, bot_state_s::timeToReact, TotalTrailDistance(), trap_EA_Alt_Attack(), trap_EA_Attack(), trap_EA_Crouch(), trap_EA_ForcePower(), trap_EA_Jump(), trap_EA_Move(), trap_EA_MoveBack(), trap_EA_MoveForward(), trap_EA_MoveLeft(), trap_EA_MoveRight(), trap_EA_Say(), trap_EA_SayTeam(), trap_EA_Use(), vec3_origin, vec3_t, vectoangles(), VectorCopy, VectorNormalize(), VectorSubtract, bot_state_s::viewangles, playerState_s::viewheight, WaitingForNow(), playerState_s::weapon, WEAPON_CHARGING, WEAPON_CHARGING_ALT, WEAPON_READY, weaponData, playerState_s::weaponstate, WP_DET_PACK, WP_FLECHETTE, WP_SABER, WP_TRIP_MINE, bot_state_s::wpCamping, bot_state_s::wpCampingTo, WPConstantRoutine(), bot_state_s::wpCurrent, bot_state_s::wpDestIgnoreTime, bot_state_s::wpDestination, bot_state_s::wpDestSwitchTime, bot_state_s::wpDirection, WPFLAG_BLUE_FLAG, WPFLAG_NOMOVEFUNC, WPFLAG_NOVIS, WPFLAG_RED_FLAG, WPFLAG_WAITFORFUNC, WPOrgVisible(), bot_state_s::wpSeenTime, bot_state_s::wpStoreDest, bot_state_s::wpSwitchTime, WPTouchRoutine(), bot_state_s::wpTravelTime, and YAW.

Referenced by BotAI().

05932 {
05933         int wp, enemy;
05934         int desiredIndex;
05935         int goalWPIndex;
05936         int doingFallback = 0;
05937         int fjHalt;
05938         vec3_t a, ang, headlevel, eorg, noz_x, noz_y, dif, a_fo;
05939         float reaction;
05940         float bLeadAmount;
05941         int meleestrafe = 0;
05942         int useTheForce = 0;
05943         int forceHostile = 0;
05944         int cBAI = 0;
05945         gentity_t *friendInLOF = 0;
05946         float mLen;
05947         int visResult = 0;
05948         int selResult = 0;
05949         int mineSelect = 0;
05950         int detSelect = 0;
05951         vec3_t preFrameGAngles;
05952 
05953         if (gDeactivated)
05954         {
05955                 bs->wpCurrent = NULL;
05956                 bs->currentEnemy = NULL;
05957                 bs->wpDestination = NULL;
05958                 bs->wpDirection = 0;
05959                 return;
05960         }
05961 
05962         if (g_entities[bs->client].inuse &&
05963                 g_entities[bs->client].client &&
05964                 g_entities[bs->client].client->sess.sessionTeam == TEAM_SPECTATOR)
05965         {
05966                 bs->wpCurrent = NULL;
05967                 bs->currentEnemy = NULL;
05968                 bs->wpDestination = NULL;
05969                 bs->wpDirection = 0;
05970                 return;
05971         }
05972 
05973 
05974 #ifndef FINAL_BUILD
05975         if (bot_getinthecarrr.integer)
05976         { //stupid vehicle debug, I tire of having to connect another client to test passengers.
05977                 gentity_t *botEnt = &g_entities[bs->client];
05978 
05979                 if (botEnt->inuse && botEnt->client && botEnt->client->ps.m_iVehicleNum)
05980                 { //in a vehicle, so...
05981                         bs->noUseTime = level.time + 5000;
05982 
05983                         if (bot_getinthecarrr.integer != 2)
05984                         {
05985                                 trap_EA_MoveForward(bs->client);
05986 
05987                                 if (bot_getinthecarrr.integer == 3)
05988                                 { //use alt fire
05989                                         trap_EA_Alt_Attack(bs->client);
05990                                 }
05991                         }
05992                 }
05993                 else
05994                 { //find one, get in
05995                         int i = 0;
05996                         gentity_t *vehicle = NULL;
05997                         //find the nearest, manned vehicle
05998                         while (i < MAX_GENTITIES)
05999                         {
06000                                 vehicle = &g_entities[i];
06001 
06002                                 if (vehicle->inuse && vehicle->client && vehicle->s.eType == ET_NPC &&
06003                                         vehicle->s.NPC_class == CLASS_VEHICLE && vehicle->m_pVehicle &&
06004                                         (vehicle->client->ps.m_iVehicleNum || bot_getinthecarrr.integer == 2))
06005                                 { //ok, this is a vehicle, and it has a pilot/passengers
06006                                         break;
06007                                 }
06008                                 i++;
06009                         }
06010                         if (i != MAX_GENTITIES && vehicle)
06011                         { //broke before end so we must've found something
06012                                 vec3_t v;
06013 
06014                                 VectorSubtract(vehicle->client->ps.origin, bs->origin, v);
06015                                 VectorNormalize(v);
06016                                 vectoangles(v, bs->goalAngles);
06017                                 MoveTowardIdealAngles(bs);
06018                                 trap_EA_Move(bs->client, v, 5000.0f);
06019 
06020                                 if (bs->noUseTime < (level.time-400))
06021                                 {
06022                                         bs->noUseTime = level.time + 500;
06023                                 }
06024                         }
06025                 }
06026 
06027                 return;
06028         }
06029 #endif
06030 
06031         if (bot_forgimmick.integer)
06032         {
06033                 bs->wpCurrent = NULL;
06034                 bs->currentEnemy = NULL;
06035                 bs->wpDestination = NULL;
06036                 bs->wpDirection = 0;
06037 
06038                 if (bot_forgimmick.integer == 2)
06039                 { //for debugging saber stuff, this is handy
06040                         trap_EA_Attack(bs->client);
06041                 }
06042 
06043                 if (bot_forgimmick.integer == 3)
06044                 { //for testing cpu usage moving around rmg terrain without AI
06045                         vec3_t mdir;
06046 
06047                         VectorSubtract(bs->origin, vec3_origin, mdir);
06048                         VectorNormalize(mdir);
06049                         trap_EA_Attack(bs->client);
06050                         trap_EA_Move(bs->client, mdir, 5000);
06051                 }
06052 
06053                 if (bot_forgimmick.integer == 4)
06054                 { //constantly move toward client 0
06055                         if (g_entities[0].client && g_entities[0].inuse)
06056                         {
06057                                 vec3_t mdir;
06058 
06059                                 VectorSubtract(g_entities[0].client->ps.origin, bs->origin, mdir);
06060                                 VectorNormalize(mdir);
06061                                 trap_EA_Move(bs->client, mdir, 5000);
06062                         }
06063                 }
06064 
06065                 if (bs->forceMove_Forward)
06066                 {
06067                         if (bs->forceMove_Forward > 0)
06068                         {
06069                                 trap_EA_MoveForward(bs->client);
06070                         }
06071                         else
06072                         {
06073                                 trap_EA_MoveBack(bs->client);
06074                         }
06075                 }
06076                 if (bs->forceMove_Right)
06077                 {
06078                         if (bs->forceMove_Right > 0)
06079                         {
06080                                 trap_EA_MoveRight(bs->client);
06081                         }
06082                         else
06083                         {
06084                                 trap_EA_MoveLeft(bs->client);
06085                         }
06086                 }
06087                 if (bs->forceMove_Up)
06088                 {
06089                         trap_EA_Jump(bs->client);
06090                 }
06091                 return;
06092         }
06093 
06094         if (!bs->lastDeadTime)
06095         { //just spawned in?
06096                 bs->lastDeadTime = level.time;
06097         }
06098 
06099         if (g_entities[bs->client].health < 1)
06100         {
06101                 bs->lastDeadTime = level.time;
06102 
06103                 if (!bs->deathActivitiesDone && bs->lastHurt && bs->lastHurt->client && bs->lastHurt->s.number != bs->client)
06104                 {
06105                         BotDeathNotify(bs);
06106                         if (PassLovedOneCheck(bs, bs->lastHurt))
06107                         {
06108                                 //CHAT: Died
06109                                 bs->chatObject = bs->lastHurt;
06110                                 bs->chatAltObject = NULL;
06111                                 BotDoChat(bs, "Died", 0);
06112                         }
06113                         else if (!PassLovedOneCheck(bs, bs->lastHurt) &&
06114                                 botstates[bs->lastHurt->s.number] &&
06115                                 PassLovedOneCheck(botstates[bs->lastHurt->s.number], &g_entities[bs->client]))
06116                         { //killed by a bot that I love, but that does not love me
06117                                 bs->chatObject = bs->lastHurt;
06118                                 bs->chatAltObject = NULL;
06119                                 BotDoChat(bs, "KilledOnPurposeByLove", 0);
06120                         }
06121 
06122                         bs->deathActivitiesDone = 1;
06123                 }
06124                 
06125                 bs->wpCurrent = NULL;
06126                 bs->currentEnemy = NULL;
06127                 bs->wpDestination = NULL;
06128                 bs->wpCamping = NULL;
06129                 bs->wpCampingTo = NULL;
06130                 bs->wpStoreDest = NULL;
06131                 bs->wpDestIgnoreTime = 0;
06132                 bs->wpDestSwitchTime = 0;
06133                 bs->wpSeenTime = 0;
06134                 bs->wpDirection = 0;
06135 
06136                 if (rand()%10 < 5 &&
06137                         (!bs->doChat || bs->chatTime < level.time))
06138                 {
06139                         trap_EA_Attack(bs->client);
06140                 }
06141 
06142                 return;
06143         }
06144 
06145         VectorCopy(bs->goalAngles, preFrameGAngles);
06146 
06147         bs->doAttack = 0;
06148         bs->doAltAttack = 0;
06149         //reset the attack states
06150 
06151         if (bs->isSquadLeader)
06152         {
06153                 CommanderBotAI(bs);
06154         }
06155         else
06156         {
06157                 BotDoTeamplayAI(bs);
06158         }
06159 
06160         if (!bs->currentEnemy)
06161         {
06162                 bs->frame_Enemy_Vis = 0;
06163         }
06164 
06165         if (bs->revengeEnemy && bs->revengeEnemy->client &&
06166                 bs->revengeEnemy->client->pers.connected != CA_ACTIVE && bs->revengeEnemy->client->pers.connected != CA_AUTHORIZING)
06167         {
06168                 bs->revengeEnemy = NULL;
06169                 bs->revengeHateLevel = 0;
06170         }
06171 
06172         if (bs->currentEnemy && bs->currentEnemy->client &&
06173                 bs->currentEnemy->client->pers.connected != CA_ACTIVE && bs->currentEnemy->client->pers.connected != CA_AUTHORIZING)
06174         {
06175                 bs->currentEnemy = NULL;
06176         }
06177 
06178         fjHalt = 0;
06179 
06180 #ifndef FORCEJUMP_INSTANTMETHOD
06181         if (bs->forceJumpChargeTime > level.time)
06182         {
06183                 useTheForce = 1;
06184                 forceHostile = 0;
06185         }
06186 
06187         if (bs->currentEnemy && bs->currentEnemy->client && bs->frame_Enemy_Vis && bs->forceJumpChargeTime < level.time)
06188 #else
06189         if (bs->currentEnemy && bs->currentEnemy->client && bs->frame_Enemy_Vis)
06190 #endif
06191         {
06192                 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, a_fo);
06193                 vectoangles(a_fo, a_fo);
06194 
06195                 //do this above all things
06196                 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PUSH)) && (bs->doForcePush > level.time || bs->cur_ps.fd.forceGripBeingGripped > level.time) && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PUSH]][FP_PUSH] /*&& InFieldOfVision(bs->viewangles, 50, a_fo)*/)
06197                 {
06198                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_PUSH;
06199                         useTheForce = 1;
06200                         forceHostile = 1;
06201                 }
06202                 else if (bs->cur_ps.fd.forceSide == FORCE_DARKSIDE)
06203                 { //try dark side powers
06204                   //in order of priority top to bottom
06205                         if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_GRIP)) && (bs->cur_ps.fd.forcePowersActive & (1 << FP_GRIP)) && InFieldOfVision(bs->viewangles, 50, a_fo))
06206                         { //already gripping someone, so hold it
06207                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_GRIP;
06208                                 useTheForce = 1;
06209                                 forceHostile = 1;
06210                         }
06211                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_LIGHTNING)) && bs->frame_Enemy_Len < FORCE_LIGHTNING_RADIUS && level.clients[bs->client].ps.fd.forcePower > 50 && InFieldOfVision(bs->viewangles, 50, a_fo))
06212                         {
06213                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_LIGHTNING;
06214                                 useTheForce = 1;
06215                                 forceHostile = 1;
06216                         }
06217                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_GRIP)) && bs->frame_Enemy_Len < MAX_GRIP_DISTANCE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_GRIP]][FP_GRIP] && InFieldOfVision(bs->viewangles, 50, a_fo))
06218                         {
06219                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_GRIP;
06220                                 useTheForce = 1;
06221                                 forceHostile = 1;
06222                         }
06223                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_RAGE)) && g_entities[bs->client].health < 25 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_RAGE]][FP_RAGE])
06224                         {
06225                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_RAGE;
06226                                 useTheForce = 1;
06227                                 forceHostile = 0;
06228                         }
06229                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_DRAIN)) && bs->frame_Enemy_Len < MAX_DRAIN_DISTANCE && level.clients[bs->client].ps.fd.forcePower > 50 && InFieldOfVision(bs->viewangles, 50, a_fo) && bs->currentEnemy->client->ps.fd.forcePower > 10 && bs->currentEnemy->client->ps.fd.forceSide == FORCE_LIGHTSIDE)
06230                         {
06231                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_DRAIN;
06232                                 useTheForce = 1;
06233                                 forceHostile = 1;
06234                         }
06235                 }
06236                 else if (bs->cur_ps.fd.forceSide == FORCE_LIGHTSIDE)
06237                 { //try light side powers
06238                         if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && bs->cur_ps.fd.forceGripCripple &&
06239                                  level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06240                         { //absorb to get out
06241                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06242                                 useTheForce = 1;
06243                                 forceHostile = 0;
06244                         }
06245                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && bs->cur_ps.electrifyTime >= level.time &&
06246                                  level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06247                         { //absorb lightning
06248                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06249                                 useTheForce = 1;
06250                                 forceHostile = 0;
06251                         }
06252                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_TELEPATHY)) && bs->frame_Enemy_Len < MAX_TRICK_DISTANCE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TELEPATHY]][FP_TELEPATHY] && InFieldOfVision(bs->viewangles, 50, a_fo) && !(bs->currentEnemy->client->ps.fd.forcePowersActive & (1 << FP_SEE)))
06253                         {
06254                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TELEPATHY;
06255                                 useTheForce = 1;
06256                                 forceHostile = 1;
06257                         }
06258                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_ABSORB)) && g_entities[bs->client].health < 75 && bs->currentEnemy->client->ps.fd.forceSide == FORCE_DARKSIDE && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_ABSORB]][FP_ABSORB])
06259                         {
06260                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_ABSORB;
06261                                 useTheForce = 1;
06262                                 forceHostile = 0;
06263                         }
06264                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PROTECT)) && g_entities[bs->client].health < 35 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PROTECT]][FP_PROTECT])
06265                         {
06266                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PROTECT;
06267                                 useTheForce = 1;
06268                                 forceHostile = 0;
06269                         }
06270                 }
06271 
06272                 if (!useTheForce)
06273                 { //try neutral powers
06274                         if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PUSH)) && bs->cur_ps.fd.forceGripBeingGripped > level.time && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_PUSH]][FP_PUSH] && InFieldOfVision(bs->viewangles, 50, a_fo))
06275                         {
06276                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PUSH;
06277                                 useTheForce = 1;
06278                                 forceHostile = 1;
06279                         }
06280                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_SPEED)) && g_entities[bs->client].health < 25 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_SPEED]][FP_SPEED])
06281                         {
06282                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_SPEED;
06283                                 useTheForce = 1;
06284                                 forceHostile = 0;
06285                         }
06286                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_SEE)) && BotMindTricked(bs->client, bs->currentEnemy->s.number) && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_SEE]][FP_SEE])
06287                         {
06288                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_SEE;
06289                                 useTheForce = 1;
06290                                 forceHostile = 0;
06291                         }
06292                         else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_PULL)) && bs->frame_Enemy_Len < 256 && level.clients[bs->client].ps.fd.forcePower > 75 && InFieldOfVision(bs->viewangles, 50, a_fo))
06293                         {
06294                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_PULL;
06295                                 useTheForce = 1;
06296                                 forceHostile = 1;
06297                         }
06298                 }
06299         }
06300 
06301         if (!useTheForce)
06302         { //try powers that we don't care if we have an enemy for
06303                 if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_HEAL)) && g_entities[bs->client].health < 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_HEAL]][FP_HEAL] && bs->cur_ps.fd.forcePowerLevel[FP_HEAL] > FORCE_LEVEL_1)
06304                 {
06305                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_HEAL;
06306                         useTheForce = 1;
06307                         forceHostile = 0;
06308                 }
06309                 else if ((bs->cur_ps.fd.forcePowersKnown & (1 << FP_HEAL)) && g_entities[bs->client].health < 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_HEAL]][FP_HEAL] && !bs->currentEnemy && bs->isCamping > level.time)
06310                 { //only meditate and heal if we're camping
06311                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_HEAL;
06312                         useTheForce = 1;
06313                         forceHostile = 0;
06314                 }
06315         }
06316 
06317         if (useTheForce && forceHostile)
06318         {
06319                 if (bs->currentEnemy && bs->currentEnemy->client &&
06320                         !ForcePowerUsableOn(&g_entities[bs->client], bs->currentEnemy, level.clients[bs->client].ps.fd.forcePowerSelected))
06321                 {
06322                         useTheForce = 0;
06323                         forceHostile = 0;
06324                 }
06325         }
06326 
06327         doingFallback = 0;
06328 
06329         bs->deathActivitiesDone = 0;
06330 
06331         if (BotUseInventoryItem(bs))
06332         {
06333                 if (rand()%10 < 5)
06334                 {
06335                         trap_EA_Use(bs->client);
06336                 }
06337         }
06338 
06339         if (bs->cur_ps.ammo[weaponData[bs->cur_ps.weapon].ammoIndex] < weaponData[bs->cur_ps.weapon].energyPerShot)
06340         {
06341                 if (BotTryAnotherWeapon(bs))
06342                 {
06343                         return;
06344                 }
06345         }
06346         else
06347         {
06348                 if (bs->currentEnemy && bs->lastVisibleEnemyIndex == bs->currentEnemy->s.number &&
06349                         bs->frame_Enemy_Vis && bs->forceWeaponSelect /*&& bs->plantContinue < level.time*/)
06350                 {
06351                         bs->forceWeaponSelect = 0;
06352                 }
06353 
06354                 if (bs->plantContinue > level.time)
06355                 {
06356                         bs->doAttack = 1;
06357                         bs->destinationGrabTime = 0;
06358                 }
06359 
06360                 if (!bs->forceWeaponSelect && bs->cur_ps.hasDetPackPlanted && bs->plantKillEmAll > level.time)
06361                 {
06362                         bs->forceWeaponSelect = WP_DET_PACK;
06363                 }
06364 
06365                 if (bs->forceWeaponSelect)
06366                 {
06367                         selResult = BotSelectChoiceWeapon(bs, bs->forceWeaponSelect, 1);
06368                 }
06369 
06370                 if (selResult)
06371                 {
06372                         if (selResult == 2)
06373                         { //newly selected
06374                                 return;
06375                         }
06376                 }
06377                 else if (BotSelectIdealWeapon(bs))
06378                 {
06379                         return;
06380                 }
06381         }
06382         /*if (BotSelectMelee(bs))
06383         {
06384                 return;
06385         }*/
06386 
06387         reaction = bs->skills.reflex/bs->settings.skill;
06388 
06389         if (reaction < 0)
06390         {
06391                 reaction = 0;
06392         }
06393         if (reaction > 2000)
06394         {
06395                 reaction = 2000;
06396         }
06397 
06398         if (!bs->currentEnemy)
06399         {
06400                 bs->timeToReact = level.time + reaction;
06401         }
06402 
06403         if (bs->cur_ps.weapon == WP_DET_PACK && bs->cur_ps.hasDetPackPlanted && bs->plantKillEmAll > level.time)
06404         {
06405                 bs->doAltAttack = 1;
06406         }
06407 
06408         if (bs->wpCamping)
06409         {
06410                 if (bs->isCamping < level.time)
06411                 {
06412                         bs->wpCamping = NULL;
06413                         bs->isCamping = 0;
06414                 }
06415 
06416                 if (bs->currentEnemy && bs->frame_Enemy_Vis)
06417                 {
06418                         bs->wpCamping = NULL;
06419                         bs->isCamping = 0;
06420                 }
06421         }
06422 
06423         if (bs->wpCurrent &&
06424                 (bs->wpSeenTime < level.time || bs->wpTravelTime < level.time))
06425         {
06426                 bs->wpCurrent = NULL;
06427         }
06428 
06429         if (bs->currentEnemy)
06430         {
06431                 if (bs->enemySeenTime < level.time ||
06432                         !PassStandardEnemyChecks(bs, bs->currentEnemy))
06433                 {
06434                         if (bs->revengeEnemy == bs->currentEnemy &&
06435                                 bs->currentEnemy->health < 1 &&
06436                                 bs->lastAttacked && bs->lastAttacked == bs->currentEnemy)
06437                         {
06438                                 //CHAT: Destroyed hated one [KilledHatedOne section]
06439                                 bs->chatObject = bs->revengeEnemy;
06440                                 bs->chatAltObject = NULL;
06441                                 BotDoChat(bs, "KilledHatedOne", 1);
06442                                 bs->revengeEnemy = NULL;
06443                                 bs->revengeHateLevel = 0;
06444                         }
06445                         else if (bs->currentEnemy->health < 1 && PassLovedOneCheck(bs, bs->currentEnemy) &&
06446                                 bs->lastAttacked && bs->lastAttacked == bs->currentEnemy)
06447                         {
06448                                 //CHAT: Killed
06449                                 bs->chatObject = bs->currentEnemy;
06450                                 bs->chatAltObject = NULL;
06451                                 BotDoChat(bs, "Killed", 0);
06452                         }
06453 
06454                         bs->currentEnemy = NULL;
06455                 }
06456         }
06457 
06458         if (bot_honorableduelacceptance.integer)
06459         {
06460                 if (bs->currentEnemy && bs->currentEnemy->client &&
06461                         bs->cur_ps.weapon == WP_SABER &&
06462                         g_privateDuel.integer &&
06463                         bs->frame_Enemy_Vis &&
06464                         bs->frame_Enemy_Len < 400 &&
06465                         bs->currentEnemy->client->ps.weapon == WP_SABER &&
06466                         bs->currentEnemy->client->ps.saberHolstered)
06467                 {
06468                         vec3_t e_ang_vec;
06469 
06470                         VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, e_ang_vec);
06471 
06472                         if (InFieldOfVision(bs->viewangles, 100, e_ang_vec))
06473                         { //Our enemy has his saber holstered and has challenged us to a duel, so challenge him back
06474                                 if (!bs->cur_ps.saberHolstered)
06475                                 {
06476                                         Cmd_ToggleSaber_f(&g_entities[bs->client]);
06477                                 }
06478                                 else
06479                                 {
06480                                         if (bs->currentEnemy->client->ps.duelIndex == bs->client &&
06481                                                 bs->currentEnemy->client->ps.duelTime > level.time &&
06482                                                 !bs->cur_ps.duelInProgress)
06483                                         {
06484                                                 Cmd_EngageDuel_f(&g_entities[bs->client]);
06485                                         }
06486                                 }
06487 
06488                                 bs->doAttack = 0;
06489                                 bs->doAltAttack = 0;
06490                                 bs->botChallengingTime = level.time + 100;
06491                                 bs->beStill = level.time + 100;
06492                         }
06493                 }
06494         }
06495         //Apparently this "allows you to cheese" when fighting against bots. I'm not sure why you'd want to con bots
06496         //into an easy kill, since they're bots and all. But whatever.
06497 
06498         if (!bs->wpCurrent)
06499         {
06500                 wp = GetNearestVisibleWP(bs->origin, bs->client);
06501 
06502                 if (wp != -1)
06503                 {
06504                         bs->wpCurrent = gWPArray[wp];
06505                         bs->wpSeenTime = level.time + 1500;
06506                         bs->wpTravelTime = level.time + 10000; //never take more than 10 seconds to travel to a waypoint
06507                 }
06508         }
06509 
06510         if (bs->enemySeenTime < level.time || !bs->frame_Enemy_Vis || !bs->currentEnemy ||
06511                 (bs->currentEnemy /*&& bs->cur_ps.weapon == WP_SABER && bs->frame_Enemy_Len > 300*/))
06512         {
06513                 enemy = ScanForEnemies(bs);
06514 
06515                 if (enemy != -1)
06516                 {
06517                         bs->currentEnemy = &g_entities[enemy];
06518                         bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
06519                 }
06520         }
06521 
06522         if (!bs->squadLeader && !bs->isSquadLeader)
06523         {
06524                 BotScanForLeader(bs);
06525         }
06526 
06527         if (!bs->squadLeader && bs->squadCannotLead < level.time)
06528         { //if still no leader after scanning, then become a squad leader
06529                 bs->isSquadLeader = 1;
06530         }
06531 
06532         if (bs->isSquadLeader && bs->squadLeader)
06533         { //we don't follow anyone if we are a leader
06534                 bs->squadLeader = NULL;
06535         }
06536 
06537         //ESTABLISH VISIBILITIES AND DISTANCES FOR THE WHOLE FRAME HERE
06538         if (bs->wpCurrent)
06539         {
06540                 if (g_RMG.integer)
06541                 { //this is somewhat hacky, but in RMG we don't really care about vertical placement because points are scattered across only the terrain.
06542                         vec3_t vecB, vecC;
06543 
06544                         vecB[0] = bs->origin[0];
06545                         vecB[1] = bs->origin[1];
06546                         vecB[2] = bs->origin[2];
06547 
06548                         vecC[0] = bs->wpCurrent->origin[0];
06549                         vecC[1] = bs->wpCurrent->origin[1];
06550                         vecC[2] = vecB[2];
06551 
06552 
06553                         VectorSubtract(vecC, vecB, a);
06554                 }
06555                 else
06556                 {
06557                         VectorSubtract(bs->wpCurrent->origin, bs->origin, a);
06558                 }
06559                 bs->frame_Waypoint_Len = VectorLength(a);
06560 
06561                 visResult = WPOrgVisible(&g_entities[bs->client], bs->origin, bs->wpCurrent->origin, bs->client);
06562 
06563                 if (visResult == 2)
06564                 {
06565                         bs->frame_Waypoint_Vis = 0;
06566                         bs->wpSeenTime = 0;
06567                         bs->wpDestination = NULL;
06568                         bs->wpDestIgnoreTime = level.time + 5000;
06569 
06570                         if (bs->wpDirection)
06571                         {
06572                                 bs->wpDirection = 0;
06573                         }
06574                         else
06575                         {
06576                                 bs->wpDirection = 1;
06577                         }
06578                 }
06579                 else if (visResult)
06580                 {
06581                         bs->frame_Waypoint_Vis = 1;
06582                 }
06583                 else
06584                 {
06585                         bs->frame_Waypoint_Vis = 0;
06586                 }
06587         }
06588 
06589         if (bs->currentEnemy)
06590         {
06591                 if (bs->currentEnemy->client)
06592                 {
06593                         VectorCopy(bs->currentEnemy->client->ps.origin, eorg);
06594                         eorg[2] += bs->currentEnemy->client->ps.viewheight;
06595                 }
06596                 else
06597                 {
06598                         VectorCopy(bs->currentEnemy->s.origin, eorg);
06599                 }
06600 
06601                 VectorSubtract(eorg, bs->eye, a);
06602                 bs->frame_Enemy_Len = VectorLength(a);
06603 
06604                 if (OrgVisible(bs->eye, eorg, bs->client))
06605                 {
06606                         bs->frame_Enemy_Vis = 1;
06607                         VectorCopy(eorg, bs->lastEnemySpotted);
06608                         VectorCopy(bs->origin, bs->hereWhenSpotted);
06609                         bs->lastVisibleEnemyIndex = bs->currentEnemy->s.number;
06610                         //VectorCopy(bs->eye, bs->lastEnemySpotted);
06611                         bs->hitSpotted = 0;
06612                 }
06613                 else
06614                 {
06615                         bs->frame_Enemy_Vis = 0;
06616                 }
06617         }
06618         else
06619         {
06620                 bs->lastVisibleEnemyIndex = ENTITYNUM_NONE;
06621         }
06622         //END
06623 
06624         if (bs->frame_Enemy_Vis)
06625         {
06626                 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
06627         }
06628 
06629         if (bs->wpCurrent)
06630         {
06631                 int wpTouchDist = BOT_WPTOUCH_DISTANCE;
06632                 WPConstantRoutine(bs);
06633 
06634                 if (!bs->wpCurrent)
06635                 { //WPConstantRoutine has the ability to nullify the waypoint if it fails certain checks, so..
06636                         return;
06637                 }
06638 
06639                 if (bs->wpCurrent->flags & WPFLAG_WAITFORFUNC)
06640                 {
06641                         if (!CheckForFunc(bs->wpCurrent->origin, -1))
06642                         {
06643                                 bs->beStill = level.time + 500; //no func brush under.. wait
06644                         }
06645                 }
06646                 if (bs->wpCurrent->flags & WPFLAG_NOMOVEFUNC)
06647                 {
06648                         if (CheckForFunc(bs->wpCurrent->origin, -1))
06649                         {
06650                                 bs->beStill = level.time + 500; //func brush under.. wait
06651                         }
06652                 }
06653 
06654                 if (bs->frame_Waypoint_Vis || (bs->wpCurrent->flags & WPFLAG_NOVIS))
06655                 {
06656                         if (g_RMG.integer)
06657                         {
06658                                 bs->wpSeenTime = level.time + 5000; //if we lose sight of the point, we have 1.5 seconds to regain it before we drop it
06659                         }
06660                         else
06661                         {
06662                                 bs->wpSeenTime = level.time + 1500; //if we lose sight of the point, we have 1.5 seconds to regain it before we drop it
06663                         }
06664                 }
06665                 VectorCopy(bs->wpCurrent->origin, bs->goalPosition);
06666                 if (bs->wpDirection)
06667                 {
06668                         goalWPIndex = bs->wpCurrent->index-1;
06669                 }
06670                 else
06671                 {
06672                         goalWPIndex = bs->wpCurrent->index+1;
06673                 }
06674 
06675                 if (bs->wpCamping)
06676                 {
06677                         VectorSubtract(bs->wpCampingTo->origin, bs->origin, a);
06678                         vectoangles(a, ang);
06679                         VectorCopy(ang, bs->goalAngles);
06680 
06681                         VectorSubtract(bs->origin, bs->wpCamping->origin, a);
06682                         if (VectorLength(a) < 64)
06683                         {
06684                                 VectorCopy(bs->wpCamping->origin, bs->goalPosition);
06685                                 bs->beStill = level.time + 1000;
06686 
06687                                 if (!bs->campStanding)
06688                                 {
06689                                         bs->duckTime = level.time + 1000;
06690                                 }
06691                         }
06692                 }
06693                 else if (gWPArray[goalWPIndex] && gWPArray[goalWPIndex]->inuse &&
06694                         !(gLevelFlags & LEVELFLAG_NOPOINTPREDICTION))
06695                 {
06696                         VectorSubtract(gWPArray[goalWPIndex]->origin, bs->origin, a);
06697                         vectoangles(a, ang);
06698                         VectorCopy(ang, bs->goalAngles);
06699                 }
06700                 else
06701                 {
06702                         VectorSubtract(bs->wpCurrent->origin, bs->origin, a);
06703                         vectoangles(a, ang);
06704                         VectorCopy(ang, bs->goalAngles);
06705                 }
06706 
06707                 if (bs->destinationGrabTime < level.time /*&& (!bs->wpDestination || (bs->currentEnemy && bs->frame_Enemy_Vis))*/)
06708                 {
06709                         GetIdealDestination(bs);
06710                 }
06711                 
06712                 if (bs->wpCurrent && bs->wpDestination)
06713                 {
06714                         if (TotalTrailDistance(bs->wpCurrent->index, bs->wpDestination->index, bs) == -1)
06715                         {
06716                                 bs->wpDestination = NULL;
06717                                 bs->destinationGrabTime = level.time + 10000;
06718                         }
06719                 }
06720 
06721                 if (g_RMG.integer)
06722                 {
06723                         if (bs->frame_Waypoint_Vis)
06724                         {
06725                                 if (bs->wpCurrent && !bs->wpCurrent->flags)
06726                                 {
06727                                         wpTouchDist *= 3;
06728                                 }
06729                         }
06730                 }
06731 
06732                 if (bs->frame_Waypoint_Len < wpTouchDist || (g_RMG.integer && bs->frame_Waypoint_Len < wpTouchDist*2))
06733                 {
06734                         WPTouchRoutine(bs);
06735 
06736                         if (!bs->wpDirection)
06737                         {
06738                                 desiredIndex = bs->wpCurrent->index+1;
06739                         }
06740                         else
06741                         {
06742                                 desiredIndex = bs->wpCurrent->index-1;
06743                         }
06744 
06745                         if (gWPArray[desiredIndex] &&
06746                                 gWPArray[desiredIndex]->inuse &&
06747                                 desiredIndex < gWPNum &&
06748                                 desiredIndex >= 0 &&
06749                                 PassWayCheck(bs, desiredIndex))
06750                         {
06751                                 bs->wpCurrent = gWPArray[desiredIndex];
06752                         }
06753                         else
06754                         {
06755                                 if (bs->wpDestination)
06756                                 {
06757                                         bs->wpDestination = NULL;
06758                                         bs->destinationGrabTime = level.time + 10000;
06759                                 }
06760 
06761                                 if (bs->wpDirection)
06762                                 {
06763                                         bs->wpDirection = 0;
06764                                 }
06765                                 else
06766                                 {
06767                                         bs->wpDirection = 1;
06768                                 }
06769                         }
06770                 }
06771         }
06772         else //We can't find a waypoint, going to need a fallback routine.
06773         {
06774                 /*if (g_gametype.integer == GT_DUEL)*/
06775                 { //helps them get out of messy situations
06776                         /*if ((level.time - bs->forceJumpChargeTime) > 3500)
06777                         {
06778                                 bs->forceJumpChargeTime = level.time + 2000;
06779                                 trap_EA_MoveForward(bs->client);
06780                         }
06781                         */
06782                         bs->jumpTime = level.time + 1500;
06783                         bs->jumpHoldTime = level.time + 1500;
06784                         bs->jDelay = 0;
06785                 }
06786                 doingFallback = BotFallbackNavigation(bs);
06787         }
06788 
06789         if (g_RMG.integer)
06790         { //for RMG if the bot sticks around an area too long, jump around randomly some to spread to a new area (horrible hacky method)
06791                 vec3_t vSubDif;
06792 
06793                 VectorSubtract(bs->origin, bs->lastSignificantAreaChange, vSubDif);
06794                 if (VectorLength(vSubDif) > 1500)
06795                 {
06796                         VectorCopy(bs->origin, bs->lastSignificantAreaChange);
06797                         bs->lastSignificantChangeTime = level.time + 20000;
06798                 }
06799 
06800                 if (bs->lastSignificantChangeTime < level.time)
06801                 {
06802                         bs->iHaveNoIdeaWhereIAmGoing = level.time + 17000;
06803                 }
06804         }
06805 
06806         if (bs->iHaveNoIdeaWhereIAmGoing > level.time && !bs->currentEnemy)
06807         {
06808                 VectorCopy(preFrameGAngles, bs->goalAngles);
06809                 bs->wpCurrent = NULL;
06810                 bs->wpSwitchTime = level.time + 150;
06811                 doingFallback = BotFallbackNavigation(bs);
06812                 bs->jumpTime = level.time + 150;
06813                 bs->jumpHoldTime = level.time + 150;
06814                 bs->jDelay = 0;
06815                 bs->lastSignificantChangeTime = level.time + 25000;
06816         }
06817 
06818         if (bs->wpCurrent && g_RMG.integer)
06819         {
06820                 qboolean doJ = qfalse;
06821 
06822                 if (bs->wpCurrent->origin[2]-192 > bs->origin[2])
06823                 {
06824                         doJ = qtrue;
06825                 }
06826                 else if ((bs->wpTravelTime - level.time) < 5000 && bs->wpCurrent->origin[2]-64 > bs->origin[2])
06827                 {
06828                         doJ = qtrue;
06829                 }
06830                 else if ((bs->wpTravelTime - level.time) < 7000 && (bs->wpCurrent->flags & WPFLAG_RED_FLAG))
06831                 {
06832                         if ((level.time - bs->jumpTime) > 200)
06833                         {
06834                                 bs->jumpTime = level.time + 100;
06835                                 bs->jumpHoldTime = level.time + 100;
06836                                 bs->jDelay = 0;
06837                         }
06838                 }
06839                 else if ((bs->wpTravelTime - level.time) < 7000 && (bs->wpCurrent->flags & WPFLAG_BLUE_FLAG))
06840                 {
06841                         if ((level.time - bs->jumpTime) > 200)
06842                         {
06843                                 bs->jumpTime = level.time + 100;
06844                                 bs->jumpHoldTime = level.time + 100;
06845                                 bs->jDelay = 0;
06846                         }
06847                 }
06848                 else if (bs->wpCurrent->index > 0)
06849                 {
06850                         if ((bs->wpTravelTime - level.time) < 7000)
06851                         {
06852                                 if ((gWPArray[bs->wpCurrent->index-1]->flags & WPFLAG_RED_FLAG) ||
06853                                         (gWPArray[bs->wpCurrent->index-1]->flags & WPFLAG_BLUE_FLAG))
06854                                 {
06855                                         if ((level.time - bs->jumpTime) > 200)
06856                                         {
06857                                                 bs->jumpTime = level.time + 100;
06858                                                 bs->jumpHoldTime = level.time + 100;
06859                                                 bs->jDelay = 0;
06860                                         }
06861                                 }
06862                         }
06863                 }
06864 
06865                 if (doJ)
06866                 {
06867                         bs->jumpTime = level.time + 1500;
06868                         bs->jumpHoldTime = level.time + 1500;
06869                         bs->jDelay = 0;
06870                 }
06871         }
06872 
06873         if (doingFallback)
06874         {
06875                 bs->doingFallback = qtrue;
06876         }
06877         else
06878         {
06879                 bs->doingFallback = qfalse;
06880         }
06881 
06882         if (bs->timeToReact < level.time && bs->currentEnemy && bs->enemySeenTime > level.time + (ENEMY_FORGET_MS - (ENEMY_FORGET_MS*0.2)))
06883         {
06884                 if (bs->frame_Enemy_Vis)
06885                 {
06886                         cBAI = CombatBotAI(bs, thinktime);
06887                 }
06888                 else if (bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT)
06889                 { //keep charging in case we see him again before we lose track of him
06890                         bs->doAltAttack = 1;
06891                 }
06892                 else if (bs->cur_ps.weaponstate == WEAPON_CHARGING)
06893                 { //keep charging in case we see him again before we lose track of him
06894                         bs->doAttack = 1;
06895                 }
06896 
06897                 if (bs->destinationGrabTime > level.time + 100)
06898                 {
06899                         bs->destinationGrabTime = level.time + 100; //assures that we will continue staying within a general area of where we want to be in a combat situation
06900                 }
06901 
06902                 if (bs->currentEnemy->client)
06903                 {
06904                         VectorCopy(bs->currentEnemy->client->ps.origin, headlevel);
06905                         headlevel[2] += bs->currentEnemy->client->ps.viewheight;
06906                 }
06907                 else
06908                 {
06909                         VectorCopy(bs->currentEnemy->client->ps.origin, headlevel);
06910                 }
06911 
06912                 if (!bs->frame_Enemy_Vis)
06913                 {
06914                         //if (!bs->hitSpotted && VectorLength(a) > 256)
06915                         if (OrgVisible(bs->eye, bs->lastEnemySpotted, -1))
06916                         {
06917                                 VectorCopy(bs->lastEnemySpotted, headlevel);
06918                                 VectorSubtract(headlevel, bs->eye, a);
06919                                 vectoangles(a, ang);
06920                                 VectorCopy(ang, bs->goalAngles);
06921 
06922                                 if (bs->cur_ps.weapon == WP_FLECHETTE &&
06923                                         bs->cur_ps.weaponstate == WEAPON_READY &&
06924                                         bs->currentEnemy && bs->currentEnemy->client)
06925                                 {
06926                                         mLen = VectorLength(a) > 128;
06927                                         if (mLen > 128 && mLen < 1024)
06928                                         {
06929                                                 VectorSubtract(bs->currentEnemy->client->ps.origin, bs->lastEnemySpotted, a);
06930 
06931                                                 if (VectorLength(a) < 300)
06932                                                 {
06933                                                         bs->doAltAttack = 1;
06934                                                 }
06935                                         }
06936                                 }
06937                         }
06938                 }
06939                 else
06940                 {
06941                         bLeadAmount = BotWeaponCanLead(bs);
06942                         if ((bs->skills.accuracy/bs->settings.skill) <= 8 &&
06943                                 bLeadAmount)
06944                         {
06945                                 BotAimLeading(bs, headlevel, bLeadAmount);
06946                         }
06947                         else
06948                         {
06949                                 VectorSubtract(headlevel, bs->eye, a);
06950                                 vectoangles(a, ang);
06951                                 VectorCopy(ang, bs->goalAngles);
06952                         }
06953 
06954                         BotAimOffsetGoalAngles(bs);
06955                 }
06956         }
06957 
06958         if (bs->cur_ps.saberInFlight)
06959         {
06960                 bs->saberThrowTime = level.time + Q_irand(4000, 10000);
06961         }
06962 
06963         if (bs->currentEnemy)
06964         {
06965                 if (BotGetWeaponRange(bs) == BWEAPONRANGE_SABER)
06966                 {
06967                         int saberRange = SABER_ATTACK_RANGE;
06968 
06969                         VectorSubtract(bs->currentEnemy->client->ps.origin, bs->eye, a_fo);
06970                         vectoangles(a_fo, a_fo);
06971 
06972                         if (bs->saberPowerTime < level.time)
06973                         { //Don't just use strong attacks constantly, switch around a bit
06974                                 if (Q_irand(1, 10) <= 5)
06975                                 {
06976                                         bs->saberPower = qtrue;
06977                                 }
06978                                 else
06979                                 {
06980                                         bs->saberPower = qfalse;
06981                                 }
06982 
06983                                 bs->saberPowerTime = level.time + Q_irand(3000, 15000);
06984                         }
06985 
06986                         if ( g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_STAFF
06987                                 && g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_DUAL )
06988                         {
06989                                 if (bs->currentEnemy->health > 75 
06990                                         && g_entities[bs->client].client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] > 2)
06991                                 {
06992                                         if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_STRONG 
06993                                                 && bs->saberPower)
06994                                         { //if we are up against someone with a lot of health and we have a strong attack available, then h4q them
06995                                                 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
06996                                         }
06997                                 }
06998                                 else if (bs->currentEnemy->health > 40 
06999                                         && g_entities[bs->client].client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] > 1)
07000                                 {
07001                                         if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_MEDIUM)
07002                                         { //they're down on health a little, use level 2 if we can
07003                                                 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
07004                                         }
07005                                 }
07006                                 else
07007                                 {
07008                                         if (g_entities[bs->client].client->ps.fd.saberAnimLevel != SS_FAST)
07009                                         { //they've gone below 40 health, go at them with quick attacks
07010                                                 Cmd_SaberAttackCycle_f(&g_entities[bs->client]);
07011                                         }
07012                                 }
07013                         }
07014 
07015                         if (g_gametype.integer == GT_SINGLE_PLAYER)
07016                         {
07017                                 saberRange *= 3;
07018                         }
07019 
07020                         if (bs->frame_Enemy_Len <= saberRange)
07021                         {
07022                                 SaberCombatHandling(bs);
07023 
07024                                 if (bs->frame_Enemy_Len < 80)
07025                                 {
07026                                         meleestrafe = 1;
07027                                 }
07028                         }
07029                         else if (bs->saberThrowTime < level.time && !bs->cur_ps.saberInFlight &&
07030                                 (bs->cur_ps.fd.forcePowersKnown & (1 << FP_SABERTHROW)) &&
07031                                 InFieldOfVision(bs->viewangles, 30, a_fo) &&
07032                                 bs->frame_Enemy_Len < BOT_SABER_THROW_RANGE &&
07033                                 bs->cur_ps.fd.saberAnimLevel != SS_STAFF)
07034                         {
07035                                 bs->doAltAttack = 1;
07036                                 bs->doAttack = 0;
07037                         }
07038                         else if (bs->cur_ps.saberInFlight && bs->frame_Enemy_Len > 300 && bs->frame_Enemy_Len < BOT_SABER_THROW_RANGE)
07039                         {
07040                                 bs->doAltAttack = 1;
07041                                 bs->doAttack = 0;
07042                         }
07043                 }
07044                 else if (BotGetWeaponRange(bs) == BWEAPONRANGE_MELEE)
07045                 {
07046                         if (bs->frame_Enemy_Len <= MELEE_ATTACK_RANGE)
07047                         {
07048                                 MeleeCombatHandling(bs);
07049                                 meleestrafe = 1;
07050                         }
07051                 }
07052         }
07053 
07054         if (doingFallback && bs->currentEnemy) //just stand and fire if we have no idea where we are
07055         {
07056                 VectorCopy(bs->origin, bs->goalPosition);
07057         }
07058 
07059         if (bs->forceJumping > level.time)
07060         {
07061                 VectorCopy(bs->origin, noz_x);
07062                 VectorCopy(bs->goalPosition, noz_y);
07063 
07064                 noz_x[2] = noz_y[2];
07065 
07066                 VectorSubtract(noz_x, noz_y, noz_x);
07067 
07068                 if (VectorLength(noz_x) < 32)
07069                 {
07070                         fjHalt = 1;
07071                 }
07072         }
07073 
07074         if (bs->doChat && bs->chatTime > level.time && (!bs->currentEnemy || !bs->frame_Enemy_Vis))
07075         {
07076                 return;
07077         }
07078         else if (bs->doChat && bs->currentEnemy && bs->frame_Enemy_Vis)
07079         {
07080                 //bs->chatTime = level.time + bs->chatTime_stored;
07081                 bs->doChat = 0; //do we want to keep the bot waiting to chat until after the enemy is gone?
07082                 bs->chatTeam = 0;
07083         }
07084         else if (bs->doChat && bs->chatTime <= level.time)
07085         {
07086                 if (bs->chatTeam)
07087                 {
07088                         trap_EA_SayTeam(bs->client, bs->currentChat);
07089                         bs->chatTeam = 0;
07090                 }
07091                 else
07092                 {
07093                         trap_EA_Say(bs->client, bs->currentChat);
07094                 }
07095                 if (bs->doChat == 2)
07096                 {
07097                         BotReplyGreetings(bs);
07098                 }
07099                 bs->doChat = 0;
07100         }
07101 
07102         CTFFlagMovement(bs);
07103 
07104         if (/*bs->wpDestination &&*/ bs->shootGoal &&
07105                 /*bs->wpDestination->associated_entity == bs->shootGoal->s.number &&*/
07106                 bs->shootGoal->health > 0 && bs->shootGoal->takedamage)
07107         {
07108                 dif[0] = (bs->shootGoal->r.absmax[0]+bs->shootGoal->r.absmin[0])/2;
07109                 dif[1] = (bs->shootGoal->r.absmax[1]+bs->shootGoal->r.absmin[1])/2;
07110                 dif[2] = (bs->shootGoal->r.absmax[2]+bs->shootGoal->r.absmin[2])/2;
07111 
07112                 if (!bs->currentEnemy || bs->frame_Enemy_Len > 256)
07113                 { //if someone is close then don't stop shooting them for this
07114                         VectorSubtract(dif, bs->eye, a);
07115                         vectoangles(a, a);
07116                         VectorCopy(a, bs->goalAngles);
07117 
07118                         if (InFieldOfVision(bs->viewangles, 30, a) &&
07119                                 EntityVisibleBox(bs->origin, NULL, NULL, dif, bs->client, bs->shootGoal->s.number))
07120                         {
07121                                 bs->doAttack = 1;
07122                         }
07123                 }
07124         }
07125 
07126         if (bs->cur_ps.hasDetPackPlanted)
07127         { //check if our enemy gets near it and detonate if he does
07128                 BotCheckDetPacks(bs);
07129         }
07130         else if (bs->currentEnemy && bs->lastVisibleEnemyIndex == bs->currentEnemy->s.number && !bs->frame_Enemy_Vis && bs->plantTime < level.time &&
07131                 !bs->doAttack && !bs->doAltAttack)
07132         {
07133                 VectorSubtract(bs->origin, bs->hereWhenSpotted, a);
07134 
07135                 if (bs->plantDecided > level.time || (bs->frame_Enemy_Len < BOT_PLANT_DISTANCE*2 && VectorLength(a) < BOT_PLANT_DISTANCE))
07136                 {
07137                         mineSelect = BotSelectChoiceWeapon(bs, WP_TRIP_MINE, 0);
07138                         detSelect = BotSelectChoiceWeapon(bs, WP_DET_PACK, 0);
07139                         if (bs->cur_ps.hasDetPackPlanted)
07140                         {
07141                                 detSelect = 0;
07142                         }
07143 
07144                         if (bs->plantDecided > level.time && bs->forceWeaponSelect &&
07145                                 bs->cur_ps.weapon == bs->forceWeaponSelect)
07146                         {
07147                                 bs->doAttack = 1;
07148                                 bs->plantDecided = 0;
07149                                 bs->plantTime = level.time + BOT_PLANT_INTERVAL;
07150                                 bs->plantContinue = level.time + 500;
07151                                 bs->beStill = level.time + 500;
07152                         }
07153                         else if (mineSelect || detSelect)
07154                         {
07155                                 if (BotSurfaceNear(bs))
07156                                 {
07157                                         if (!mineSelect)
07158                                         { //if no mines use detpacks, otherwise use mines
07159                                                 mineSelect = WP_DET_PACK;
07160                                         }
07161                                         else
07162                                         {
07163                                                 mineSelect = WP_TRIP_MINE;
07164                                         }
07165 
07166                                         detSelect = BotSelectChoiceWeapon(bs, mineSelect, 1);
07167 
07168                                         if (detSelect && detSelect != 2)
07169                                         { //We have it and it is now our weapon
07170                                                 bs->plantDecided = level.time + 1000;
07171                                                 bs->forceWeaponSelect = mineSelect;
07172                                                 return;
07173                                         }
07174                                         else if (detSelect == 2)
07175                                         {
07176                                                 bs->forceWeaponSelect = mineSelect;
07177                                                 return;
07178                                         }
07179                                 }
07180                         }
07181                 }
07182         }
07183         else if (bs->plantContinue < level.time)
07184         {
07185                 bs->forceWeaponSelect = 0;
07186         }
07187 
07188         if (g_gametype.integer == GT_JEDIMASTER && !bs->cur_ps.isJediMaster && bs->jmState == -1 && gJMSaberEnt && gJMSaberEnt->inuse)
07189         {
07190                 vec3_t saberLen;
07191                 float fSaberLen = 0;
07192 
07193                 VectorSubtract(bs->origin, gJMSaberEnt->r.currentOrigin, saberLen);
07194                 fSaberLen = VectorLength(saberLen);
07195 
07196                 if (fSaberLen < 256)
07197                 {
07198                         if (OrgVisible(bs->origin, gJMSaberEnt->r.currentOrigin, bs->client))
07199                         {
07200                                 VectorCopy(gJMSaberEnt->r.currentOrigin, bs->goalPosition);
07201                         }
07202                 }
07203         }
07204 
07205         if (bs->beStill < level.time && !WaitingForNow(bs, bs->goalPosition) && !fjHalt)
07206         {
07207                 VectorSubtract(bs->goalPosition, bs->origin, bs->goalMovedir);
07208                 VectorNormalize(bs->goalMovedir);
07209 
07210                 if (bs->jumpTime > level.time && bs->jDelay < level.time &&
07211                         level.clients[bs->client].pers.cmd.upmove > 0)
07212                 {
07213                 //      trap_EA_Move(bs->client, bs->origin, 5000);
07214                         bs->beStill = level.time + 200;
07215                 }
07216                 else
07217                 {
07218                         trap_EA_Move(bs->client, bs->goalMovedir, 5000);
07219                 }
07220 
07221                 if (meleestrafe)
07222                 {
07223                         StrafeTracing(bs);
07224                 }
07225 
07226                 if (bs->meleeStrafeDir && meleestrafe && bs->meleeStrafeDisable < level.time)
07227                 {
07228                         trap_EA_MoveRight(bs->client);
07229                 }
07230                 else if (meleestrafe && bs->meleeStrafeDisable < level.time)
07231                 {
07232                         trap_EA_MoveLeft(bs->client);
07233                 }
07234 
07235                 if (BotTrace_Jump(bs, bs->goalPosition))
07236                 {
07237                         bs->jumpTime = level.time + 100;
07238                 }
07239                 else if (BotTrace_Duck(bs, bs->goalPosition))
07240                 {
07241                         bs->duckTime = level.time + 100;
07242                 }
07243 #ifdef BOT_STRAFE_AVOIDANCE
07244                 else
07245                 {
07246                         int strafeAround = BotTrace_Strafe(bs, bs->goalPosition);
07247 
07248                         if (strafeAround == STRAFEAROUND_RIGHT)
07249                         {
07250                                 trap_EA_MoveRight(bs->client);
07251                         }
07252                         else if (strafeAround == STRAFEAROUND_LEFT)
07253                         {
07254                                 trap_EA_MoveLeft(bs->client);
07255                         }
07256                 }
07257 #endif
07258         }
07259 
07260 #ifndef FORCEJUMP_INSTANTMETHOD
07261         if (bs->forceJumpChargeTime > level.time)
07262         {
07263                 bs->jumpTime = 0;
07264         }
07265 #endif
07266 
07267         if (bs->jumpPrep > level.time)
07268         {
07269                 bs->forceJumpChargeTime = 0;
07270         }
07271 
07272         if (bs->forceJumpChargeTime > level.time)
07273         {
07274                 bs->jumpHoldTime = ((bs->forceJumpChargeTime - level.time)/2) + level.time;
07275                 bs->forceJumpChargeTime = 0;
07276         }
07277 
07278         if (bs->jumpHoldTime > level.time)
07279         {
07280                 bs->jumpTime = bs->jumpHoldTime;
07281         }
07282 
07283         if (bs->jumpTime > level.time && bs->jDelay < level.time)
07284         {
07285                 if (bs->jumpHoldTime > level.time)
07286                 {
07287                         trap_EA_Jump(bs->client);
07288                         if (bs->wpCurrent)
07289                         {
07290                                 if ((bs->wpCurrent->origin[2] - bs->origin[2]) < 64)
07291                                 {
07292                                         trap_EA_MoveForward(bs->client);
07293                                 }
07294                         }
07295                         else
07296                         {
07297                                 trap_EA_MoveForward(bs->client);
07298                         }
07299                         if (g_entities[bs->client].client->ps.groundEntityNum == ENTITYNUM_NONE)
07300                         {
07301                                 g_entities[bs->client].client->ps.pm_flags |= PMF_JUMP_HELD;
07302                         }
07303                 }
07304                 else if (!(bs->cur_ps.pm_flags & PMF_JUMP_HELD))
07305                 {
07306                         trap_EA_Jump(bs->client);
07307                 }
07308         }
07309 
07310         if (bs->duckTime > level.time)
07311         {
07312                 trap_EA_Crouch(bs->client);
07313         }
07314 
07315         if ( bs->dangerousObject && bs->dangerousObject->inuse && bs->dangerousObject->health > 0 &&
07316                 bs->dangerousObject->takedamage && (!bs->frame_Enemy_Vis || !bs->currentEnemy) &&
07317                 (BotGetWeaponRange(bs) == BWEAPONRANGE_MID || BotGetWeaponRange(bs) == BWEAPONRANGE_LONG) &&
07318                 bs->cur_ps.weapon != WP_DET_PACK && bs->cur_ps.weapon != WP_TRIP_MINE &&
07319                 !bs->shootGoal )
07320         {
07321                 float danLen;
07322 
07323                 VectorSubtract(bs->dangerousObject->r.currentOrigin, bs->eye, a);
07324 
07325                 danLen = VectorLength(a);
07326 
07327                 if (danLen > 256)
07328                 {
07329                         vectoangles(a, a);
07330                         VectorCopy(a, bs->goalAngles);
07331 
07332                         if (Q_irand(1, 10) < 5)
07333                         {
07334                                 bs->goalAngles[YAW] += Q_irand(0, 3);
07335                                 bs->goalAngles[PITCH] += Q_irand(0, 3);
07336                         }
07337                         else
07338                         {
07339                                 bs->goalAngles[YAW] -= Q_irand(0, 3);
07340                                 bs->goalAngles[PITCH] -= Q_irand(0, 3);
07341                         }
07342 
07343                         if (InFieldOfVision(bs->viewangles, 30, a) &&
07344                                 EntityVisibleBox(bs->origin, NULL, NULL, bs->dangerousObject->r.currentOrigin, bs->client, bs->dangerousObject->s.number))
07345                         {
07346                                 bs->doAttack = 1;
07347                         }                       
07348                 }
07349         }
07350 
07351         if (PrimFiring(bs) ||
07352                 AltFiring(bs))
07353         {
07354                 friendInLOF = CheckForFriendInLOF(bs);
07355 
07356                 if (friendInLOF)
07357                 {
07358                         if (PrimFiring(bs))
07359                         {
07360                                 KeepPrimFromFiring(bs);
07361                         }
07362                         if (AltFiring(bs))
07363                         {
07364                                 KeepAltFromFiring(bs);
07365                         }
07366                         if (useTheForce && forceHostile)
07367                         {
07368                                 useTheForce = 0;
07369                         }
07370 
07371                         if (!useTheForce && friendInLOF->client)
07372                         { //we have a friend here and are not currently using force powers, see if we can help them out
07373                                 if (friendInLOF->health <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL])
07374                                 {
07375                                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_HEAL;
07376                                         useTheForce = 1;
07377                                         forceHostile = 0;
07378                                 }
07379                                 else if (friendInLOF->client->ps.fd.forcePower <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_FORCE]][FP_TEAM_FORCE])
07380                                 {
07381                                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_FORCE;
07382                                         useTheForce = 1;
07383                                         forceHostile = 0;
07384                                 }
07385                         }
07386                 }
07387         }
07388         else if (g_gametype.integer >= GT_TEAM)
07389         { //still check for anyone to help..
07390                 friendInLOF = CheckForFriendInLOF(bs);
07391 
07392                 if (!useTheForce && friendInLOF)
07393                 {
07394                         if (friendInLOF->health <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL])
07395                         {
07396                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_HEAL;
07397                                 useTheForce = 1;
07398                                 forceHostile = 0;
07399                         }
07400                         else if (friendInLOF->client->ps.fd.forcePower <= 50 && level.clients[bs->client].ps.fd.forcePower > forcePowerNeeded[level.clients[bs->client].ps.fd.forcePowerLevel[FP_TEAM_FORCE]][FP_TEAM_FORCE])
07401                         {
07402                                 level.clients[bs->client].ps.fd.forcePowerSelected = FP_TEAM_FORCE;
07403                                 useTheForce = 1;
07404                                 forceHostile = 0;
07405                         }
07406                 }
07407         }
07408 
07409         if (bs->doAttack && bs->cur_ps.weapon == WP_DET_PACK &&
07410                 bs->cur_ps.hasDetPackPlanted)
07411         { //maybe a bit hackish, but bots only want to plant one of these at any given time to avoid complications
07412                 bs->doAttack = 0;
07413         }
07414 
07415         if (bs->doAttack && bs->cur_ps.weapon == WP_SABER &&
07416                 bs->saberDefending && bs->currentEnemy && bs->currentEnemy->client &&
07417                 BotWeaponBlockable(bs->currentEnemy->client->ps.weapon) )
07418         {
07419                 bs->doAttack = 0;
07420         }
07421 
07422         if (bs->cur_ps.saberLockTime > level.time)
07423         {
07424                 if (rand()%10 < 5)
07425                 {
07426                         bs->doAttack = 1;
07427                 }
07428                 else
07429                 {
07430                         bs->doAttack = 0;
07431                 }
07432         }
07433 
07434         if (bs->botChallengingTime > level.time)
07435         {
07436                 bs->doAttack = 0;
07437                 bs->doAltAttack = 0;
07438         }
07439 
07440         if (bs->cur_ps.weapon == WP_SABER &&
07441                 bs->cur_ps.saberInFlight &&
07442                 !bs->cur_ps.saberEntityNum)
07443         { //saber knocked away, keep trying to get it back
07444                 bs->doAttack = 1;
07445                 bs->doAltAttack = 0;
07446         }
07447 
07448         if (bs->doAttack)
07449         {
07450                 trap_EA_Attack(bs->client);
07451         }
07452         else if (bs->doAltAttack)
07453         {
07454                 trap_EA_Alt_Attack(bs->client);
07455         }
07456 
07457         if (useTheForce && forceHostile && bs->botChallengingTime > level.time)
07458         {
07459                 useTheForce = qfalse;
07460         }
07461 
07462         if (useTheForce)
07463         {
07464 #ifndef FORCEJUMP_INSTANTMETHOD
07465                 if (bs->forceJumpChargeTime > level.time)
07466                 {
07467                         level.clients[bs->client].ps.fd.forcePowerSelected = FP_LEVITATION;
07468                         trap_EA_ForcePower(bs->client);
07469                 }
07470                 else
07471                 {
07472 #endif
07473                         if (bot_forcepowers.integer && !g_forcePowerDisable.integer)
07474                         {
07475                                 trap_EA_ForcePower(bs->client);
07476                         }
07477 #ifndef FORCEJUMP_INSTANTMETHOD
07478                 }
07479 #endif
07480         }
07481 
07482         MoveTowardIdealAngles(bs);
07483 }


Variable Documentation

vmCvar_t bot_attachments
 

Definition at line 374 of file ai_main.h.

Referenced by BotAISetup(), BotAIStartFrame(), BotLovedOneDied(), GetLoveLevel(), and PassLovedOneCheck().

vmCvar_t bot_camp
 

Definition at line 375 of file ai_main.h.

Referenced by BotAISetup(), BotAIStartFrame(), and WPTouchRoutine().

vmCvar_t bot_forcepowers
 

Definition at line 366 of file ai_main.h.

Referenced by BotAISetup(), and StandardBotAI().

vmCvar_t bot_forgimmick
 

Definition at line 367 of file ai_main.h.

Referenced by BotAISetup(), BotAIStartFrame(), and StandardBotAI().

vmCvar_t bot_honorableduelacceptance
 

Definition at line 368 of file ai_main.h.

Referenced by BotAISetup(), BotAIStartFrame(), and StandardBotAI().

vmCvar_t bot_wp_clearweight
 

Definition at line 379 of file ai_main.h.

Referenced by BotAISetup(), and CalculateWeightGoals().

vmCvar_t bot_wp_distconnect
 

Definition at line 380 of file ai_main.h.

Referenced by BotAISetup(), and RepairPaths().

vmCvar_t bot_wp_edit
 

Definition at line 378 of file ai_main.h.

Referenced by BotAISetup(), and LoadPath_ThisLevel().

vmCvar_t bot_wp_info
 

Definition at line 377 of file ai_main.h.

Referenced by BotAISetup(), BotAIStartFrame(), and BotWaypointRender().

vmCvar_t bot_wp_visconnect
 

Definition at line 381 of file ai_main.h.

Referenced by BotAISetup(), and RepairPaths().

gentity_t* eFlagBlue
 

Definition at line 389 of file ai_main.h.

Referenced by CTFTakesPriority(), FlagObjects(), and LoadPath_ThisLevel().

gentity_t* eFlagRed
 

Definition at line 388 of file ai_main.h.

Referenced by CTFTakesPriority(), FlagObjects(), and LoadPath_ThisLevel().

wpobject_t* flagBlue
 

Definition at line 385 of file ai_main.h.

Referenced by BotDefendFlag(), BotGetEnemyFlag(), BotGetFlagHome(), CreateNewWP_FromObject(), CTFFlagMovement(), CTFTakesPriority(), FlagObjects(), and GetNewFlagPoint().

wpobject_t* flagRed
 

Definition at line 383 of file ai_main.h.

Referenced by BotDefendFlag(), BotGetEnemyFlag(), BotGetFlagHome(), CreateNewWP_FromObject(), CTFFlagMovement(), CTFTakesPriority(), FlagObjects(), and GetNewFlagPoint().

float floattime
 

Definition at line 410 of file ai_main.h.

char gBotChatBuffer[MAX_CLIENTS][MAX_CHAT_BUFFER_SIZE]
 

Definition at line 391 of file ai_main.h.

Referenced by BotDoChat(), BotUtilizePersonality(), and ReadChatGroups().

float gBotEdit
 

Definition at line 394 of file ai_main.h.

Referenced by AcceptBotCommand(), BotAIStartFrame(), BotWaypointRender(), and LoadPath_ThisLevel().

float gDeactivated
 

Definition at line 393 of file ai_main.h.

Referenced by AcceptBotCommand(), and StandardBotAI().

int gLastPrintedIndex
 

Definition at line 402 of file ai_main.h.

Referenced by BotWaypointRender().

int gLevelFlags
 

Definition at line 408 of file ai_main.h.

Referenced by BotIsAChickenWuss(), LoadPath_ThisLevel(), LoadPathData(), PassStandardEnemyChecks(), and StandardBotAI().

wpobject_t* gWPArray[MAX_WPARRAY_SIZE]
 

Definition at line 398 of file ai_main.h.

Referenced by AcceptBotCommand(), B_InitAlloc(), BeginAutoPathRoutine(), BotGetFlagBack(), BotGuardFlagCarrier(), BotWaypointRender(), CalculateJumpRoutes(), CalculatePaths(), CalculateSiegeGoals(), CalculateWeightGoals(), CanForceJumpTo(), CheckForShorterRoutes(), ConnectTrail(), CreateNewWP(), CreateNewWP_FromObject(), CreateNewWP_InsertUnder(), CreateNewWP_InTrail(), CTFTakesPriority(), DoorBlockingSection(), FlagObjects(), GetBestIdleGoal(), GetIdealDestination(), GetNearestVisibleWP(), GetNearestVisibleWPToItem(), GetNewFlagPoint(), JMTakesPriority(), OpposingEnds(), PassWayCheck(), RemoveWP(), RemoveWP_InTrail(), RepairPaths(), SavePathData(), Siege_DefendFromAttackers(), Siege_TargetClosestObjective(), SiegeTakesPriority(), StandardBotAI(), TeleportToWP(), TotalTrailDistance(), TransferWPData(), WPFlagsModify(), and WPTouchRoutine().

int gWPNum
 

Definition at line 399 of file ai_main.h.

Referenced by AcceptBotCommand(), BeginAutoPathRoutine(), BotWaypointRender(), CalculateJumpRoutes(), CalculatePaths(), CalculateWeightGoals(), CreateNewWP(), CreateNewWP_FromObject(), CreateNewWP_InsertUnder(), CreateNewWP_InTrail(), FlagObjects(), G_BackwardAttachment(), G_RMGPathing(), GetBestIdleGoal(), GetNearestVisibleWP(), GetNearestVisibleWPToItem(), GetNewFlagPoint(), RemoveAllWP(), RemoveWP(), RemoveWP_InTrail(), RepairPaths(), SavePathData(), Siege_TargetClosestObjective(), StandardBotAI(), TeleportToWP(), TotalTrailDistance(), and WPFlagsModify().

int gWPRenderedFrame
 

Definition at line 395 of file ai_main.h.

Referenced by BotWaypointRender().

float gWPRenderTime
 

Definition at line 392 of file ai_main.h.

Referenced by BotWaypointRender().

int nodenum
 

Definition at line 406 of file ai_main.h.

Referenced by ConnectTrail(), G_NearestNodeToPoint(), G_NodeClearFlags(), G_NodeClearForNext(), G_NodeMatchingXY(), G_NodeMatchingXY_BA(), G_RMGPathing(), and NodeHere().

nodeobject_t nodetable[MAX_NODETABLE_SIZE]
 

Definition at line 404 of file ai_main.h.

Referenced by ConnectTrail(), G_BackwardAttachment(), G_NearestNodeToPoint(), G_NodeClearFlags(), G_NodeClearForNext(), G_NodeMatchingXY(), G_NodeMatchingXY_BA(), G_RecursiveConnection(), G_RMGPathing(), and NodeHere().

wpobject_t* oFlagBlue
 

Definition at line 386 of file ai_main.h.

Referenced by CreateNewWP_FromObject(), CTFTakesPriority(), and FlagObjects().

wpobject_t* oFlagRed
 

Definition at line 384 of file ai_main.h.

Referenced by CreateNewWP_FromObject(), CTFTakesPriority(), and FlagObjects().