codemp/game/ai_main.c File Reference

#include "g_local.h"
#include "q_shared.h"
#include "botlib.h"
#include "be_aas.h"
#include "be_ea.h"
#include "be_ai_char.h"
#include "be_ai_chat.h"
#include "be_ai_gen.h"
#include "be_ai_goal.h"
#include "be_ai_move.h"
#include "be_ai_weap.h"
#include "ai_main.h"
#include "w_saber.h"
#include "chars.h"
#include "inv.h"
#include "syn.h"

Go to the source code of this file.

Defines

#define MAX_PATH   144
#define BOT_THINK_TIME   0
#define BOT_STRAFE_AVOIDANCE
#define STRAFEAROUND_RIGHT   1
#define STRAFEAROUND_LEFT   2

Functions

void BotStraightTPOrderCheck (gentity_t *ent, int ordernum, bot_state_t *bs)
void BotSelectWeapon (int client, int weapon)
void BotReportStatus (bot_state_t *bs)
void BotOrder (gentity_t *ent, int clientnum, int ordernum)
int BotMindTricked (int botClient, int enemyClient)
int BotGetWeaponRange (bot_state_t *bs)
int PassLovedOneCheck (bot_state_t *bs, gentity_t *ent)
void ExitLevel (void)
void QDECL BotAI_Print (int type, char *fmt,...)
qboolean WP_ForcePowerUsable (gentity_t *self, forcePowers_t forcePower)
int IsTeamplay (void)
int BotAI_GetClientState (int clientNum, playerState_t *state)
int BotAI_GetEntityState (int entityNum, entityState_t *state)
int BotAI_GetSnapshotEntity (int clientNum, int sequence, entityState_t *state)
void BotEntityInfo (int entnum, aas_entityinfo_t *info)
int NumBots (void)
float AngleDifference (float ang1, float ang2)
float BotChangeViewAngle (float angle, float ideal_angle, float speed)
void BotChangeViewAngles (bot_state_t *bs, float thinktime)
void BotInputToUserCommand (bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time, int useTime)
void BotUpdateInput (bot_state_t *bs, int time, int elapsed_time)
void BotAIRegularUpdate (void)
void RemoveColorEscapeSequences (char *text)
int BotAI (int client, float thinktime)
void BotScheduleBotThink (void)
int PlayersInGame (void)
int BotAISetupClient (int client, struct bot_settings_s *settings, qboolean restart)
int BotAIShutdownClient (int client, qboolean restart)
void BotResetState (bot_state_t *bs)
int BotAILoadMap (int restart)
int OrgVisible (vec3_t org1, vec3_t org2, int ignore)
int WPOrgVisible (gentity_t *bot, vec3_t org1, vec3_t org2, int ignore)
int OrgVisibleBox (vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore)
int CheckForFunc (vec3_t org, int ignore)
qboolean BotPVSCheck (const vec3_t p1, const vec3_t p2)
int GetNearestVisibleWP (vec3_t org, int ignore)
int PassWayCheck (bot_state_t *bs, int windex)
float TotalTrailDistance (int start, int end, bot_state_t *bs)
void CheckForShorterRoutes (bot_state_t *bs, int newwpindex)
void WPConstantRoutine (bot_state_t *bs)
qboolean BotCTFGuardDuty (bot_state_t *bs)
void WPTouchRoutine (bot_state_t *bs)
void MoveTowardIdealAngles (bot_state_t *bs)
int BotTrace_Strafe (bot_state_t *bs, vec3_t traceto)
int BotTrace_Jump (bot_state_t *bs, vec3_t traceto)
int BotTrace_Duck (bot_state_t *bs, vec3_t traceto)
int PassStandardEnemyChecks (bot_state_t *bs, gentity_t *en)
void BotDamageNotification (gclient_t *bot, gentity_t *attacker)
int BotCanHear (bot_state_t *bs, gentity_t *en, float endist)
void UpdateEventTracker (void)
int InFieldOfVision (vec3_t viewangles, float fov, vec3_t angles)
qboolean G_ThereIsAMaster (void)
int ScanForEnemies (bot_state_t *bs)
int WaitingForNow (bot_state_t *bs, vec3_t goalpos)
int BotIsAChickenWuss (bot_state_t *bs)
gentity_tGetNearestBadThing (bot_state_t *bs)
int BotDefendFlag (bot_state_t *bs)
int BotGetEnemyFlag (bot_state_t *bs)
int BotGetFlagBack (bot_state_t *bs)
int BotGuardFlagCarrier (bot_state_t *bs)
int BotGetFlagHome (bot_state_t *bs)
void GetNewFlagPoint (wpobject_t *wp, gentity_t *flagEnt, int team)
int CTFTakesPriority (bot_state_t *bs)
int EntityVisibleBox (vec3_t org1, vec3_t mins, vec3_t maxs, vec3_t org2, int ignore, int ignore2)
int Siege_TargetClosestObjective (bot_state_t *bs, int flag)
void Siege_DefendFromAttackers (bot_state_t *bs)
int Siege_CountDefenders (bot_state_t *bs)
int Siege_CountTeammates (bot_state_t *bs)
int SiegeTakesPriority (bot_state_t *bs)
int JMTakesPriority (bot_state_t *bs)
int BotHasAssociated (bot_state_t *bs, wpobject_t *wp)
int GetBestIdleGoal (bot_state_t *bs)
void GetIdealDestination (bot_state_t *bs)
void CommanderBotCTFAI (bot_state_t *bs)
void CommanderBotSiegeAI (bot_state_t *bs)
void BotDoTeamplayAI (bot_state_t *bs)
void CommanderBotTeamplayAI (bot_state_t *bs)
void CommanderBotAI (bot_state_t *bs)
void MeleeCombatHandling (bot_state_t *bs)
void SaberCombatHandling (bot_state_t *bs)
float BotWeaponCanLead (bot_state_t *bs)
void BotAimLeading (bot_state_t *bs, vec3_t headlevel, float leadAmount)
void BotAimOffsetGoalAngles (bot_state_t *bs)
int ShouldSecondaryFire (bot_state_t *bs)
int CombatBotAI (bot_state_t *bs, float thinktime)
int BotFallbackNavigation (bot_state_t *bs)
int BotTryAnotherWeapon (bot_state_t *bs)
qboolean BotWeaponSelectable (bot_state_t *bs, int weapon)
int BotSelectIdealWeapon (bot_state_t *bs)
int BotSelectChoiceWeapon (bot_state_t *bs, int weapon, int doselection)
int BotSelectMelee (bot_state_t *bs)
int GetLoveLevel (bot_state_t *bs, bot_state_t *love)
void BotLovedOneDied (bot_state_t *bs, bot_state_t *loved, int lovelevel)
void BotDeathNotify (bot_state_t *bs)
void StrafeTracing (bot_state_t *bs)
int PrimFiring (bot_state_t *bs)
int KeepPrimFromFiring (bot_state_t *bs)
int AltFiring (bot_state_t *bs)
int KeepAltFromFiring (bot_state_t *bs)
gentity_tCheckForFriendInLOF (bot_state_t *bs)
void BotScanForLeader (bot_state_t *bs)
void BotReplyGreetings (bot_state_t *bs)
void CTFFlagMovement (bot_state_t *bs)
void BotCheckDetPacks (bot_state_t *bs)
int BotUseInventoryItem (bot_state_t *bs)
int BotSurfaceNear (bot_state_t *bs)
int BotWeaponBlockable (int weapon)
void Cmd_EngageDuel_f (gentity_t *ent)
void Cmd_ToggleSaber_f (gentity_t *ent)
void Bot_SetForcedMovement (int bot, int forward, int right, int up)
void StandardBotAI (bot_state_t *bs, float thinktime)
int BotAIStartFrame (int time)
int BotAISetup (int restart)
int BotAIShutdown (int restart)

Variables

bot_state_tbotstates [MAX_CLIENTS]
int numbots
float floattime
float regularupdate_time
int rebel_attackers
int imperial_attackers
boteventtracker_t gBotEventTracker [MAX_CLIENTS]
vmCvar_t bot_forcepowers
vmCvar_t bot_forgimmick
vmCvar_t bot_honorableduelacceptance
vmCvar_t bot_pvstype
vmCvar_t bot_normgpath
vmCvar_t bot_getinthecarrr
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_tdroppedRedFlag
gentity_teFlagBlue
gentity_tdroppedBlueFlag
char * ctfStateNames []
char * ctfStateDescriptions []
char * siegeStateDescriptions []
char * teamplayStateDescriptions []
int gUpdateVars = 0


Define Documentation

#define BOT_STRAFE_AVOIDANCE
 

Definition at line 1548 of file ai_main.c.

#define BOT_THINK_TIME   0
 

Definition at line 43 of file ai_main.c.

Referenced by BotAIStartFrame(), and BotScheduleBotThink().

#define MAX_PATH   144
 

Definition at line 41 of file ai_main.c.

#define STRAFEAROUND_LEFT   2
 

Definition at line 1552 of file ai_main.c.

Referenced by BotTrace_Strafe(), and StandardBotAI().

#define STRAFEAROUND_RIGHT   1
 

Definition at line 1551 of file ai_main.c.

Referenced by BotTrace_Strafe(), and StandardBotAI().


Function Documentation

int AltFiring bot_state_t bs  ) 
 

Definition at line 5502 of file ai_main.c.

References bot_state_t, bot_state_s::cur_ps, bot_state_s::doAltAttack, WEAPON_CHARGING_ALT, and playerState_s::weaponstate.

Referenced by StandardBotAI().

05503 {
05504         if (bs->cur_ps.weaponstate != WEAPON_CHARGING_ALT &&
05505                 bs->doAltAttack)
05506         {
05507                 return 1;
05508         }
05509 
05510         if (bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT &&
05511                 !bs->doAltAttack)
05512         {
05513                 return 1;
05514         }
05515 
05516         return 0;
05517 }

float AngleDifference float  ang1,
float  ang2
 

Definition at line 425 of file ai_main.c.

Referenced by BotChangeViewAngles(), and BotTrace_Strafe().

00425                                               {
00426         float diff;
00427 
00428         diff = ang1 - ang2;
00429         if (ang1 > ang2) {
00430                 if (diff > 180.0) diff -= 360.0;
00431         }
00432         else {
00433                 if (diff < -180.0) diff += 360.0;
00434         }
00435         return diff;
00436 }

void Bot_SetForcedMovement int  bot,
int  forward,
int  right,
int  up
 

Definition at line 5883 of file ai_main.c.

References bot_state_t, botstates, bot_state_s::forceMove_Forward, bot_state_s::forceMove_Right, and bot_state_s::forceMove_Up.

Referenced by ClientCommand().

05884 {
05885         bot_state_t *bs;
05886 
05887         bs = botstates[bot];
05888 
05889         if (!bs)
05890         { //not a bot
05891                 return;
05892         }
05893 
05894         if (forward != -1)
05895         {
05896                 if (bs->forceMove_Forward)
05897                 {
05898                         bs->forceMove_Forward = 0;
05899                 }
05900                 else
05901                 {
05902                         bs->forceMove_Forward = forward;
05903                 }
05904         }
05905         if (right != -1)
05906         {
05907                 if (bs->forceMove_Right)
05908                 {
05909                         bs->forceMove_Right = 0;
05910                 }
05911                 else
05912                 {
05913                         bs->forceMove_Right = right;
05914                 }
05915         }
05916         if (up != -1)
05917         {
05918                 if (bs->forceMove_Up)
05919                 {
05920                         bs->forceMove_Up = 0;
05921                 }
05922                 else
05923                 {
05924                         bs->forceMove_Up = up;
05925                 }
05926         }
05927 }

int BotAI int  client,
float  thinktime
 

Definition at line 696 of file ai_main.c.

References AngleMod(), bot_state_t, BotAI_GetClientState(), BotAI_Print(), botstates, client, Com_Printf(), bot_state_s::cur_ps, playerState_s::delta_angles, bot_state_s::eye, vmCvar_t::integer, bot_state_s::inuse, bot_state_s::ltime, bot_state_s::origin, playerState_s::origin, PRT_FATAL, Q_stricmp(), qfalse, qtrue, RemoveColorEscapeSequences(), SHORT2ANGLE, StandardBotAI(), strchr(), bot_state_s::thinktime, trap_BotGetServerCommand(), trap_Cvar_Update(), trap_EA_ResetInput(), trap_Milliseconds(), VectorCopy, bot_state_s::viewangles, and playerState_s::viewheight.

Referenced by BotAIStartFrame().

00696                                        {
00697         bot_state_t *bs;
00698         char buf[1024], *args;
00699         int j;
00700 #ifdef _DEBUG
00701         int start = 0;
00702         int end = 0;
00703 #endif
00704 
00705         trap_EA_ResetInput(client);
00706         //
00707         bs = botstates[client];
00708         if (!bs || !bs->inuse) {
00709                 BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client);
00710                 return qfalse;
00711         }
00712 
00713         //retrieve the current client state
00714         BotAI_GetClientState( client, &bs->cur_ps );
00715 
00716         //retrieve any waiting server commands
00717         while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) {
00718                 //have buf point to the command and args to the command arguments
00719                 args = strchr( buf, ' ');
00720                 if (!args) continue;
00721                 *args++ = '\0';
00722 
00723                 //remove color espace sequences from the arguments
00724                 RemoveColorEscapeSequences( args );
00725 
00726                 if (!Q_stricmp(buf, "cp "))
00727                         { /*CenterPrintf*/ }
00728                 else if (!Q_stricmp(buf, "cs"))
00729                         { /*ConfigStringModified*/ }
00730                 else if (!Q_stricmp(buf, "scores"))
00731                         { /*FIXME: parse scores?*/ }
00732                 else if (!Q_stricmp(buf, "clientLevelShot"))
00733                         { /*ignore*/ }
00734         }
00735         //add the delta angles to the bot's current view angles
00736         for (j = 0; j < 3; j++) {
00737                 bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
00738         }
00739         //increase the local time of the bot
00740         bs->ltime += thinktime;
00741         //
00742         bs->thinktime = thinktime;
00743         //origin of the bot
00744         VectorCopy(bs->cur_ps.origin, bs->origin);
00745         //eye coordinates of the bot
00746         VectorCopy(bs->cur_ps.origin, bs->eye);
00747         bs->eye[2] += bs->cur_ps.viewheight;
00748         //get the area the bot is in
00749 
00750 #ifdef _DEBUG
00751         start = trap_Milliseconds();
00752 #endif
00753         StandardBotAI(bs, thinktime);
00754 #ifdef _DEBUG
00755         end = trap_Milliseconds();
00756 
00757         trap_Cvar_Update(&bot_debugmessages);
00758 
00759         if (bot_debugmessages.integer)
00760         {
00761                 Com_Printf("Single AI frametime: %i\n", (end - start));
00762         }
00763 #endif
00764 
00765         //subtract the delta angles
00766         for (j = 0; j < 3; j++) {
00767                 bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
00768         }
00769         //everything was ok
00770         return qtrue;
00771 }

int BotAI_GetClientState int  clientNum,
playerState_t state
 

Definition at line 351 of file ai_main.c.

References gentity_s::client, g_entities, gentity_t, gentity_s::inuse, memcpy(), playerState_t, gclient_s::ps, qfalse, and qtrue.

Referenced by BotAI().

00351                                                                 {
00352         gentity_t       *ent;
00353 
00354         ent = &g_entities[clientNum];
00355         if ( !ent->inuse ) {
00356                 return qfalse;
00357         }
00358         if ( !ent->client ) {
00359                 return qfalse;
00360         }
00361 
00362         memcpy( state, &ent->client->ps, sizeof(playerState_t) );
00363         return qtrue;
00364 }

int BotAI_GetEntityState int  entityNum,
entityState_t state
 

Definition at line 371 of file ai_main.c.

References entityState_t, g_entities, gentity_t, gentity_s::inuse, entityShared_t::linked, memcpy(), memset(), qfalse, qtrue, gentity_s::r, gentity_s::s, SVF_NOCLIENT, and entityShared_t::svFlags.

Referenced by BotAI_GetSnapshotEntity().

00371                                                                 {
00372         gentity_t       *ent;
00373 
00374         ent = &g_entities[entityNum];
00375         memset( state, 0, sizeof(entityState_t) );
00376         if (!ent->inuse) return qfalse;
00377         if (!ent->r.linked) return qfalse;
00378         if (ent->r.svFlags & SVF_NOCLIENT) return qfalse;
00379         memcpy( state, &ent->s, sizeof(entityState_t) );
00380         return qtrue;
00381 }

int BotAI_GetSnapshotEntity int  clientNum,
int  sequence,
entityState_t state
 

Definition at line 388 of file ai_main.c.

References BotAI_GetEntityState(), entityState_t, memset(), and trap_BotGetSnapshotEntity().

00388                                                                                  {
00389         int             entNum;
00390 
00391         entNum = trap_BotGetSnapshotEntity( clientNum, sequence );
00392         if ( entNum == -1 ) {
00393                 memset(state, 0, sizeof(entityState_t));
00394                 return -1;
00395         }
00396 
00397         BotAI_GetEntityState( entNum, state );
00398 
00399         return sequence + 1;
00400 }

void QDECL BotAI_Print int  type,
char *  fmt,
... 
 

Definition at line 332 of file ai_main.c.

References QDECL.

Referenced by BotAI(), and BotAISetupClient().

00332 { return; }

int BotAILoadMap int  restart  ) 
 

Definition at line 966 of file ai_main.c.

References BotResetState(), botstates, bot_state_s::inuse, MAX_CLIENTS, qtrue, and bot_state_s::setupcount.

Referenced by G_InitGame().

00966                                 {
00967         int                     i;
00968 
00969         for (i = 0; i < MAX_CLIENTS; i++) {
00970                 if (botstates[i] && botstates[i]->inuse) {
00971                         BotResetState( botstates[i] );
00972                         botstates[i]->setupcount = 4;
00973                 }
00974         }
00975 
00976         return qtrue;
00977 }

void BotAimLeading bot_state_t bs,
vec3_t  headlevel,
float  leadAmount
 

Definition at line 4607 of file ai_main.c.

References bot_state_t, gentity_s::client, bot_state_s::currentEnemy, bot_state_s::eye, bot_state_s::frame_Enemy_Len, bot_state_s::goalAngles, gclient_s::ps, vec3_t, vectoangles(), VectorCopy, VectorNormalize(), VectorSubtract, and playerState_s::velocity.

Referenced by StandardBotAI().

04608 {
04609         int x;
04610         vec3_t predictedSpot;
04611         vec3_t movementVector;
04612         vec3_t a, ang;
04613         float vtotal;
04614 
04615         if (!bs->currentEnemy ||
04616                 !bs->currentEnemy->client)
04617         {
04618                 return;
04619         }
04620 
04621         if (!bs->frame_Enemy_Len)
04622         {
04623                 return;
04624         }
04625 
04626         vtotal = 0;
04627 
04628         if (bs->currentEnemy->client->ps.velocity[0] < 0)
04629         {
04630                 vtotal += -bs->currentEnemy->client->ps.velocity[0];
04631         }
04632         else
04633         {
04634                 vtotal += bs->currentEnemy->client->ps.velocity[0];
04635         }
04636 
04637         if (bs->currentEnemy->client->ps.velocity[1] < 0)
04638         {
04639                 vtotal += -bs->currentEnemy->client->ps.velocity[1];
04640         }
04641         else
04642         {
04643                 vtotal += bs->currentEnemy->client->ps.velocity[1];
04644         }
04645 
04646         if (bs->currentEnemy->client->ps.velocity[2] < 0)
04647         {
04648                 vtotal += -bs->currentEnemy->client->ps.velocity[2];
04649         }
04650         else
04651         {
04652                 vtotal += bs->currentEnemy->client->ps.velocity[2];
04653         }
04654 
04655         //G_Printf("Leadin target with a velocity total of %f\n", vtotal);
04656 
04657         VectorCopy(bs->currentEnemy->client->ps.velocity, movementVector);
04658 
04659         VectorNormalize(movementVector);
04660 
04661         x = bs->frame_Enemy_Len*leadAmount; //hardly calculated with an exact science, but it works
04662 
04663         if (vtotal > 400)
04664         {
04665                 vtotal = 400;
04666         }
04667 
04668         if (vtotal)
04669         {
04670                 x = (bs->frame_Enemy_Len*0.9)*leadAmount*(vtotal*0.0012); //hardly calculated with an exact science, but it works
04671         }
04672         else
04673         {
04674                 x = (bs->frame_Enemy_Len*0.9)*leadAmount; //hardly calculated with an exact science, but it works
04675         }
04676 
04677         predictedSpot[0] = headlevel[0] + (movementVector[0]*x);
04678         predictedSpot[1] = headlevel[1] + (movementVector[1]*x);
04679         predictedSpot[2] = headlevel[2] + (movementVector[2]*x);
04680 
04681         VectorSubtract(predictedSpot, bs->eye, a);
04682         vectoangles(a, ang);
04683         VectorCopy(ang, bs->goalAngles);
04684 }

void BotAimOffsetGoalAngles bot_state_t bs  ) 
 

Definition at line 4687 of file ai_main.c.

References botskills_s::accuracy, bot_state_s::aimOffsetAmtPitch, bot_state_s::aimOffsetAmtYaw, bot_state_s::aimOffsetTime, bot_state_t, BotMindTricked(), bot_state_s::client, bot_state_s::currentEnemy, bot_state_s::frame_Enemy_Vis, g_entities, bot_state_s::goalAngles, level, entityState_s::number, botskills_s::perfectaim, PITCH, entityState_s::pos, rand(), bot_state_s::revengeEnemy, bot_state_s::revengeHateLevel, gentity_s::s, bot_state_s::settings, bot_settings_s::skill, bot_state_s::skills, level_locals_t::time, trajectory_t::trDelta, and YAW.

Referenced by StandardBotAI().

04688 {
04689         int i;
04690         float accVal;
04691         i = 0;
04692 
04693         if (bs->skills.perfectaim)
04694         {
04695                 return;
04696         }
04697 
04698         if (bs->aimOffsetTime > level.time)
04699         {
04700                 if (bs->aimOffsetAmtYaw)
04701                 {
04702                         bs->goalAngles[YAW] += bs->aimOffsetAmtYaw;
04703                 }
04704 
04705                 if (bs->aimOffsetAmtPitch)
04706                 {
04707                         bs->goalAngles[PITCH] += bs->aimOffsetAmtPitch;
04708                 }
04709                 
04710                 while (i <= 2)
04711                 {
04712                         if (bs->goalAngles[i] > 360)
04713                         {
04714                                 bs->goalAngles[i] -= 360;
04715                         }
04716 
04717                         if (bs->goalAngles[i] < 0)
04718                         {
04719                                 bs->goalAngles[i] += 360;
04720                         }
04721 
04722                         i++;
04723                 }
04724                 return;
04725         }
04726 
04727         accVal = bs->skills.accuracy/bs->settings.skill;
04728 
04729         if (bs->currentEnemy && BotMindTricked(bs->client, bs->currentEnemy->s.number))
04730         { //having to judge where they are by hearing them, so we should be quite inaccurate here
04731                 accVal *= 7;
04732 
04733                 if (accVal < 30)
04734                 {
04735                         accVal = 30;
04736                 }
04737         }
04738 
04739         if (bs->revengeEnemy && bs->revengeHateLevel &&
04740                 bs->currentEnemy == bs->revengeEnemy)
04741         { //bot becomes more skilled as anger level raises
04742                 accVal = accVal/bs->revengeHateLevel;
04743         }
04744 
04745         if (bs->currentEnemy && bs->frame_Enemy_Vis)
04746         { //assume our goal is aiming at the enemy, seeing as he's visible and all
04747                 if (!bs->currentEnemy->s.pos.trDelta[0] &&
04748                         !bs->currentEnemy->s.pos.trDelta[1] &&
04749                         !bs->currentEnemy->s.pos.trDelta[2])
04750                 {
04751                         accVal = 0; //he's not even moving, so he shouldn't really be hard to hit.
04752                 }
04753                 else
04754                 {
04755                         accVal += accVal*0.25; //if he's moving he's this much harder to hit
04756                 }
04757 
04758                 if (g_entities[bs->client].s.pos.trDelta[0] ||
04759                         g_entities[bs->client].s.pos.trDelta[1] ||
04760                         g_entities[bs->client].s.pos.trDelta[2])
04761                 {
04762                         accVal += accVal*0.15; //make it somewhat harder to aim if we're moving also
04763                 }
04764         }
04765 
04766         if (accVal > 90)
04767         {
04768                 accVal = 90;
04769         }
04770         if (accVal < 1)
04771         {
04772                 accVal = 0;
04773         }
04774 
04775         if (!accVal)
04776         {
04777                 bs->aimOffsetAmtYaw = 0;
04778                 bs->aimOffsetAmtPitch = 0;
04779                 return;
04780         }
04781 
04782         if (rand()%10 <= 5)
04783         {
04784                 bs->aimOffsetAmtYaw = rand()%(int)accVal;
04785         }
04786         else
04787         {
04788                 bs->aimOffsetAmtYaw = -(rand()%(int)accVal);
04789         }
04790 
04791         if (rand()%10 <= 5)
04792         {
04793                 bs->aimOffsetAmtPitch = rand()%(int)accVal;
04794         }
04795         else
04796         {
04797                 bs->aimOffsetAmtPitch = -(rand()%(int)accVal);
04798         }
04799 
04800         bs->aimOffsetTime = level.time + rand()%500 + 200;
04801 }

void BotAIRegularUpdate void   ) 
 

Definition at line 662 of file ai_main.c.

References FloatTime, regularupdate_time, and trap_BotUpdateEntityItems().

00662                               {
00663         if (regularupdate_time < FloatTime()) {
00664                 trap_BotUpdateEntityItems();
00665                 regularupdate_time = FloatTime() + 0.3;
00666         }
00667 }

int BotAISetup int  restart  ) 
 

Definition at line 7575 of file ai_main.c.

References bot_attachments, bot_camp, bot_forcepowers, bot_forgimmick, bot_getinthecarrr, bot_honorableduelacceptance, bot_pvstype, bot_wp_clearweight, bot_wp_distconnect, bot_wp_edit, bot_wp_info, bot_wp_visconnect, botstates, CVAR_CHEAT, memset(), qfalse, qtrue, trap_BotLibSetup(), trap_Cvar_Register(), and trap_Cvar_Update().

Referenced by G_InitGame().

07575                               {
07576         //rww - new bot cvars..
07577         trap_Cvar_Register(&bot_forcepowers, "bot_forcepowers", "1", CVAR_CHEAT);
07578         trap_Cvar_Register(&bot_forgimmick, "bot_forgimmick", "0", CVAR_CHEAT);
07579         trap_Cvar_Register(&bot_honorableduelacceptance, "bot_honorableduelacceptance", "0", CVAR_CHEAT);
07580         trap_Cvar_Register(&bot_pvstype, "bot_pvstype", "1", CVAR_CHEAT);
07581 #ifndef FINAL_BUILD
07582         trap_Cvar_Register(&bot_getinthecarrr, "bot_getinthecarrr", "0", 0);
07583 #endif
07584 
07585 #ifdef _DEBUG
07586         trap_Cvar_Register(&bot_nogoals, "bot_nogoals", "0", CVAR_CHEAT);
07587         trap_Cvar_Register(&bot_debugmessages, "bot_debugmessages", "0", CVAR_CHEAT);
07588 #endif
07589 
07590         trap_Cvar_Register(&bot_attachments, "bot_attachments", "1", 0);
07591         trap_Cvar_Register(&bot_camp, "bot_camp", "1", 0);
07592 
07593         trap_Cvar_Register(&bot_wp_info, "bot_wp_info", "1", 0);
07594         trap_Cvar_Register(&bot_wp_edit, "bot_wp_edit", "0", CVAR_CHEAT);
07595         trap_Cvar_Register(&bot_wp_clearweight, "bot_wp_clearweight", "1", 0);
07596         trap_Cvar_Register(&bot_wp_distconnect, "bot_wp_distconnect", "1", 0);
07597         trap_Cvar_Register(&bot_wp_visconnect, "bot_wp_visconnect", "1", 0);
07598 
07599         trap_Cvar_Update(&bot_forcepowers);
07600         //end rww
07601 
07602         //if the game is restarted for a tournament
07603         if (restart) {
07604                 return qtrue;
07605         }
07606 
07607         //initialize the bot states
07608         memset( botstates, 0, sizeof(botstates) );
07609 
07610         if (!trap_BotLibSetup())
07611         {
07612                 return qfalse; //wts?!
07613         }
07614 
07615         return qtrue;
07616 }

int BotAISetupClient int  client,
struct bot_settings_s settings,
qboolean  restart
 

Definition at line 819 of file ai_main.c.

References B_Alloc(), bot_settings_t, bot_state_t, BotAI_Print(), BotDoChat(), BotScheduleBotThink(), botstates, BotUtilizePersonality(), bot_state_s::botWeaponWeights, client, bot_state_s::client, bot_state_s::entergame_time, bot_state_s::entitynum, FloatTime, g_gametype, bot_state_s::gs, GT_DUEL, GT_POWERDUEL, vmCvar_t::integer, bot_state_s::inuse, memcpy(), memset(), bot_state_s::ms, numbots, PlayersInGame(), PRT_FATAL, qfalse, qtrue, bot_state_s::settings, bot_state_s::setupcount, trap_BotAllocGoalState(), trap_BotAllocMoveState(), trap_BotAllocWeaponState(), WP_BLASTER, WP_BOWCASTER, WP_BRYAR_PISTOL, WP_DEMP2, WP_DET_PACK, WP_DISRUPTOR, WP_FLECHETTE, WP_MELEE, WP_NONE, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, WP_STUN_BATON, WP_THERMAL, WP_TRIP_MINE, and bot_state_s::ws.

Referenced by G_BotConnect().

00819                                                                                     {
00820         bot_state_t *bs;
00821 
00822         if (!botstates[client]) botstates[client] = (bot_state_t *) B_Alloc(sizeof(bot_state_t)); //G_Alloc(sizeof(bot_state_t));
00823                                                                                                                                                           //rww - G_Alloc bad! B_Alloc good.
00824 
00825         memset(botstates[client], 0, sizeof(bot_state_t));
00826 
00827         bs = botstates[client];
00828 
00829         if (bs && bs->inuse) {
00830                 BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client);
00831                 return qfalse;
00832         }
00833 
00834         memcpy(&bs->settings, settings, sizeof(bot_settings_t));
00835 
00836         bs->client = client; //need to know the client number before doing personality stuff
00837 
00838         //initialize weapon weight defaults..
00839         bs->botWeaponWeights[WP_NONE] = 0;
00840         bs->botWeaponWeights[WP_STUN_BATON] = 1;
00841         bs->botWeaponWeights[WP_SABER] = 10;
00842         bs->botWeaponWeights[WP_BRYAR_PISTOL] = 11;
00843         bs->botWeaponWeights[WP_BLASTER] = 12;
00844         bs->botWeaponWeights[WP_DISRUPTOR] = 13;
00845         bs->botWeaponWeights[WP_BOWCASTER] = 14;
00846         bs->botWeaponWeights[WP_REPEATER] = 15;
00847         bs->botWeaponWeights[WP_DEMP2] = 16;
00848         bs->botWeaponWeights[WP_FLECHETTE] = 17;
00849         bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = 18;
00850         bs->botWeaponWeights[WP_THERMAL] = 14;
00851         bs->botWeaponWeights[WP_TRIP_MINE] = 0;
00852         bs->botWeaponWeights[WP_DET_PACK] = 0;
00853         bs->botWeaponWeights[WP_MELEE] = 1;
00854 
00855         BotUtilizePersonality(bs);
00856 
00857         if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
00858         {
00859                 bs->botWeaponWeights[WP_SABER] = 13;
00860         }
00861 
00862         //allocate a goal state
00863         bs->gs = trap_BotAllocGoalState(client);
00864 
00865         //allocate a weapon state
00866         bs->ws = trap_BotAllocWeaponState();
00867 
00868         bs->inuse = qtrue;
00869         bs->entitynum = client;
00870         bs->setupcount = 4;
00871         bs->entergame_time = FloatTime();
00872         bs->ms = trap_BotAllocMoveState();
00873         numbots++;
00874 
00875         //NOTE: reschedule the bot thinking
00876         BotScheduleBotThink();
00877 
00878         if (PlayersInGame())
00879         { //don't talk to yourself
00880                 BotDoChat(bs, "GeneralGreetings", 0);
00881         }
00882 
00883         return qtrue;
00884 }

int BotAIShutdown int  restart  ) 
 

Definition at line 7623 of file ai_main.c.

References BotAIShutdownClient(), botstates, client, bot_state_s::inuse, MAX_CLIENTS, qtrue, and trap_BotLibShutdown().

Referenced by G_ShutdownGame().

07623                                  {
07624 
07625         int i;
07626 
07627         //if the game is restarted for a tournament
07628         if ( restart ) {
07629                 //shutdown all the bots in the botlib
07630                 for (i = 0; i < MAX_CLIENTS; i++) {
07631                         if (botstates[i] && botstates[i]->inuse) {
07632                                 BotAIShutdownClient(botstates[i]->client, restart);
07633                         }
07634                 }
07635                 //don't shutdown the bot library
07636         }
07637         else {
07638                 trap_BotLibShutdown();
07639         }
07640         return qtrue;
07641 }

int BotAIShutdownClient int  client,
qboolean  restart
 

Definition at line 891 of file ai_main.c.

References bot_state_t, botstates, client, bot_state_s::gs, bot_state_s::inuse, memset(), bot_state_s::ms, numbots, qfalse, qtrue, trap_BotFreeGoalState(), trap_BotFreeMoveState(), trap_BotFreeWeaponState(), and bot_state_s::ws.

Referenced by BotAIShutdown(), and ClientDisconnect().

00891                                                       {
00892         bot_state_t *bs;
00893 
00894         bs = botstates[client];
00895         if (!bs || !bs->inuse) {
00896                 //BotAI_Print(PRT_ERROR, "BotAIShutdownClient: client %d already shutdown\n", client);
00897                 return qfalse;
00898         }
00899 
00900         trap_BotFreeMoveState(bs->ms);
00901         //free the goal state`                  
00902         trap_BotFreeGoalState(bs->gs);
00903         //free the weapon weights
00904         trap_BotFreeWeaponState(bs->ws);
00905         //
00906         //clear the bot state
00907         memset(bs, 0, sizeof(bot_state_t));
00908         //set the inuse flag to qfalse
00909         bs->inuse = qfalse;
00910         //there's one bot less
00911         numbots--;
00912         //everything went ok
00913         return qtrue;
00914 }

int BotAIStartFrame int  time  ) 
 

Definition at line 7492 of file ai_main.c.

References bot_attachments, bot_camp, bot_forgimmick, bot_getinthecarrr, bot_honorableduelacceptance, bot_pvstype, BOT_THINK_TIME, bot_wp_info, BotAI(), BotScheduleBotThink(), botstates, bot_state_s::botthink_residual, BotUpdateInput(), BotWaypointRender(), gentity_s::client, client, CON_CONNECTED, clientPersistant_t::connected, G_CheckBotSpawn(), g_entities, gBotEdit, gUpdateVars, bot_state_s::inuse, level, MAX_CLIENTS, gclient_s::pers, qtrue, level_locals_t::time, trap_BotUserCommand(), trap_Cvar_Update(), and UpdateEventTracker().

Referenced by vmMain().

07492                               {
07493         int i;
07494         int elapsed_time, thinktime;
07495         static int local_time;
07496         static int botlib_residual;
07497         static int lastbotthink_time;
07498 
07499         if (gUpdateVars < level.time)
07500         {
07501                 trap_Cvar_Update(&bot_pvstype);
07502                 trap_Cvar_Update(&bot_camp);
07503                 trap_Cvar_Update(&bot_attachments);
07504                 trap_Cvar_Update(&bot_forgimmick);
07505                 trap_Cvar_Update(&bot_honorableduelacceptance);
07506 #ifndef FINAL_BUILD
07507                 trap_Cvar_Update(&bot_getinthecarrr);
07508 #endif
07509                 gUpdateVars = level.time + 1000;
07510         }
07511 
07512         G_CheckBotSpawn();
07513 
07514         //rww - addl bot frame functions
07515         if (gBotEdit)
07516         {
07517                 trap_Cvar_Update(&bot_wp_info);
07518                 BotWaypointRender();
07519         }
07520 
07521         UpdateEventTracker();
07522         //end rww
07523 
07524         //cap the bot think time
07525         //if the bot think time changed we should reschedule the bots
07526         if (BOT_THINK_TIME != lastbotthink_time) {
07527                 lastbotthink_time = BOT_THINK_TIME;
07528                 BotScheduleBotThink();
07529         }
07530 
07531         elapsed_time = time - local_time;
07532         local_time = time;
07533 
07534         if (elapsed_time > BOT_THINK_TIME) thinktime = elapsed_time;
07535         else thinktime = BOT_THINK_TIME;
07536 
07537         // execute scheduled bot AI
07538         for( i = 0; i < MAX_CLIENTS; i++ ) {
07539                 if( !botstates[i] || !botstates[i]->inuse ) {
07540                         continue;
07541                 }
07542                 //
07543                 botstates[i]->botthink_residual += elapsed_time;
07544                 //
07545                 if ( botstates[i]->botthink_residual >= thinktime ) {
07546                         botstates[i]->botthink_residual -= thinktime;
07547 
07548                         if (g_entities[i].client->pers.connected == CON_CONNECTED) {
07549                                 BotAI(i, (float) thinktime / 1000);
07550                         }
07551                 }
07552         }
07553 
07554         // execute bot user commands every frame
07555         for( i = 0; i < MAX_CLIENTS; i++ ) {
07556                 if( !botstates[i] || !botstates[i]->inuse ) {
07557                         continue;
07558                 }
07559                 if( g_entities[i].client->pers.connected != CON_CONNECTED ) {
07560                         continue;
07561                 }
07562 
07563                 BotUpdateInput(botstates[i], time, elapsed_time);
07564                 trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd);
07565         }
07566 
07567         return qtrue;
07568 }

int BotCanHear bot_state_t bs,
gentity_t en,
float  endist
 

Definition at line 1945 of file ai_main.c.

References bot_state_t, BotMindTricked(), bot_state_s::client, gentity_s::client, EV_ALT_FIRE, EV_FIRE_WEAPON, EV_FOOTSTEP, EV_FOOTSTEP_METAL, EV_FOOTWADE, EV_GLOBAL_SOUND, EV_JUMP, EV_ROLL, EV_SABER_ATTACK, EV_STEP_12, EV_STEP_16, EV_STEP_4, EV_STEP_8, playerState_s::footstepTime, gBotEventTracker, gentity_t, level, MAX_PS_EVENTS, entityState_s::number, playerState_s::otherSoundLen, playerState_s::otherSoundTime, gclient_s::ps, gentity_s::s, and level_locals_t::time.

Referenced by ScanForEnemies().

01946 {
01947         float minlen;
01948 
01949         if (!en || !en->client)
01950         {
01951                 return 0;
01952         }
01953 
01954         if (en && en->client && en->client->ps.otherSoundTime > level.time)
01955         { //they made a noise in recent time
01956                 minlen = en->client->ps.otherSoundLen;
01957                 goto checkStep;
01958         }
01959 
01960         if (en && en->client && en->client->ps.footstepTime > level.time)
01961         { //they made a footstep
01962                 minlen = 256;
01963                 goto checkStep;
01964         }
01965 
01966         if (gBotEventTracker[en->s.number].eventTime < level.time)
01967         { //no recent events to check
01968                 return 0;
01969         }
01970 
01971         switch(gBotEventTracker[en->s.number].events[gBotEventTracker[en->s.number].eventSequence & (MAX_PS_EVENTS-1)])
01972         { //did the last event contain a sound?
01973         case EV_GLOBAL_SOUND:
01974                 minlen = 256;
01975                 break;
01976         case EV_FIRE_WEAPON:
01977         case EV_ALT_FIRE:
01978         case EV_SABER_ATTACK:
01979                 minlen = 512;
01980                 break;
01981         case EV_STEP_4:
01982         case EV_STEP_8:
01983         case EV_STEP_12:
01984         case EV_STEP_16:
01985         case EV_FOOTSTEP:
01986         case EV_FOOTSTEP_METAL:
01987         case EV_FOOTWADE:
01988                 minlen = 256;
01989                 break;
01990         case EV_JUMP:
01991         case EV_ROLL:
01992                 minlen = 256;
01993                 break;
01994         default:
01995                 minlen = 999999;
01996                 break;
01997         }
01998 checkStep:
01999         if (BotMindTricked(bs->client, en->s.number))
02000         { //if mindtricked by this person, cut down on the minlen so they can't "hear" as well
02001                 minlen /= 4;
02002         }
02003 
02004         if (endist <= minlen)
02005         { //we heard it
02006                 return 1;
02007         }
02008 
02009         return 0;
02010 }

float BotChangeViewAngle float  angle,
float  ideal_angle,
float  speed
 

Definition at line 443 of file ai_main.c.

References AngleMod().

00443                                                                       {
00444         float move;
00445 
00446         angle = AngleMod(angle);
00447         ideal_angle = AngleMod(ideal_angle);
00448         if (angle == ideal_angle) return angle;
00449         move = ideal_angle - angle;
00450         if (ideal_angle > angle) {
00451                 if (move > 180.0) move -= 360.0;
00452         }
00453         else {
00454                 if (move < -180.0) move += 360.0;
00455         }
00456         if (move > 0) {
00457                 if (move > speed) move = speed;
00458         }
00459         else {
00460                 if (move < -speed) move = -speed;
00461         }
00462         return AngleMod(angle + move);
00463 }

void BotChangeViewAngles bot_state_t bs,
float  thinktime
 

Definition at line 470 of file ai_main.c.

References AngleDifference(), AngleMod(), bot_state_t, bot_state_s::client, bot_state_s::currentEnemy, bot_state_s::frame_Enemy_Vis, bot_state_s::ideal_viewangles, botskills_s::maxturn, PITCH, bot_state_s::settings, bot_settings_s::skill, bot_state_s::skills, trap_EA_View(), botskills_s::turnspeed, botskills_s::turnspeed_combat, bot_state_s::viewangles, and bot_state_s::viewanglespeed.

Referenced by BotUpdateInput().

00470                                                            {
00471         float diff, factor, maxchange, anglespeed, disired_speed;
00472         int i;
00473 
00474         if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360;
00475         
00476         if (bs->currentEnemy && bs->frame_Enemy_Vis)
00477         {
00478                 if (bs->settings.skill <= 1)
00479                 {
00480                         factor = (bs->skills.turnspeed_combat*0.4f)*bs->settings.skill;
00481                 }
00482                 else if (bs->settings.skill <= 2)
00483                 {
00484                         factor = (bs->skills.turnspeed_combat*0.6f)*bs->settings.skill;
00485                 }
00486                 else if (bs->settings.skill <= 3)
00487                 {
00488                         factor = (bs->skills.turnspeed_combat*0.8f)*bs->settings.skill;
00489                 }
00490                 else
00491                 {
00492                         factor = bs->skills.turnspeed_combat*bs->settings.skill;
00493                 }
00494         }
00495         else
00496         {
00497                 factor = bs->skills.turnspeed;
00498         }
00499 
00500         if (factor > 1)
00501         {
00502                 factor = 1;
00503         }
00504         if (factor < 0.001)
00505         {
00506                 factor = 0.001f;
00507         }
00508 
00509         maxchange = bs->skills.maxturn;
00510 
00511         //if (maxchange < 240) maxchange = 240;
00512         maxchange *= thinktime;
00513         for (i = 0; i < 2; i++) {
00514                 bs->viewangles[i] = AngleMod(bs->viewangles[i]);
00515                 bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]);
00516                 diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]);
00517                 disired_speed = diff * factor;
00518                 bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed);
00519                 if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange;
00520                 if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange;
00521                 anglespeed = bs->viewanglespeed[i];
00522                 if (anglespeed > maxchange) anglespeed = maxchange;
00523                 if (anglespeed < -maxchange) anglespeed = -maxchange;
00524                 bs->viewangles[i] += anglespeed;
00525                 bs->viewangles[i] = AngleMod(bs->viewangles[i]);
00526                 bs->viewanglespeed[i] *= 0.45 * (1 - factor);
00527         }
00528         if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360;
00529         trap_EA_View(bs->client, bs->viewangles);
00530 }

void BotCheckDetPacks bot_state_t bs  ) 
 

Definition at line 5726 of file ai_main.c.

References BOT_PLANT_BLOW_DISTANCE, bot_state_t, gentity_s::client, bot_state_s::client, bot_state_s::currentEnemy, FOFS, bot_state_s::frame_Enemy_Vis, G_Find(), gentity_t, level, NULL, entityState_s::number, OrgVisible(), bot_state_s::origin, playerState_s::origin, gentity_s::parent, bot_state_s::plantContinue, bot_state_s::plantKillEmAll, entityState_s::pos, gclient_s::ps, gentity_s::s, level_locals_t::time, trajectory_t::trBase, vec3_t, and VectorSubtract.

Referenced by StandardBotAI().

05727 {
05728         gentity_t *dp = NULL;
05729         gentity_t *myDet = NULL;
05730         vec3_t a;
05731         float enLen;
05732         float myLen;
05733 
05734         while ( (dp = G_Find( dp, FOFS(classname), "detpack") ) != NULL )
05735         {
05736                 if (dp && dp->parent && dp->parent->s.number == bs->client)
05737                 {
05738                         myDet = dp;
05739                         break;
05740                 }
05741         }
05742 
05743         if (!myDet)
05744         {
05745                 return;
05746         }
05747 
05748         if (!bs->currentEnemy || !bs->currentEnemy->client || !bs->frame_Enemy_Vis)
05749         { //require the enemy to be visilbe just to be fair..
05750 
05751                 //unless..
05752                 if (bs->currentEnemy && bs->currentEnemy->client &&
05753                         (level.time - bs->plantContinue) < 5000)
05754                 { //it's a fresh plant (within 5 seconds) so we should be able to guess
05755                         goto stillmadeit;
05756                 }
05757                 return;
05758         }
05759 
05760 stillmadeit:
05761 
05762         VectorSubtract(bs->currentEnemy->client->ps.origin, myDet->s.pos.trBase, a);
05763         enLen = VectorLength(a);
05764 
05765         VectorSubtract(bs->origin, myDet->s.pos.trBase, a);
05766         myLen = VectorLength(a);
05767 
05768         if (enLen > myLen)
05769         {
05770                 return;
05771         }
05772 
05773         if (enLen < BOT_PLANT_BLOW_DISTANCE && OrgVisible(bs->currentEnemy->client->ps.origin, myDet->s.pos.trBase, bs->currentEnemy->s.number))
05774         { //we could just call the "blow all my detpacks" function here, but I guess that's cheating.
05775                 bs->plantKillEmAll = level.time + 500;
05776         }
05777 }

qboolean BotCTFGuardDuty bot_state_t bs  ) 
 

Definition at line 1432 of file ai_main.c.

References bot_state_t, bot_state_s::ctfState, CTFSTATE_DEFENDER, g_gametype, GT_CTF, GT_CTY, vmCvar_t::integer, qboolean, qfalse, and qtrue.

Referenced by WPTouchRoutine().

01433 {
01434         if (g_gametype.integer != GT_CTF &&
01435                 g_gametype.integer != GT_CTY)
01436         {
01437                 return qfalse;
01438         }
01439 
01440         if (bs->ctfState == CTFSTATE_DEFENDER)
01441         {
01442                 return qtrue;
01443         }
01444 
01445         return qfalse;
01446 }

void BotDamageNotification gclient_t bot,
gentity_t attacker
 

Definition at line 1861 of file ai_main.c.

References bot_state_t, botstates, gentity_s::client, bot_state_s::client, playerState_s::clientNum, bot_state_s::currentEnemy, ENEMY_FORGET_MS, bot_state_s::enemySeenTime, g_entities, gclient_t, gentity_t, bot_state_s::lastAttacked, bot_state_s::lastHurt, level, MAX_CLIENTS, NULL, entityState_s::number, PassLovedOneCheck(), PassStandardEnemyChecks(), gclient_s::ps, gentity_s::s, and level_locals_t::time.

Referenced by G_Damage().

01862 {
01863         bot_state_t *bs;
01864         bot_state_t *bs_a;
01865         int i;
01866 
01867         if (!bot || !attacker || !attacker->client)
01868         {
01869                 return;
01870         }
01871 
01872         if (bot->ps.clientNum >= MAX_CLIENTS)
01873         { //an NPC.. do nothing for them.
01874                 return;
01875         }
01876 
01877         if (attacker->s.number >= MAX_CLIENTS)
01878         { //if attacker is an npc also don't care I suppose.
01879                 return;
01880         }
01881 
01882         bs_a = botstates[attacker->s.number];
01883 
01884         if (bs_a)
01885         { //if the client attacking us is a bot as well
01886                 bs_a->lastAttacked = &g_entities[bot->ps.clientNum];
01887                 i = 0;
01888 
01889                 while (i < MAX_CLIENTS)
01890                 {
01891                         if (botstates[i] &&
01892                                 i != bs_a->client &&
01893                                 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01894                         {
01895                                 botstates[i]->lastAttacked = NULL;
01896                         }
01897 
01898                         i++;
01899                 }
01900         }
01901         else //got attacked by a real client, so no one gets rights to lastAttacked
01902         {
01903                 i = 0;
01904 
01905                 while (i < MAX_CLIENTS)
01906                 {
01907                         if (botstates[i] &&
01908                                 botstates[i]->lastAttacked == &g_entities[bot->ps.clientNum])
01909                         {
01910                                 botstates[i]->lastAttacked = NULL;
01911                         }
01912 
01913                         i++;
01914                 }
01915         }
01916 
01917         bs = botstates[bot->ps.clientNum];
01918 
01919         if (!bs)
01920         {
01921                 return;
01922         }
01923 
01924         bs->lastHurt = attacker;
01925 
01926         if (bs->currentEnemy)
01927         { //we don't care about the guy attacking us if we have an enemy already
01928                 return;
01929         }
01930 
01931         if (!PassStandardEnemyChecks(bs, attacker))
01932         { //the person that hurt us is not a valid enemy
01933                 return;
01934         }
01935 
01936         if (PassLovedOneCheck(bs, attacker))
01937         { //the person that hurt us is the one we love!
01938                 bs->currentEnemy = attacker;
01939                 bs->enemySeenTime = level.time + ENEMY_FORGET_MS;
01940         }
01941 }

void BotDeathNotify bot_state_t bs  ) 
 

Definition at line 5390 of file ai_main.c.

References bot_state_t, BotLovedOneDied(), botstates, bot_state_s::client, level_locals_t::clients, level, bot_state_s::loved, bot_state_s::lovednum, MAX_CLIENTS, botattachment_s::name, and strcmp().

Referenced by StandardBotAI().

05391 { //in case someone has an emotional attachment to us, we'll notify them
05392         int i = 0;
05393         int ltest = 0;
05394 
05395         while (i < MAX_CLIENTS)
05396         {
05397                 if (botstates[i] && botstates[i]->lovednum)
05398                 {
05399                         ltest = 0;
05400                         while (ltest < botstates[i]->lovednum)
05401                         {
05402                                 if (strcmp(level.clients[bs->client].pers.netname, botstates[i]->loved[ltest].name) == 0)
05403                                 {
05404                                         BotLovedOneDied(botstates[i], bs, botstates[i]->loved[ltest].level);
05405                                         break;
05406                                 }
05407 
05408                                 ltest++;
05409                         }
05410                 }
05411 
05412                 i++;
05413         }
05414 }

int BotDefendFlag bot_state_t bs  ) 
 

Definition at line 2507 of file ai_main.c.

References BASE_GUARD_DISTANCE, bot_state_t, bot_state_s::client, level_locals_t::clients, flagBlue, flagRed, level, wpobject_s::origin, bot_state_s::origin, TEAM_BLUE, TEAM_RED, vec3_t, VectorSubtract, bot_state_s::wpDestination, and wpobject_t.

Referenced by CTFTakesPriority().

02508 {
02509         wpobject_t *flagPoint;
02510         vec3_t a;
02511 
02512         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
02513         {
02514                 flagPoint = flagRed;
02515         }
02516         else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE)
02517         {
02518                 flagPoint = flagBlue;
02519         }
02520         else
02521         {
02522                 return 0;
02523         }
02524 
02525         if (!flagPoint)
02526         {
02527                 return 0;
02528         }
02529 
02530         VectorSubtract(bs->origin, flagPoint->origin, a);
02531 
02532         if (VectorLength(a) > BASE_GUARD_DISTANCE)
02533         {
02534                 bs->wpDestination = flagPoint;
02535         }
02536 
02537         return 1;
02538 }

void BotDoTeamplayAI bot_state_t bs  ) 
 

Definition at line 4143 of file ai_main.c.

References bot_state_t, bot_state_s::isSquadLeader, NULL, bot_state_s::squadLeader, bot_state_s::state_Forced, bot_state_s::teamplayState, and TEAMPLAYSTATE_REGROUP.

Referenced by StandardBotAI().

04144 {
04145         if (bs->state_Forced)
04146         {
04147                 bs->teamplayState = bs->state_Forced;
04148         }
04149 
04150         if (bs->teamplayState == TEAMPLAYSTATE_REGROUP)
04151         { //force to find a new leader
04152                 bs->squadLeader = NULL;
04153                 bs->isSquadLeader = 0;
04154         }
04155 }

void BotEntityInfo int  entnum,
aas_entityinfo_t info
 

Definition at line 407 of file ai_main.c.

References aas_entityinfo_t, and trap_AAS_EntityInfo().

00407                                                        {
00408         trap_AAS_EntityInfo(entnum, info);
00409 }

int BotFallbackNavigation bot_state_t bs  ) 
 

Definition at line 5029 of file ai_main.c.

References AngleVectors(), bot_state_t, bot_state_s::currentEnemy, ENTITYNUM_NONE, trace_t::fraction, bot_state_s::frame_Enemy_Vis, bot_state_s::goalAngles, bot_state_s::goalPosition, MASK_SOLID, NULL, bot_state_s::origin, PITCH, rand(), ROLL, trap_Trace(), vec3_t, VectorCopy, and YAW.

Referenced by StandardBotAI().

05030 {
05031         vec3_t b_angle, fwd, trto, mins, maxs;
05032         trace_t tr;
05033 
05034         if (bs->currentEnemy && bs->frame_Enemy_Vis)
05035         {
05036                 return 2; //we're busy
05037         }
05038 
05039         mins[0] = -15;
05040         mins[1] = -15;
05041         mins[2] = 0;
05042         maxs[0] = 15;
05043         maxs[1] = 15;
05044         maxs[2] = 32;
05045 
05046         bs->goalAngles[PITCH] = 0;
05047         bs->goalAngles[ROLL] = 0;
05048 
05049         VectorCopy(bs->goalAngles, b_angle);
05050 
05051         AngleVectors(b_angle, fwd, NULL, NULL);
05052 
05053         trto[0] = bs->origin[0] + fwd[0]*16;
05054         trto[1] = bs->origin[1] + fwd[1]*16;
05055         trto[2] = bs->origin[2] + fwd[2]*16;
05056 
05057         trap_Trace(&tr, bs->origin, mins, maxs, trto, ENTITYNUM_NONE, MASK_SOLID);
05058 
05059         if (tr.fraction == 1)
05060         {
05061                 VectorCopy(trto, bs->goalPosition);
05062                 return 1; //success!
05063         }
05064         else
05065         {
05066                 bs->goalAngles[YAW] = rand()%360;
05067         }
05068 
05069         return 0;
05070 }

int BotGetEnemyFlag bot_state_t bs  ) 
 

Definition at line 2541 of file ai_main.c.

References BASE_GETENEMYFLAG_DISTANCE, bot_state_t, bot_state_s::client, level_locals_t::clients, flagBlue, flagRed, level, wpobject_s::origin, bot_state_s::origin, TEAM_BLUE, TEAM_RED, vec3_t, VectorSubtract, bot_state_s::wpDestination, and wpobject_t.

Referenced by CTFTakesPriority().

02542 {
02543         wpobject_t *flagPoint;
02544         vec3_t a;
02545 
02546         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
02547         {
02548                 flagPoint = flagBlue;
02549         }
02550         else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE)
02551         {
02552                 flagPoint = flagRed;
02553         }
02554         else
02555         {
02556                 return 0;
02557         }
02558 
02559         if (!flagPoint)
02560         {
02561                 return 0;
02562         }
02563 
02564         VectorSubtract(bs->origin, flagPoint->origin, a);
02565 
02566         if (VectorLength(a) > BASE_GETENEMYFLAG_DISTANCE)
02567         {
02568                 bs->wpDestination = flagPoint;
02569         }
02570 
02571         return 1;
02572 }

int BotGetFlagBack bot_state_t bs  ) 
 

Definition at line 2575 of file ai_main.c.

References bot_state_t, gentity_s::client, bot_state_s::client, level_locals_t::clients, g_entities, gentity_t, GetNearestVisibleWP(), gWPArray, wpobject_s::index, level, MAX_CLIENTS, NULL, OnSameTeam(), entityState_s::origin, playerState_s::origin, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_REDFLAG, Q_irand(), gentity_s::s, TEAM_RED, level_locals_t::time, TotalTrailDistance(), vec3_t, VectorCopy, bot_state_s::wpCurrent, bot_state_s::wpDestination, and bot_state_s::wpDestSwitchTime.

Referenced by CTFTakesPriority().

02576 {
02577         int i = 0;
02578         int myFlag = 0;
02579         int foundCarrier = 0;
02580         int tempInt = 0;
02581         gentity_t *ent = NULL;
02582         vec3_t usethisvec;
02583 
02584         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
02585         {
02586                 myFlag = PW_REDFLAG;
02587         }
02588         else
02589         {
02590                 myFlag = PW_BLUEFLAG;
02591         }
02592 
02593         while (i < MAX_CLIENTS)
02594         {
02595                 ent = &g_entities[i];
02596 
02597                 if (ent && ent->client && ent->client->ps.powerups[myFlag] && !OnSameTeam(&g_entities[bs->client], ent))
02598                 {
02599                         foundCarrier = 1;
02600                         break;
02601                 }
02602 
02603                 i++;
02604         }
02605 
02606         if (!foundCarrier)
02607         {
02608                 return 0;
02609         }
02610 
02611         if (!ent)
02612         {
02613                 return 0;
02614         }
02615 
02616         if (bs->wpDestSwitchTime < level.time)
02617         {
02618                 if (ent->client)
02619                 {
02620                         VectorCopy(ent->client->ps.origin, usethisvec);
02621                 }
02622                 else
02623                 {
02624                         VectorCopy(ent->s.origin, usethisvec);
02625                 }
02626 
02627                 tempInt = GetNearestVisibleWP(usethisvec, 0);
02628 
02629                 if (tempInt != -1 && TotalTrailDistance(bs->wpCurrent->index, tempInt, bs) != -1)
02630                 {
02631                         bs->wpDestination = gWPArray[tempInt];
02632                         bs->wpDestSwitchTime = level.time + Q_irand(1000, 5000);
02633                 }
02634         }
02635 
02636         return 1;
02637 }

int BotGetFlagHome bot_state_t bs  ) 
 

Definition at line 2706 of file ai_main.c.

References BASE_FLAGWAIT_DISTANCE, bot_state_t, bot_state_s::client, level_locals_t::clients, flagBlue, flagRed, level, wpobject_s::origin, bot_state_s::origin, TEAM_BLUE, TEAM_RED, vec3_t, VectorSubtract, bot_state_s::wpDestination, and wpobject_t.

Referenced by CTFTakesPriority().

02707 {
02708         wpobject_t *flagPoint;
02709         vec3_t a;
02710 
02711         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
02712         {
02713                 flagPoint = flagRed;
02714         }
02715         else if (level.clients[bs->client].sess.sessionTeam == TEAM_BLUE)
02716         {
02717                 flagPoint = flagBlue;
02718         }
02719         else
02720         {
02721                 return 0;
02722         }
02723 
02724         if (!flagPoint)
02725         {
02726                 return 0;
02727         }
02728 
02729         VectorSubtract(bs->origin, flagPoint->origin, a);
02730 
02731         if (VectorLength(a) > BASE_FLAGWAIT_DISTANCE)
02732         {
02733                 bs->wpDestination = flagPoint;
02734         }
02735 
02736         return 1;
02737 }

int BotGetWeaponRange bot_state_t bs  ) 
 

Definition at line 2264 of file ai_main.c.

References bot_state_t, BWEAPONRANGE_LONG, BWEAPONRANGE_MELEE, BWEAPONRANGE_MID, BWEAPONRANGE_SABER, bot_state_s::cur_ps, playerState_s::weapon, 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 BotIsAChickenWuss(), BotTrace_Jump(), CombatBotAI(), GetIdealDestination(), Siege_TargetClosestObjective(), and StandardBotAI().

02265 {
02266         switch (bs->cur_ps.weapon)
02267         {
02268         case WP_STUN_BATON:
02269         case WP_MELEE:
02270                 return BWEAPONRANGE_MELEE;
02271         case WP_SABER:
02272                 return BWEAPONRANGE_SABER;
02273         case WP_BRYAR_PISTOL:
02274                 return BWEAPONRANGE_MID;
02275         case WP_BLASTER:
02276                 return BWEAPONRANGE_MID;
02277         case WP_DISRUPTOR:
02278                 return BWEAPONRANGE_MID;
02279         case WP_BOWCASTER:
02280                 return BWEAPONRANGE_LONG;
02281         case WP_REPEATER:
02282                 return BWEAPONRANGE_MID;
02283         case WP_DEMP2:
02284                 return BWEAPONRANGE_LONG;
02285         case WP_FLECHETTE:
02286                 return BWEAPONRANGE_LONG;
02287         case WP_ROCKET_LAUNCHER:
02288                 return BWEAPONRANGE_LONG;
02289         case WP_THERMAL:
02290                 return BWEAPONRANGE_LONG;
02291         case WP_TRIP_MINE:
02292                 return BWEAPONRANGE_LONG;
02293         case WP_DET_PACK:
02294                 return BWEAPONRANGE_LONG;
02295         default:
02296                 return BWEAPONRANGE_MID;
02297         }
02298 }

int BotGuardFlagCarrier bot_state_t bs  ) 
 

Definition at line 2641 of file ai_main.c.

References bot_state_t, gentity_s::client, bot_state_s::client, level_locals_t::clients, g_entities, gentity_t, GetNearestVisibleWP(), gWPArray, wpobject_s::index, level, MAX_CLIENTS, NULL, OnSameTeam(), entityState_s::origin, playerState_s::origin, playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_REDFLAG, Q_irand(), gentity_s::s, TEAM_RED, level_locals_t::time, TotalTrailDistance(), vec3_t, VectorCopy, bot_state_s::wpCurrent, bot_state_s::wpDestination, and bot_state_s::wpDestSwitchTime.

Referenced by CTFTakesPriority().

02642 {
02643         int i = 0;
02644         int enemyFlag = 0;
02645         int foundCarrier = 0;
02646         int tempInt = 0;
02647         gentity_t *ent = NULL;
02648         vec3_t usethisvec;
02649 
02650         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
02651         {
02652                 enemyFlag = PW_BLUEFLAG;
02653         }
02654         else
02655         {
02656                 enemyFlag = PW_REDFLAG;
02657         }
02658 
02659         while (i < MAX_CLIENTS)
02660         {
02661                 ent = &g_entities[i];
02662 
02663                 if (ent && ent->client && ent->client->ps.powerups[enemyFlag] && OnSameTeam(&g_entities[bs->client], ent))
02664                 {
02665                         foundCarrier = 1;
02666                         break;
02667                 }
02668 
02669                 i++;
02670         }
02671 
02672         if (!foundCarrier)
02673         {
02674                 return 0;
02675         }
02676 
02677         if (!ent)
02678         {
02679                 return 0;
02680         }
02681 
02682         if (bs->wpDestSwitchTime < level.time)
02683         {
02684                 if (ent->client)
02685                 {
02686                         VectorCopy(ent->client->ps.origin, usethisvec);
02687                 }
02688                 else
02689                 {
02690                         VectorCopy(ent->s.origin, usethisvec);
02691                 }
02692 
02693                 tempInt = GetNearestVisibleWP(usethisvec, 0);
02694 
02695                 if (tempInt != -1 && TotalTrailDistance(bs->wpCurrent->index, tempInt, bs) != -1)
02696                 {
02697                         bs->wpDestination = gWPArray[tempInt];
02698                         bs->wpDestSwitchTime = level.time + Q_irand(1000, 5000);
02699                 }
02700         }
02701 
02702         return 1;
02703 }

int BotHasAssociated bot_state_t bs,
wpobject_t wp
 

Definition at line 3500 of file ai_main.c.

References playerState_s::ammo, wpobject_s::associated_entity, bot_state_t, bot_state_s::cur_ps, ENTITYNUM_NONE, g_entities, gentity_t, gitem_s::giTag, gitem_s::giType, IT_AMMO, IT_HOLDABLE, IT_POWERUP, IT_WEAPON, gentity_s::item, playerState_s::powerups, STAT_HOLDABLE_ITEMS, STAT_WEAPONS, playerState_s::stats, and wpobject_t.

Referenced by GetBestIdleGoal().

03501 {
03502         gentity_t *as;
03503 
03504         if (wp->associated_entity == ENTITYNUM_NONE)
03505         { //make it think this is an item we have so we don't go after nothing
03506                 return 1;
03507         }
03508 
03509         as = &g_entities[wp->associated_entity];
03510 
03511         if (!as || !as->item)
03512         {
03513                 return 0;
03514         }
03515 
03516         if (as->item->giType == IT_WEAPON)
03517         {
03518                 if (bs->cur_ps.stats[STAT_WEAPONS] & (1 << as->item->giTag))
03519                 {
03520                         return 1;
03521                 }
03522 
03523                 return 0;
03524         }
03525         else if (as->item->giType == IT_HOLDABLE)
03526         {
03527                 if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << as->item->giTag))
03528                 {
03529                         return 1;
03530                 }
03531 
03532                 return 0;
03533         }
03534         else if (as->item->giType == IT_POWERUP)
03535         {
03536                 if (bs->cur_ps.powerups[as->item->giTag])
03537                 {
03538                         return 1;
03539                 }
03540 
03541                 return 0;
03542         }
03543         else if (as->item->giType == IT_AMMO)
03544         {
03545                 if (bs->cur_ps.ammo[as->item->giTag] > 10) //hack
03546                 {
03547                         return 1;
03548                 }
03549 
03550                 return 0;
03551         }
03552 
03553         return 0;
03554 }

void BotInputToUserCommand bot_input_t bi,
usercmd_t ucmd,
int  delta_angles[3],
int  time,
int  useTime
 

Definition at line 537 of file ai_main.c.

References abs(), ACTION_ALT_ATTACK, ACTION_ATTACK, ACTION_CROUCH, ACTION_DELAYEDJUMP, ACTION_FORCEPOWER, ACTION_GESTURE, ACTION_JUMP, ACTION_MOVEBACK, ACTION_MOVEFORWARD, ACTION_MOVELEFT, ACTION_MOVERIGHT, ACTION_RESPAWN, ACTION_USE, ACTION_WALK, bot_input_s::actionflags, ANGLE2SHORT, usercmd_s::angles, AngleVectors(), bot_input_t, BUTTON_ALT_ATTACK, BUTTON_ATTACK, BUTTON_FORCEPOWER, BUTTON_GESTURE, BUTTON_USE, BUTTON_USE_HOLDABLE, BUTTON_WALKING, usercmd_s::buttons, bot_input_s::dir, DotProduct, usercmd_s::forwardmove, level, memset(), NULL, PITCH, Q_irand(), usercmd_s::rightmove, ROLL, usercmd_s::serverTime, bot_input_s::speed, level_locals_t::time, ucmd, usercmd_s::upmove, usercmd_t, vec3_t, bot_input_s::viewangles, usercmd_s::weapon, bot_input_s::weapon, WP_BRYAR_PISTOL, WP_NONE, and YAW.

Referenced by BotUpdateInput().

00537                                                                                                          {
00538         vec3_t angles, forward, right;
00539         short temp;
00540         int j;
00541 
00542         //clear the whole structure
00543         memset(ucmd, 0, sizeof(usercmd_t));
00544         //
00545         //Com_Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);
00546         //the duration for the user command in milli seconds
00547         ucmd->serverTime = time;
00548         //
00549         if (bi->actionflags & ACTION_DELAYEDJUMP) {
00550                 bi->actionflags |= ACTION_JUMP;
00551                 bi->actionflags &= ~ACTION_DELAYEDJUMP;
00552         }
00553         //set the buttons
00554         if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
00555         if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
00556         if (bi->actionflags & ACTION_ALT_ATTACK) ucmd->buttons |= BUTTON_ALT_ATTACK;
00557 //      if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
00558         if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
00559         if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
00560         if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;
00561 
00562         if (bi->actionflags & ACTION_FORCEPOWER) ucmd->buttons |= BUTTON_FORCEPOWER;
00563 
00564         if (useTime < level.time && Q_irand(1, 10) < 5)
00565         { //for now just hit use randomly in case there's something useable around
00566                 ucmd->buttons |= BUTTON_USE;
00567         }
00568 #if 0
00569 // Here's an interesting bit.  The bots in TA used buttons to do additional gestures.
00570 // I ripped them out because I didn't want too many buttons given the fact that I was already adding some for JK2.
00571 // We can always add some back in if we want though.
00572         if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
00573         if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
00574         if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
00575         if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
00576         if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
00577         if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
00578 #endif //0
00579 
00580         if (bi->weapon == WP_NONE)
00581         {
00582 #ifdef _DEBUG
00583 //              Com_Printf("WARNING: Bot tried to use WP_NONE!\n");
00584 #endif
00585                 bi->weapon = WP_BRYAR_PISTOL;
00586         }
00587 
00588         //
00589         ucmd->weapon = bi->weapon;
00590         //set the view angles
00591         //NOTE: the ucmd->angles are the angles WITHOUT the delta angles
00592         ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
00593         ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
00594         ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
00595         //subtract the delta angles
00596         for (j = 0; j < 3; j++) {
00597                 temp = ucmd->angles[j] - delta_angles[j];
00598                 ucmd->angles[j] = temp;
00599         }
00600         //NOTE: movement is relative to the REAL view angles
00601         //get the horizontal forward and right vector
00602         //get the pitch in the range [-180, 180]
00603         if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
00604         else angles[PITCH] = 0;
00605         angles[YAW] = bi->viewangles[YAW];
00606         angles[ROLL] = 0;
00607         AngleVectors(angles, forward, right, NULL);
00608         //bot input speed is in the range [0, 400]
00609         bi->speed = bi->speed * 127 / 400;
00610         //set the view independent movement
00611         ucmd->forwardmove = DotProduct(forward, bi->dir) * bi->speed;
00612         ucmd->rightmove = DotProduct(right, bi->dir) * bi->speed;
00613         ucmd->upmove = abs((int)(forward[2])) * bi->dir[2] * bi->speed;
00614         //normal keyboard movement
00615         if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove += 127;
00616         if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove -= 127;
00617         if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove -= 127;
00618         if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove += 127;
00619         //jump/moveup
00620         if (bi->actionflags & ACTION_JUMP) ucmd->upmove += 127;
00621         //crouch/movedown
00622         if (bi->actionflags & ACTION_CROUCH) ucmd->upmove -= 127;
00623         //
00624         //Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);
00625         //Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime);
00626 }

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, gentity_s::client, bot_state_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 BotLovedOneDied bot_state_t bs,
bot_state_t loved,
int  lovelevel
 

Definition at line 5315 of file ai_main.c.

References bot_attachments, bot_state_t, BotDoChat(), bot_state_s::chatAltObject, bot_state_s::chatObject, bot_state_s::client, gentity_s::client, g_entities, g_gametype, GT_DUEL, GT_POWERDUEL, vmCvar_t::integer, IsTeamplay(), bot_state_s::lastHurt, bot_state_s::loved_death_thresh, NULL, entityState_s::number, OnSameTeam(), PassLovedOneCheck(), bot_state_s::revengeEnemy, bot_state_s::revengeHateLevel, and gentity_s::s.

Referenced by BotDeathNotify().

05316 {
05317         if (!loved->lastHurt || !loved->lastHurt->client ||
05318                 loved->lastHurt->s.number == loved->client)
05319         {
05320                 return;
05321         }
05322 
05323         if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
05324         { //There is no love in 1-on-1
05325                 return;
05326         }
05327 
05328         if (!IsTeamplay())
05329         {
05330                 if (lovelevel < 2)
05331                 {
05332                         return;
05333                 }
05334         }
05335         else if (OnSameTeam(&g_entities[bs->client], loved->lastHurt))
05336         { //don't hate teammates no matter what
05337                 return;
05338         }
05339 
05340         if (loved->client == loved->lastHurt->s.number)
05341         {
05342                 return;
05343         }
05344 
05345         if (bs->client == loved->lastHurt->s.number)
05346         { //oops!
05347                 return;
05348         }
05349         
05350         if (!bot_attachments.integer)
05351         {
05352                 return;
05353         }
05354 
05355         if (!PassLovedOneCheck(bs, loved->lastHurt))
05356         { //a loved one killed a loved one.. you cannot hate them
05357                 bs->chatObject = loved->lastHurt;
05358                 bs->chatAltObject = &g_entities[loved->client];
05359                 BotDoChat(bs, "LovedOneKilledLovedOne", 0);
05360                 return;
05361         }
05362 
05363         if (bs->revengeEnemy == loved->lastHurt)
05364         {
05365                 if (bs->revengeHateLevel < bs->loved_death_thresh)
05366                 {
05367                         bs->revengeHateLevel++;
05368 
05369                         if (bs->revengeHateLevel == bs->loved_death_thresh)
05370                         {
05371                                 //broke into the highest anger level
05372                                 //CHAT: Hatred section
05373                                 bs->chatObject = loved->lastHurt;
05374                                 bs->chatAltObject = NULL;
05375                                 BotDoChat(bs, "Hatred", 1);
05376                         }
05377                 }
05378         }
05379         else if (bs->revengeHateLevel < bs->loved_death_thresh-1)
05380         { //only switch hatred if we don't hate the existing revenge-enemy too much
05381                 //CHAT: BelovedKilled section
05382                 bs->chatObject = &g_entities[loved->client];
05383                 bs->chatAltObject = loved->lastHurt;
05384                 BotDoChat(bs, "BelovedKilled", 0);
05385                 bs->revengeHateLevel = 0;
05386                 bs->revengeEnemy = loved->lastHurt;
05387         }
05388 }

int BotMindTricked int  botClient,
int  enemyClient
 

Definition at line 279 of file ai_main.c.

References gentity_s::client, playerState_s::fd, forcedata_t, forcedata_s::forceMindtrickTargetIndex, forcedata_s::forceMindtrickTargetIndex2, forcedata_s::forceMindtrickTargetIndex3, forcedata_s::forceMindtrickTargetIndex4, g_entities, and gclient_s::ps.

Referenced by BotAimOffsetGoalAngles(), BotCanHear(), PassStandardEnemyChecks(), ScanForEnemies(), and StandardBotAI().

00280 {
00281         forcedata_t *fd;
00282 
00283         if (!g_entities[enemyClient].client)
00284         {
00285                 return 0;
00286         }
00287         
00288         fd = &g_entities[enemyClient].client->ps.fd;
00289 
00290         if (!fd)
00291         {
00292                 return 0;
00293         }
00294 
00295         if (botClient > 47)
00296         {
00297                 if (fd->forceMindtrickTargetIndex4 & (1 << (botClient-48)))
00298                 {
00299                         return 1;
00300                 }
00301         }
00302         else if (botClient > 31)
00303         {
00304                 if (fd->forceMindtrickTargetIndex3 & (1 << (botClient-32)))
00305                 {
00306                         return 1;
00307                 }
00308         }
00309         else if (botClient > 15)
00310         {
00311                 if (fd->forceMindtrickTargetIndex2 & (1 << (botClient-16)))
00312                 {
00313                         return 1;
00314                 }
00315         }
00316         else
00317         {
00318                 if (fd->forceMindtrickTargetIndex & (1 << botClient))
00319                 {
00320                         return 1;
00321                 }
00322         }
00323 
00324         return 0;
00325 }

void BotOrder gentity_t ent,
int  clientnum,
int  ordernum
 

Definition at line 184 of file ai_main.c.

References BotDoChat(), BotReportStatus(), botstates, BotStraightTPOrderCheck(), bot_state_s::chatAltObject, bot_state_s::chatObject, bot_state_s::chatTeam, gentity_s::client, CTFSTATE_MAXCTFSTATES, CTFSTATE_NONE, g_entities, g_gametype, gentity_t, GT_CTF, GT_CTY, GT_SIEGE, GT_TEAM, vmCvar_t::integer, MAX_CLIENTS, NULL, OnSameTeam(), gclient_s::sess, SIEGESTATE_MAXSIEGESTATES, SIEGESTATE_NONE, bot_state_s::state_Forced, clientSession_t::teamLeader, TEAMPLAYSTATE_MAXTPSTATES, and TEAMPLAYSTATE_NONE.

00185 {
00186         int stateMin = 0;
00187         int stateMax = 0;
00188         int i = 0;
00189 
00190         if (!ent || !ent->client || !ent->client->sess.teamLeader)
00191         {
00192                 return;
00193         }
00194 
00195         if (clientnum != -1 && !botstates[clientnum])
00196         {
00197                 return;
00198         }
00199 
00200         if (clientnum != -1 && !OnSameTeam(ent, &g_entities[clientnum]))
00201         {
00202                 return;
00203         }
00204 
00205         if (g_gametype.integer != GT_CTF && g_gametype.integer != GT_CTY && g_gametype.integer != GT_SIEGE &&
00206                 g_gametype.integer != GT_TEAM)
00207         {
00208                 return;
00209         }
00210 
00211         if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY)
00212         {
00213                 stateMin = CTFSTATE_NONE;
00214                 stateMax = CTFSTATE_MAXCTFSTATES;
00215         }
00216         else if (g_gametype.integer == GT_SIEGE)
00217         {
00218                 stateMin = SIEGESTATE_NONE;
00219                 stateMax = SIEGESTATE_MAXSIEGESTATES;
00220         }
00221         else if (g_gametype.integer == GT_TEAM)
00222         {
00223                 stateMin = TEAMPLAYSTATE_NONE;
00224                 stateMax = TEAMPLAYSTATE_MAXTPSTATES;
00225         }
00226 
00227         if ((ordernum < stateMin && ordernum != -1) || ordernum >= stateMax)
00228         {
00229                 return;
00230         }
00231 
00232         if (clientnum != -1)
00233         {
00234                 if (ordernum == -1)
00235                 {
00236                         BotReportStatus(botstates[clientnum]);
00237                 }
00238                 else
00239                 {
00240                         BotStraightTPOrderCheck(ent, ordernum, botstates[clientnum]);
00241                         botstates[clientnum]->state_Forced = ordernum;
00242                         botstates[clientnum]->chatObject = ent;
00243                         botstates[clientnum]->chatAltObject = NULL;
00244                         if (BotDoChat(botstates[clientnum], "OrderAccepted", 1))
00245                         {
00246                                 botstates[clientnum]->chatTeam = 1;
00247                         }
00248                 }
00249         }
00250         else
00251         {
00252                 while (i < MAX_CLIENTS)
00253                 {
00254                         if (botstates[i] && OnSameTeam(ent, &g_entities[i]))
00255                         {
00256                                 if (ordernum == -1)
00257                                 {
00258                                         BotReportStatus(botstates[i]);
00259                                 }
00260                                 else
00261                                 {
00262                                         BotStraightTPOrderCheck(ent, ordernum, botstates[i]);
00263                                         botstates[i]->state_Forced = ordernum;
00264                                         botstates[i]->chatObject = ent;
00265                                         botstates[i]->chatAltObject = NULL;
00266                                         if (BotDoChat(botstates[i], "OrderAccepted", 0))
00267                                         {
00268                                                 botstates[i]->chatTeam = 1;
00269                                         }
00270                                 }
00271                         }
00272 
00273                         i++;
00274                 }
00275         }
00276 }

qboolean BotPVSCheck const vec3_t  p1,
const vec3_t  p2
 

Definition at line 1086 of file ai_main.c.

References bot_pvstype, g_RMG, vmCvar_t::integer, qboolean, qfalse, qtrue, trap_InPVS(), vec3_t, and VectorSubtract.

Referenced by GetNearestBadThing(), GetNearestVisibleWP(), ScanForEnemies(), and SiegeTakesPriority().

01087 {
01088         if (g_RMG.integer && bot_pvstype.integer)
01089         {
01090                 vec3_t subPoint;
01091                 VectorSubtract(p1, p2, subPoint);
01092 
01093                 if (VectorLength(subPoint) > 5000)
01094                 {
01095                         return qfalse;
01096                 }
01097                 return qtrue;
01098         }
01099 
01100         return trap_InPVS(p1, p2);
01101 }

void BotReplyGreetings bot_state_t bs  ) 
 

Definition at line 5618 of file ai_main.c.

References bot_state_t, BotDoChat(), botstates, bot_state_s::canChat, bot_state_s::chatAltObject, bot_state_s::chatObject, bot_state_s::client, g_entities, MAX_CLIENTS, and NULL.

Referenced by StandardBotAI().

05619 {
05620         int i = 0;
05621         int numhello = 0;
05622 
05623         while (i < MAX_CLIENTS)
05624         {
05625                 if (botstates[i] &&
05626                         botstates[i]->canChat &&
05627                         i != bs->client)
05628                 {
05629                         botstates[i]->chatObject = &g_entities[bs->client];
05630                         botstates[i]->chatAltObject = NULL;
05631                         if (BotDoChat(botstates[i], "ResponseGreetings", 0))
05632                         {
05633                                 numhello++;
05634                         }
05635                 }
05636 
05637                 if (numhello > 3)
05638                 { //don't let more than 4 bots say hello at once
05639                         return;
05640                 }
05641 
05642                 i++;
05643         }
05644 }

void BotReportStatus bot_state_t bs  ) 
 

Definition at line 167 of file ai_main.c.

References bot_state_t, bot_state_s::client, bot_state_s::ctfState, ctfStateDescriptions, g_gametype, GT_CTF, GT_CTY, GT_SIEGE, GT_TEAM, vmCvar_t::integer, bot_state_s::siegeState, siegeStateDescriptions, bot_state_s::teamplayState, teamplayStateDescriptions, and trap_EA_SayTeam().

Referenced by BotOrder().

00168 {
00169         if (g_gametype.integer == GT_TEAM)
00170         {
00171                 trap_EA_SayTeam(bs->client, teamplayStateDescriptions[bs->teamplayState]);
00172         }
00173         else if (g_gametype.integer == GT_SIEGE)
00174         {
00175                 trap_EA_SayTeam(bs->client, siegeStateDescriptions[bs->siegeState]);
00176         }
00177         else if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY)
00178         {
00179                 trap_EA_SayTeam(bs->client, ctfStateDescriptions[bs->ctfState]);
00180         }
00181 }

void BotResetState bot_state_t bs  ) 
 

Definition at line 924 of file ai_main.c.

References bot_settings_t, bot_state_t, client, bot_state_s::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 BotScanForLeader bot_state_t bs  ) 
 

Definition at line 5585 of file ai_main.c.

References bot_state_t, botstates, bot_state_s::client, gentity_s::client, g_entities, gentity_t, GetLoveLevel(), bot_state_s::isSquadLeader, IsTeamplay(), MAX_CLIENTS, OnSameTeam(), and bot_state_s::squadLeader.

Referenced by StandardBotAI().

05586 { //bots will only automatically obtain a leader if it's another bot using this method.
05587         int i = 0;
05588         gentity_t *ent;
05589 
05590         if (bs->isSquadLeader)
05591         {
05592                 return;
05593         }
05594 
05595         while (i < MAX_CLIENTS)
05596         {
05597                 ent = &g_entities[i];
05598 
05599                 if (ent && ent->client && botstates[i] && botstates[i]->isSquadLeader && bs->client != i)
05600                 {
05601                         if (OnSameTeam(&g_entities[bs->client], ent))
05602                         {
05603                                 bs->squadLeader = ent;
05604                                 break;
05605                         }
05606                         if (GetLoveLevel(bs, botstates[i]) > 1 && !IsTeamplay())
05607                         { //ignore love status regarding squad leaders if we're in teamplay
05608                                 bs->squadLeader = ent;
05609                                 break;
05610                         }
05611                 }
05612 
05613                 i++;
05614         }
05615 }

void BotScheduleBotThink void   ) 
 

Definition at line 778 of file ai_main.c.

References BOT_THINK_TIME, botstates, bot_state_s::botthink_residual, bot_state_s::inuse, MAX_CLIENTS, and numbots.

Referenced by BotAISetupClient(), and BotAIStartFrame().

00778                                {
00779         int i, botnum;
00780 
00781         botnum = 0;
00782 
00783         for( i = 0; i < MAX_CLIENTS; i++ ) {
00784                 if( !botstates[i] || !botstates[i]->inuse ) {
00785                         continue;
00786                 }
00787                 //initialize the bot think residual time
00788                 botstates[i]->botthink_residual = BOT_THINK_TIME * botnum / numbots;
00789                 botnum++;
00790         }
00791 }

int BotSelectChoiceWeapon bot_state_t bs,
int  weapon,
int  doselection
 

Definition at line 5216 of file ai_main.c.

References playerState_s::ammo, weaponData_s::ammoIndex, bot_state_t, BotSelectWeapon(), bot_state_s::client, bot_state_s::cur_ps, weaponData_s::energyPerShot, STAT_WEAPONS, playerState_s::stats, bot_state_s::virtualWeapon, playerState_s::weapon, weaponData, and WP_NUM_WEAPONS.

Referenced by StandardBotAI().

05217 { //if !doselection then bot will only check if he has the specified weapon and return 1 (yes) or 0 (no)
05218         int i;
05219         int hasit = 0;
05220 
05221         i = 0;
05222 
05223         while (i < WP_NUM_WEAPONS)
05224         {
05225                 if (bs->cur_ps.ammo[weaponData[i].ammoIndex] > weaponData[i].energyPerShot &&
05226                         i == weapon &&
05227                         (bs->cur_ps.stats[STAT_WEAPONS] & (1 << i)))
05228                 {
05229                         hasit = 1;
05230                         break;
05231                 }
05232 
05233                 i++;
05234         }
05235 
05236         if (hasit && bs->cur_ps.weapon != weapon && doselection && bs->virtualWeapon != weapon)
05237         {
05238                 bs->virtualWeapon = weapon;
05239                 BotSelectWeapon(bs->client, weapon);
05240                 //bs->cur_ps.weapon = weapon;
05241                 //level.clients[bs->client].ps.weapon = weapon;
05242                 return 2;
05243         }
05244 
05245         if (hasit)
05246         {
05247                 return 1;
05248         }
05249 
05250         return 0;
05251 }

int BotSelectIdealWeapon bot_state_t bs  ) 
 

Definition at line 5123 of file ai_main.c.

References playerState_s::ammo, weaponData_s::ammoIndex, bot_state_t, BotSelectWeapon(), BotWeaponSelectable(), bot_state_s::botWeaponWeights, bot_state_s::client, gentity_s::client, bot_state_s::cur_ps, bot_state_s::currentEnemy, weaponData_s::energyPerShot, bot_state_s::frame_Enemy_Len, gclient_s::ps, STAT_WEAPONS, playerState_s::stats, bot_state_s::virtualWeapon, playerState_s::weapon, weaponData, WP_BLASTER, WP_BOWCASTER, WP_BRYAR_PISTOL, WP_DEMP2, WP_DISRUPTOR, WP_NUM_WEAPONS, WP_REPEATER, WP_ROCKET_LAUNCHER, WP_SABER, and WP_THERMAL.

Referenced by StandardBotAI().

05124 {
05125         int i;
05126         int bestweight = -1;
05127         int bestweapon = 0;
05128 
05129         i = 0;
05130 
05131         while (i < WP_NUM_WEAPONS)
05132         {
05133                 if (bs->cur_ps.ammo[weaponData[i].ammoIndex] >= weaponData[i].energyPerShot &&
05134                         bs->botWeaponWeights[i] > bestweight &&
05135                         (bs->cur_ps.stats[STAT_WEAPONS] & (1 << i)))
05136                 {
05137                         if (i == WP_THERMAL)
05138                         { //special case..
05139                                 if (bs->currentEnemy && bs->frame_Enemy_Len < 700)
05140                                 {
05141                                         bestweight = bs->botWeaponWeights[i];
05142                                         bestweapon = i;
05143                                 }
05144                         }
05145                         else
05146                         {
05147                                 bestweight = bs->botWeaponWeights[i];
05148                                 bestweapon = i;
05149                         }
05150                 }
05151 
05152                 i++;
05153         }
05154 
05155         if ( bs->currentEnemy && bs->frame_Enemy_Len < 300 &&
05156                 (bestweapon == WP_BRYAR_PISTOL || bestweapon == WP_BLASTER || bestweapon == WP_BOWCASTER) &&
05157                 (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SABER)) )
05158         {
05159                 bestweapon = WP_SABER;
05160                 bestweight = 1;
05161         }
05162 
05163         if ( bs->currentEnemy && bs->frame_Enemy_Len > 300 &&
05164                 bs->currentEnemy->client && bs->currentEnemy->client->ps.weapon != WP_SABER &&
05165                 (bestweapon == WP_SABER) )
05166         { //if the enemy is far away, and we have our saber selected, see if we have any good distance weapons instead
05167                 if (BotWeaponSelectable(bs, WP_DISRUPTOR))
05168                 {
05169                         bestweapon = WP_DISRUPTOR;
05170                         bestweight = 1;
05171                 }
05172                 else if (BotWeaponSelectable(bs, WP_ROCKET_LAUNCHER))
05173                 {
05174                         bestweapon = WP_ROCKET_LAUNCHER;
05175                         bestweight = 1;
05176                 }
05177                 else if (BotWeaponSelectable(bs, WP_BOWCASTER))
05178                 {
05179                         bestweapon = WP_BOWCASTER;
05180                         bestweight = 1;
05181                 }
05182                 else if (BotWeaponSelectable(bs, WP_BLASTER))
05183                 {
05184                         bestweapon = WP_BLASTER;
05185                         bestweight = 1;
05186                 }
05187                 else if (BotWeaponSelectable(bs, WP_REPEATER))
05188                 {
05189                         bestweapon = WP_REPEATER;
05190                         bestweight = 1;
05191                 }
05192                 else if (BotWeaponSelectable(bs, WP_DEMP2))
05193                 {
05194                         bestweapon = WP_DEMP2;
05195                         bestweight = 1;
05196                 }
05197         }
05198 
05199         //assert(bs->cur_ps.weapon > 0 && bestweapon > 0);
05200 
05201         if (bestweight != -1 && bs->cur_ps.weapon != bestweapon && bs->virtualWeapon != bestweapon)
05202         {
05203                 bs->virtualWeapon = bestweapon;
05204                 BotSelectWeapon(bs->client, bestweapon);
05205                 //bs->cur_ps.weapon = bestweapon;
05206                 //level.clients[bs->client].ps.weapon = bestweapon;
05207                 return 1;
05208         }
05209 
05210         //assert(bs->cur_ps.weapon > 0);
05211 
05212         return 0;
05213 }

int BotSelectMelee bot_state_t bs  ) 
 

Definition at line 5254 of file ai_main.c.

References bot_state_t, BotSelectWeapon(), bot_state_s::client, bot_state_s::cur_ps, bot_state_s::virtualWeapon, and playerState_s::weapon.

05255 {
05256         if (bs->cur_ps.weapon != 1 && bs->virtualWeapon != 1)
05257         {
05258                 bs->virtualWeapon = 1;
05259                 BotSelectWeapon(bs->client, 1);
05260                 //bs->cur_ps.weapon = 1;
05261                 //level.clients[bs->client].ps.weapon = 1;
05262                 return 1;
05263         }
05264 
05265         return 0;
05266 }

void BotSelectWeapon int  client,
int  weapon
 

Definition at line 157 of file ai_main.c.

References client, trap_EA_SelectWeapon(), and WP_NONE.

Referenced by BotSelectChoiceWeapon(), BotSelectIdealWeapon(), BotSelectMelee(), and BotTryAnotherWeapon().

00158 {
00159         if (weapon <= WP_NONE)
00160         {
00161 //              assert(0);
00162                 return;
00163         }
00164         trap_EA_SelectWeapon(client, weapon);
00165 }

void BotStraightTPOrderCheck gentity_t ent,
int  ordernum,
bot_state_t bs
 

Definition at line 128 of file ai_main.c.

References bot_state_t, gentity_t, bot_state_s::isSquadLeader, NULL, bot_state_s::squadLeader, bot_state_s::teamplayState, TEAMPLAYSTATE_ASSISTING, TEAMPLAYSTATE_FOLLOWING, and bot_state_s::wpDestSwitchTime.

Referenced by BotOrder().

00129 {
00130         switch (ordernum)
00131         {
00132         case 0:
00133                 if (bs->squadLeader == ent)
00134                 {
00135                         bs->teamplayState = 0;
00136                         bs->squadLeader = NULL;
00137                 }
00138                 break;
00139         case TEAMPLAYSTATE_FOLLOWING:
00140                 bs->teamplayState = ordernum;
00141                 bs->isSquadLeader = 0;
00142                 bs->squadLeader = ent;
00143                 bs->wpDestSwitchTime = 0;
00144                 break;
00145         case TEAMPLAYSTATE_ASSISTING:
00146                 bs->teamplayState = ordernum;
00147                 bs->isSquadLeader = 0;
00148                 bs->squadLeader = ent;
00149                 bs->wpDestSwitchTime = 0;
00150                 break;
00151         default:
00152                 bs->teamplayState = ordernum;
00153                 break;
00154         }
00155 }

int BotSurfaceNear bot_state_t bs  ) 
 

Definition at line 5833 of file ai_main.c.

References AngleVectors(), bot_state_t, bot_state_s::client, trace_t::fraction, MASK_SOLID, NULL, bot_state_s::origin, trap_Trace(), vec3_t, and bot_state_s::viewangles.

Referenced by StandardBotAI().

05834 {
05835         trace_t tr;
05836         vec3_t fwd;
05837 
05838         AngleVectors(bs->viewangles, fwd, NULL, NULL);
05839 
05840         fwd[0] = bs->origin[0]+(fwd[0]*64);
05841         fwd[1] = bs->origin[1]+(fwd[1]*64);
05842         fwd[2] = bs->origin[2]+(fwd[2]*64);
05843 
05844         trap_Trace(&tr, bs->origin, NULL, NULL, fwd, bs->client, MASK_SOLID);
05845 
05846         if (tr.fraction != 1)
05847         {
05848                 return 1;
05849         }
05850 
05851         return 0;
05852 }

int BotTrace_Duck bot_state_t bs,
vec3_t  traceto
 

Definition at line 1702 of file ai_main.c.

References AngleVectors(), bot_state_t, bot_state_s::client, trace_t::fraction, MASK_PLAYERSOLID, NULL, bot_state_s::origin, trap_Trace(), vec3_t, vectoangles(), VectorCopy, and VectorSubtract.

Referenced by StandardBotAI().

01703 {
01704         vec3_t mins, maxs, a, fwd, traceto_mod, tracefrom_mod;
01705         trace_t tr;
01706 
01707         VectorSubtract(traceto, bs->origin, a);
01708         vectoangles(a, a);
01709 
01710         AngleVectors(a, fwd, NULL, NULL);
01711 
01712         traceto_mod[0] = bs->origin[0] + fwd[0]*4;
01713         traceto_mod[1] = bs->origin[1] + fwd[1]*4;
01714         traceto_mod[2] = bs->origin[2] + fwd[2]*4;
01715 
01716         mins[0] = -15;
01717         mins[1] = -15;
01718         mins[2] = -23;
01719         maxs[0] = 15;
01720         maxs[1] = 15;
01721         maxs[2] = 8;
01722 
01723         trap_Trace(&tr, bs->origin, mins, maxs, traceto_mod, bs->client, MASK_PLAYERSOLID);
01724 
01725         if (tr.fraction != 1)
01726         {
01727                 return 0;
01728         }
01729 
01730         VectorCopy(bs->origin, tracefrom_mod);
01731 
01732         tracefrom_mod[2] += 31;//33;
01733         traceto_mod[2] += 31;//33;
01734 
01735         mins[0] = -15;
01736         mins[1] = -15;
01737         mins[2] = 0;
01738         maxs[0] = 15;
01739         maxs[1] = 15;
01740         maxs[2] = 32;
01741 
01742         trap_Trace(&tr, tracefrom_mod, mins, maxs, traceto_mod, bs->client, MASK_PLAYERSOLID);
01743 
01744         if (tr.fraction != 1)
01745         {
01746                 return 1;
01747         }
01748 
01749         return 0;
01750 }

int BotTrace_Jump bot_state_t bs,
vec3_t  traceto
 

Definition at line 1638 of file ai_main.c.

References AngleVectors(), bot_state_t, BotGetWeaponRange(), botstates, BWEAPONRANGE_MELEE, BWEAPONRANGE_SABER, bot_state_s::client, bot_state_s::currentEnemy, trace_t::entityNum, trace_t::fraction, bot_state_s::jumpTime, level, MASK_PLAYERSOLID, MAX_CLIENTS, NULL, entityState_s::number, bot_state_s::origin, gentity_s::s, level_locals_t::time, trap_Trace(), vec3_t, vectoangles(), VectorCopy, and VectorSubtract.

Referenced by StandardBotAI().

01639 {
01640         vec3_t mins, maxs, a, fwd, traceto_mod, tracefrom_mod;
01641         trace_t tr;
01642         int orTr;
01643 
01644         VectorSubtract(traceto, bs->origin, a);
01645         vectoangles(a, a);
01646 
01647         AngleVectors(a, fwd, NULL, NULL);
01648 
01649         traceto_mod[0] = bs->origin[0] + fwd[0]*4;
01650         traceto_mod[1] = bs->origin[1] + fwd[1]*4;
01651         traceto_mod[2] = bs->origin[2] + fwd[2]*4;
01652 
01653         mins[0] = -15;
01654         mins[1] = -15;
01655         mins[2] = -18;
01656         maxs[0] = 15;
01657         maxs[1] = 15;
01658         maxs[2] = 32;
01659 
01660         trap_Trace(&tr, bs->origin, mins, maxs, traceto_mod, bs->client, MASK_PLAYERSOLID);
01661 
01662         if (tr.fraction == 1)
01663         {
01664                 return 0;
01665         }
01666 
01667         orTr = tr.entityNum;
01668 
01669         VectorCopy(bs->origin, tracefrom_mod);
01670 
01671         tracefrom_mod[2] += 41;
01672         traceto_mod[2] += 41;
01673 
01674         mins[0] = -15;
01675         mins[1] = -15;
01676         mins[2] = 0;
01677         maxs[0] = 15;
01678         maxs[1] = 15;
01679         maxs[2] = 8;
01680 
01681         trap_Trace(&tr, tracefrom_mod, mins, maxs, traceto_mod, bs->client, MASK_PLAYERSOLID);
01682 
01683         if (tr.fraction == 1)
01684         {
01685                 if (orTr >= 0 && orTr < MAX_CLIENTS && botstates[orTr] && botstates[orTr]->jumpTime > level.time)
01686                 {
01687                         return 0; //so bots don't try to jump over each other at the same time
01688                 }
01689 
01690                 if (bs->currentEnemy && bs->currentEnemy->s.number == orTr && (BotGetWeaponRange(bs) == BWEAPONRANGE_SABER || BotGetWeaponRange(bs) == BWEAPONRANGE_MELEE))
01691                 {
01692                         return 0;
01693                 }
01694 
01695                 return 1;
01696         }
01697 
01698         return 0;
01699 }

int BotTrace_Strafe bot_state_t bs,
vec3_t  traceto
 

Definition at line 1556 of file ai_main.c.

References AngleDifference(), AngleVectors(), bot_state_t, bot_state_s::client, bot_state_s::cur_ps, DEFAULT_MAXS_2, ENTITYNUM_NONE, trace_t::fraction, playerState_s::groundEntityNum, MASK_PLAYERSOLID, bot_state_s::origin, playerMaxs, playerMins, STRAFEAROUND_LEFT, STRAFEAROUND_RIGHT, trap_Trace(), vec3_t, vectoangles(), VectorCopy, VectorNormalize(), VectorSubtract, bot_state_s::viewangles, and YAW.

Referenced by StandardBotAI().

01557 {
01558         vec3_t playerMins = {-15, -15, /*DEFAULT_MINS_2*/-8};
01559         vec3_t playerMaxs = {15, 15, DEFAULT_MAXS_2};
01560         vec3_t from, to;
01561         vec3_t dirAng, dirDif;
01562         vec3_t forward, right;
01563         trace_t tr;
01564 
01565         if (bs->cur_ps.groundEntityNum == ENTITYNUM_NONE)
01566         { //don't do this in the air, it can be.. dangerous.
01567                 return 0;
01568         }
01569 
01570         VectorSubtract(traceto, bs->origin, dirAng);
01571         VectorNormalize(dirAng);
01572         vectoangles(dirAng, dirAng);
01573 
01574         if (AngleDifference(bs->viewangles[YAW], dirAng[YAW]) > 60 ||
01575                 AngleDifference(bs->viewangles[YAW], dirAng[YAW]) < -60)
01576         { //If we aren't facing the direction we're going here, then we've got enough excuse to be too stupid to strafe around anyway
01577                 return 0;
01578         }
01579 
01580         VectorCopy(bs->origin, from);
01581         VectorCopy(traceto, to);
01582 
01583         VectorSubtract(to, from, dirDif);
01584         VectorNormalize(dirDif);
01585         vectoangles(dirDif, dirDif);
01586 
01587         AngleVectors(dirDif, forward, 0, 0);
01588 
01589         to[0] = from[0] + forward[0]*32;
01590         to[1] = from[1] + forward[1]*32;
01591         to[2] = from[2] + forward[2]*32;
01592 
01593         trap_Trace(&tr, from, playerMins, playerMaxs, to, bs->client, MASK_PLAYERSOLID);
01594 
01595         if (tr.fraction == 1)
01596         {
01597                 return 0;
01598         }
01599 
01600         AngleVectors(dirAng, 0, right, 0);
01601 
01602         from[0] += right[0]*32;
01603         from[1] += right[1]*32;
01604         from[2] += right[2]*16;
01605 
01606         to[0] += right[0]*32;
01607         to[1] += right[1]*32;
01608         to[2] += right[2]*32;
01609 
01610         trap_Trace(&tr, from, playerMins, playerMaxs, to, bs->client, MASK_PLAYERSOLID);
01611 
01612         if (tr.fraction == 1)
01613         {
01614                 return STRAFEAROUND_RIGHT;
01615         }
01616 
01617         from[0] -= right[0]*64;
01618         from[1] -= right[1]*64;
01619         from[2] -= right[2]*64;
01620 
01621         to[0] -= right[0]*64;
01622         to[1] -= right[1]*64;
01623         to[2] -= right[2]*64;
01624 
01625         trap_Trace(&tr, from, playerMins, playerMaxs, to, bs->client, MASK_PLAYERSOLID);
01626 
01627         if (tr.fraction == 1)
01628         {
01629                 return STRAFEAROUND_LEFT;
01630         }
01631 
01632         return 0;
01633 }

int BotTryAnotherWeapon bot_state_t bs  ) 
 

Definition at line 5072 of file ai_main.c.

References playerState_s::ammo, weaponData_s::ammoIndex, bot_state_t, BotSelectWeapon(), bot_state_s::client, bot_state_s::cur_ps, weaponData_s::energyPerShot, STAT_WEAPONS, playerState_s::stats, bot_state_s::virtualWeapon, playerState_s::weapon, weaponData, and WP_NUM_WEAPONS.

Referenced by StandardBotAI().

05073 { //out of ammo, resort to the first weapon we come across that has ammo
05074         int i;
05075 
05076         i = 1;
05077 
05078         while (i < WP_NUM_WEAPONS)
05079         {
05080                 if (bs->cur_ps.ammo[weaponData[i].ammoIndex] >= weaponData[i].energyPerShot &&
05081                         (bs->cur_ps.stats[STAT_WEAPONS] & (1 << i)))
05082                 {
05083                         bs->virtualWeapon = i;
05084                         BotSelectWeapon(bs->client, i);
05085                         //bs->cur_ps.weapon = i;
05086                         //level.clients[bs->client].ps.weapon = i;
05087                         return 1;
05088                 }
05089 
05090                 i++;
05091         }
05092 
05093         if (bs->cur_ps.weapon != 1 && bs->virtualWeapon != 1)
05094         { //should always have this.. shouldn't we?
05095                 bs->virtualWeapon = 1;
05096                 BotSelectWeapon(bs->client, 1);
05097                 //bs->cur_ps.weapon = 1;
05098                 //level.clients[bs->client].ps.weapon = 1;
05099                 return 1;
05100         }
05101 
05102         return 0;
05103 }

void BotUpdateInput bot_state_t bs,
int  time,
int  elapsed_time
 

Definition at line 633 of file ai_main.c.

References ACTION_ATTACK, ACTION_RESPAWN, bot_input_s::actionflags, AngleMod(), bot_input_t, bot_state_t, BotChangeViewAngles(), BotInputToUserCommand(), BUTTON_ATTACK, usercmd_s::buttons, bot_state_s::client, bot_state_s::cur_ps, playerState_s::delta_angles, bot_state_s::lastucmd, bot_state_s::noUseTime, SHORT2ANGLE, trap_EA_GetInput(), and bot_state_s::viewangles.

Referenced by BotAIStartFrame().

00633                                                                  {
00634         bot_input_t bi;
00635         int j;
00636 
00637         //add the delta angles to the bot's current view angles
00638         for (j = 0; j < 3; j++) {
00639                 bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
00640         }
00641         //change the bot view angles
00642         BotChangeViewAngles(bs, (float) elapsed_time / 1000);
00643         //retrieve the bot input
00644         trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
00645         //respawn hack
00646         if (bi.actionflags & ACTION_RESPAWN) {
00647                 if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
00648         }
00649         //convert the bot input to a usercmd
00650         BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time, bs->noUseTime);
00651         //subtract the delta angles
00652         for (j = 0; j < 3; j++) {
00653                 bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
00654         }
00655 }

int BotUseInventoryItem bot_state_t bs  ) 
 

Definition at line 5780 of file ai_main.c.

References BG_GetItemIndexByTag(), bot_state_t, bot_state_s::client, level_locals_t::clients, bot_state_s::cur_ps, bot_state_s::currentEnemy, bot_state_s::frame_Enemy_Vis, g_entities, HI_MEDPAC, HI_MEDPAC_BIG, HI_SEEKER, HI_SENTRY_GUN, HI_SHIELD, IT_HOLDABLE, level, bot_state_s::runningToEscapeThreat, STAT_HOLDABLE_ITEM, STAT_HOLDABLE_ITEMS, and playerState_s::stats.

Referenced by StandardBotAI().

05781 {
05782         if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC))
05783         {
05784                 if (g_entities[bs->client].health <= 75)
05785                 {
05786                         bs->cur_ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_MEDPAC, IT_HOLDABLE);
05787                         goto wantuseitem;
05788                 }
05789         }
05790         if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_MEDPAC_BIG))
05791         {
05792                 if (g_entities[bs->client].health <= 50)
05793                 {
05794                         bs->cur_ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_MEDPAC_BIG, IT_HOLDABLE);
05795                         goto wantuseitem;
05796                 }
05797         }
05798         if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SEEKER))
05799         {
05800                 if (bs->currentEnemy && bs->frame_Enemy_Vis)
05801                 {
05802                         bs->cur_ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_SEEKER, IT_HOLDABLE);
05803                         goto wantuseitem;
05804                 }
05805         }
05806         if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SENTRY_GUN))
05807         {
05808                 if (bs->currentEnemy && bs->frame_Enemy_Vis)
05809                 {
05810                         bs->cur_ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_SENTRY_GUN, IT_HOLDABLE);
05811                         goto wantuseitem;
05812                 }
05813         }
05814         if (bs->cur_ps.stats[STAT_HOLDABLE_ITEMS] & (1 << HI_SHIELD))
05815         {
05816                 if (bs->currentEnemy && bs->frame_Enemy_Vis && bs->runningToEscapeThreat)
05817                 { //this will (hopefully) result in the bot placing the shield down while facing
05818                   //the enemy and running away
05819                         bs->cur_ps.stats[STAT_HOLDABLE_ITEM] = BG_GetItemIndexByTag(HI_SHIELD, IT_HOLDABLE);
05820                         goto wantuseitem;
05821                 }
05822         }
05823 
05824         return 0;
05825 
05826 wantuseitem:
05827         level.clients[bs->client].ps.stats[STAT_HOLDABLE_ITEM] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM];
05828 
05829         return 1;
05830 }

int BotWeaponBlockable int  weapon  ) 
 

Definition at line 5855 of file ai_main.c.

References WP_DEMP2, WP_DET_PACK, WP_DISRUPTOR, WP_MELEE, WP_ROCKET_LAUNCHER, WP_STUN_BATON, WP_THERMAL, and WP_TRIP_MINE.

Referenced by StandardBotAI().

05856 {
05857         switch (weapon)
05858         {
05859         case WP_STUN_BATON:
05860         case WP_MELEE:
05861                 return 0;
05862         case WP_DISRUPTOR:
05863                 return 0;
05864         case WP_DEMP2:
05865                 return 0;
05866         case WP_ROCKET_LAUNCHER:
05867                 return 0;
05868         case WP_THERMAL:
05869                 return 0;
05870         case WP_TRIP_MINE:
05871                 return 0;
05872         case WP_DET_PACK:
05873                 return 0;
05874         default:
05875                 return 1;
05876         }
05877 }

float BotWeaponCanLead bot_state_t bs  ) 
 

Definition at line 4570 of file ai_main.c.

References bot_state_t, bot_state_s::cur_ps, playerState_s::weapon, WP_BLASTER, WP_BOWCASTER, WP_BRYAR_PISTOL, WP_DEMP2, WP_REPEATER, WP_ROCKET_LAUNCHER, and WP_THERMAL.

Referenced by StandardBotAI().

04571 {
04572         int weap = bs->cur_ps.weapon;
04573 
04574         if (weap == WP_BRYAR_PISTOL)
04575         {
04576                 return 0.5;
04577         }
04578         if (weap == WP_BLASTER)
04579         {
04580                 return 0.35;
04581         }
04582         if (weap == WP_BOWCASTER)
04583         {
04584                 return 0.5;
04585         }
04586         if (weap == WP_REPEATER)
04587         {
04588                 return 0.45;
04589         }
04590         if (weap == WP_THERMAL)
04591         {
04592                 return 0.5;
04593         }
04594         if (weap == WP_DEMP2)
04595         {
04596                 return 0.35;
04597         }
04598         if (weap == WP_ROCKET_LAUNCHER)
04599         {
04600                 return 0.7;
04601         }
04602         
04603         return 0;
04604 }

qboolean BotWeaponSelectable bot_state_t bs,
int  weapon
 

Definition at line 5106 of file ai_main.c.

References playerState_s::ammo, weaponData_s::ammoIndex, bot_state_t, bot_state_s::cur_ps, weaponData_s::energyPerShot, qboolean, qfalse, qtrue, STAT_WEAPONS, playerState_s::stats, weaponData, and WP_NONE.

Referenced by BotSelectIdealWeapon().

05107 {
05108         if (weapon == WP_NONE)
05109         {
05110                 return qfalse;
05111         }
05112 
05113         if (bs->cur_ps.ammo[weaponData[weapon].ammoIndex] >= weaponData[weapon].energyPerShot &&
05114                 (bs->cur_ps.stats[STAT_WEAPONS] & (1 << weapon)))
05115         {
05116                 return qtrue;
05117         }
05118         
05119         return qfalse;
05120 }

gentity_t* CheckForFriendInLOF bot_state_t bs  ) 
 

Definition at line 5538 of file ai_main.c.

References AngleVectors(), bot_state_t, botstates, gentity_s::client, bot_state_s::client, trace_t::entityNum, bot_state_s::eye, trace_t::fraction, g_entities, gentity_t, GetLoveLevel(), IsTeamplay(), MASK_PLAYERSOLID, MAX_CLIENTS, NULL, entityState_s::number, OnSameTeam(), gentity_s::s, trap_Trace(), vec3_t, VectorCopy, and bot_state_s::viewangles.

Referenced by StandardBotAI().

05539 {
05540         vec3_t fwd;
05541         vec3_t trfrom, trto;
05542         vec3_t mins, maxs;
05543         gentity_t *trent;
05544         trace_t tr;
05545 
05546         mins[0] = -3;
05547         mins[1] = -3;
05548         mins[2] = -3;
05549 
05550         maxs[0] = 3;
05551         maxs[1] = 3;
05552         maxs[2] = 3;
05553 
05554         AngleVectors(bs->viewangles, fwd, NULL, NULL);
05555 
05556         VectorCopy(bs->eye, trfrom);
05557 
05558         trto[0] = trfrom[0] + fwd[0]*2048;
05559         trto[1] = trfrom[1] + fwd[1]*2048;
05560         trto[2] = trfrom[2] + fwd[2]*2048;
05561 
05562         trap_Trace(&tr, trfrom, mins, maxs, trto, bs->client, MASK_PLAYERSOLID);
05563 
05564         if (tr.fraction != 1 && tr.entityNum <= MAX_CLIENTS)
05565         {
05566                 trent = &g_entities[tr.entityNum];
05567 
05568                 if (trent && trent->client)
05569                 {
05570                         if (IsTeamplay() && OnSameTeam(&g_entities[bs->client], trent))
05571                         {
05572                                 return trent;
05573                         }
05574 
05575                         if (botstates[trent->s.number] && GetLoveLevel(bs, botstates[trent->s.number]) > 1)
05576                         {
05577                                 return trent;
05578                         }
05579                 }
05580         }
05581 
05582         return NULL;
05583 }

int CheckForFunc vec3_t  org,
int  ignore
 

Definition at line 1053 of file ai_main.c.

References gentity_s::classname, trace_t::entityNum, trace_t::fraction, g_entities, gentity_t, MASK_SOLID, NULL, strstr(), trap_Trace(), vec3_t, and VectorCopy.

Referenced by StandardBotAI(), and WaitingForNow().

01054 {
01055         gentity_t *fent;
01056         vec3_t under;
01057         trace_t tr;
01058 
01059         VectorCopy(org, under);
01060 
01061         under[2] -= 64;
01062 
01063         trap_Trace(&tr, org, NULL, NULL, under, ignore, MASK_SOLID);
01064 
01065         if (tr.fraction == 1)
01066         {
01067                 return 0;
01068         }
01069 
01070         fent = &g_entities[tr.entityNum];
01071 
01072         if (!fent)
01073         {
01074                 return 0;
01075         }
01076 
01077         if (strstr(fent->classname, "func_"))
01078         {
01079                 return 1; //there's a func brush here
01080         }
01081 
01082         return 0;
01083 }

void CheckForShorterRoutes bot_state_t bs,
int  newwpindex
 

Definition at line 1263 of file ai_main.c.

References bot_state_s::beStill, bot_state_t, bot_state_s::cur_ps, playerState_s::fd, bot_state_s::forceJumpChargeTime, bot_state_s::forceJumping, wpneighbor_s::forceJumpTo, forcedata_s::forcePowerLevel, FP_LEVITATION, gWPArray, wpobject_s::index, bot_state_s::jDelay, bot_state_s::jumpTime, level, wpobject_s::neighbornum, wpobject_s::neighbors, wpneighbor_s::num, level_locals_t::time, TotalTrailDistance(), bot_state_s::wpCurrent, bot_state_s::wpDestination, bot_state_s::wpDirection, and bot_state_s::wpSwitchTime.

Referenced by WPTouchRoutine().

01264 {
01265         float bestlen;
01266         float checklen;
01267         int bestindex;
01268         int i;
01269         int fj;
01270 
01271         i = 0;
01272         fj = 0;
01273 
01274         if (!bs->wpDestination)
01275         {
01276                 return;
01277         }
01278 
01279         //set our traversal direction based on the index of the point
01280         if (newwpindex < bs->wpDestination->index)
01281         {
01282                 bs->wpDirection = 0;
01283         }
01284         else if (newwpindex > bs->wpDestination->index)
01285         {
01286                 bs->wpDirection = 1;
01287         }
01288 
01289         //can't switch again yet
01290         if (bs->wpSwitchTime > level.time)
01291         {
01292                 return;
01293         }
01294 
01295         //no neighboring points to check off of
01296         if (!gWPArray[newwpindex]->neighbornum)
01297         {
01298                 return;
01299         }
01300 
01301         //get the trail distance for our wp
01302         bestindex = newwpindex;
01303         bestlen = TotalTrailDistance(newwpindex, bs->wpDestination->index, bs);
01304 
01305         while (i < gWPArray[newwpindex]->neighbornum)
01306         { //now go through the neighbors and check the distance to the desired point from each neighbor
01307                 checklen = TotalTrailDistance(gWPArray[newwpindex]->neighbors[i].num, bs->wpDestination->index, bs);
01308 
01309                 if (checklen < bestlen-64 || bestlen == -1)
01310                 { //this path covers less distance, let's take it instead
01311                         if (bs->cur_ps.fd.forcePowerLevel[FP_LEVITATION] >= gWPArray[newwpindex]->neighbors[i].forceJumpTo)
01312                         {
01313                                 bestlen = checklen;
01314                                 bestindex = gWPArray[newwpindex]->neighbors[i].num;
01315 
01316                                 if (gWPArray[newwpindex]->neighbors[i].forceJumpTo)
01317                                 {
01318                                         fj = gWPArray[newwpindex]->neighbors[i].forceJumpTo;
01319                                 }
01320                                 else
01321                                 {
01322                                         fj = 0;
01323                                 }
01324                         }
01325                 }
01326 
01327                 i++;
01328         }
01329 
01330         if (bestindex != newwpindex && bestindex != -1)
01331         { //we found a path we want to switch to, let's do it
01332                 bs->wpCurrent = gWPArray[bestindex];
01333                 bs->wpSwitchTime = level.time + 3000;
01334 
01335                 if (fj)
01336                 { //do we have to force jump to get to this neighbor?
01337 #ifndef FORCEJUMP_INSTANTMETHOD
01338                         bs->forceJumpChargeTime = level.time + 1000;
01339                         bs->beStill = level.time + 1000;
01340                         bs->forceJumping = bs->forceJumpChargeTime;
01341 #else
01342                         bs->beStill = level.time + 500;
01343                         bs->jumpTime = level.time + fj*1200;
01344                         bs->jDelay = level.time + 200;
01345                         bs->forceJumping = bs->jumpTime;
01346 #endif
01347                 }
01348         }
01349 }

void Cmd_EngageDuel_f gentity_t ent  ) 
 

Definition at line 2766 of file g_cmds.c.

02767 {
02768         trace_t tr;
02769         vec3_t forward, fwdOrg;
02770 
02771         if (!g_privateDuel.integer)
02772         {
02773                 return;
02774         }
02775 
02776         if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL)
02777         { //rather pointless in this mode..
02778                 trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "NODUEL_GAMETYPE")) );
02779                 return;
02780         }
02781 
02782         //if (g_gametype.integer >= GT_TEAM && g_gametype.integer != GT_SIEGE)
02783         if (g_gametype.integer >= GT_TEAM)
02784         { //no private dueling in team modes
02785                 trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "NODUEL_GAMETYPE")) );
02786                 return;
02787         }
02788 
02789         if (ent->client->ps.duelTime >= level.time)
02790         {
02791                 return;
02792         }
02793 
02794         if (ent->client->ps.weapon != WP_SABER)
02795         {
02796                 return;
02797         }
02798 
02799         /*
02800         if (!ent->client->ps.saberHolstered)
02801         { //must have saber holstered at the start of the duel
02802                 return;
02803         }
02804         */
02805         //NOTE: No longer doing this..
02806 
02807         if (ent->client->ps.saberInFlight)
02808         {
02809                 return;
02810         }
02811 
02812         if (ent->client->ps.duelInProgress)
02813         {
02814                 return;
02815         }
02816 
02817         //New: Don't let a player duel if he just did and hasn't waited 10 seconds yet (note: If someone challenges him, his duel timer will reset so he can accept)
02818         if (ent->client->ps.fd.privateDuelTime > level.time)
02819         {
02820                 trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "CANTDUEL_JUSTDID")) );
02821                 return;
02822         }
02823 
02824         if (G_OtherPlayersDueling())
02825         {
02826                 trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "CANTDUEL_BUSY")) );
02827                 return;
02828         }
02829 
02830         AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL );
02831 
02832         fwdOrg[0] = ent->client->ps.origin[0] + forward[0]*256;
02833         fwdOrg[1] = ent->client->ps.origin[1] + forward[1]*256;
02834         fwdOrg[2] = (ent->client->ps.origin[2]+ent->client->ps.viewheight) + forward[2]*256;
02835 
02836         trap_Trace(&tr, ent->client->ps.origin, NULL, NULL, fwdOrg, ent->s.number, MASK_PLAYERSOLID);
02837 
02838         if (tr.fraction != 1 && tr.entityNum < MAX_CLIENTS)
02839         {
02840                 gentity_t *challenged = &g_entities[tr.entityNum];
02841 
02842                 if (!challenged || !challenged->client || !challenged->inuse ||
02843                         challenged->health < 1 || challenged->client->ps.stats[STAT_HEALTH] < 1 ||
02844                         challenged->client->ps.weapon != WP_SABER || challenged->client->ps.duelInProgress ||
02845                         challenged->client->ps.saberInFlight)
02846                 {
02847                         return;
02848                 }
02849 
02850                 if (g_gametype.integer >= GT_TEAM && OnSameTeam(ent, challenged))
02851                 {
02852                         return;
02853                 }
02854 
02855                 if (challenged->client->ps.duelIndex == ent->s.number && challenged->client->ps.duelTime >= level.time)
02856                 {
02857                         trap_SendServerCommand( /*challenged-g_entities*/-1, va("print \"%s %s %s!\n\"", challenged->client->pers.netname, G_GetStringEdString("MP_SVGAME", "PLDUELACCEPT"), ent->client->pers.netname) );
02858 
02859                         ent->client->ps.duelInProgress = qtrue;
02860                         challenged->client->ps.duelInProgress = qtrue;
02861 
02862                         ent->client->ps.duelTime = level.time + 2000;
02863                         challenged->client->ps.duelTime = level.time + 2000;
02864 
02865                         G_AddEvent(ent, EV_PRIVATE_DUEL, 1);
02866                         G_AddEvent(challenged, EV_PRIVATE_DUEL, 1);
02867 
02868                         //Holster their sabers now, until the duel starts (then they'll get auto-turned on to look cool)
02869 
02870                         if (!ent->client->ps.saberHolstered)
02871                         {
02872                                 if (ent->client->saber[0].soundOff)
02873                                 {
02874                                         G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOff);
02875                                 }
02876                                 if (ent->client->saber[1].soundOff &&
02877                                         ent->client->saber[1].model[0])
02878                                 {
02879                                         G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOff);
02880                                 }
02881                                 ent->client->ps.weaponTime = 400;
02882                                 ent->client->ps.saberHolstered = 2;
02883                         }
02884                         if (!challenged->client->ps.saberHolstered)
02885                         {
02886                                 if (challenged->client->saber[0].soundOff)
02887                                 {
02888                                         G_Sound(challenged, CHAN_AUTO, challenged->client->saber[0].soundOff);
02889                                 }
02890                                 if (challenged->client->saber[1].soundOff &&
02891                                         challenged->client->saber[1].model[0])
02892                                 {
02893                                         G_Sound(challenged, CHAN_AUTO, challenged->client->saber[1].soundOff);
02894                                 }
02895                                 challenged->client->ps.weaponTime = 400;
02896                                 challenged->client->ps.saberHolstered = 2;
02897                         }
02898                 }
02899                 else
02900                 {
02901                         //Print the message that a player has been challenged in private, only announce the actual duel initiation in private
02902                         trap_SendServerCommand( challenged-g_entities, va("cp \"%s %s\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME", "PLDUELCHALLENGE")) );
02903                         trap_SendServerCommand( ent-g_entities, va("cp \"%s %s\n\"", G_GetStringEdString("MP_SVGAME", "PLDUELCHALLENGED"), challenged->client->pers.netname) );
02904                 }
02905 
02906                 challenged->client->ps.fd.privateDuelTime = 0; //reset the timer in case this player just got out of a duel. He should still be able to accept the challenge.
02907 
02908                 ent->client->ps.forceHandExtend = HANDEXTEND_DUELCHALLENGE;
02909                 ent->client->ps.forceHandExtendTime = level.time + 1000;
02910 
02911                 ent->client->ps.duelIndex = challenged->s.number;
02912                 ent->client->ps.duelTime = level.time + 5000;
02913         }
02914 }

void Cmd_ToggleSaber_f gentity_t ent  ) 
 

Definition at line 2467 of file g_cmds.c.

02468 {
02469         if (ent->client->ps.fd.forceGripCripple)
02470         { //if they are being gripped, don't let them unholster their saber
02471                 if (ent->client->ps.saberHolstered)
02472                 {
02473                         return;
02474                 }
02475         }
02476 
02477         if (ent->client->ps.saberInFlight)
02478         {
02479                 if (ent->client->ps.saberEntityNum)
02480                 { //turn it off in midair
02481                         saberKnockDown(&g_entities[ent->client->ps.saberEntityNum], ent, ent);
02482                 }
02483                 return;
02484         }
02485 
02486         if (ent->client->ps.forceHandExtend != HANDEXTEND_NONE)
02487         {
02488                 return;
02489         }
02490 
02491         if (ent->client->ps.weapon != WP_SABER)
02492         {
02493                 return;
02494         }
02495 
02496 //      if (ent->client->ps.duelInProgress && !ent->client->ps.saberHolstered)
02497 //      {
02498 //              return;
02499 //      }
02500 
02501         if (ent->client->ps.duelTime >= level.time)
02502         {
02503                 return;
02504         }
02505 
02506         if (ent->client->ps.saberLockTime >= level.time)
02507         {
02508                 return;
02509         }
02510 
02511         if (ent->client && ent->client->ps.weaponTime < 1)
02512         {
02513                 if (ent->client->ps.saberHolstered == 2)
02514                 {
02515                         ent->client->ps.saberHolstered = 0;
02516 
02517                         if (ent->client->saber[0].soundOn)
02518                         {
02519                                 G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOn);
02520                         }
02521                         if (ent->client->saber[1].soundOn)
02522                         {
02523                                 G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOn);
02524                         }
02525                 }
02526                 else
02527                 {
02528                         ent->client->ps.saberHolstered = 2;
02529                         if (ent->client->saber[0].soundOff)
02530                         {
02531                                 G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOff);
02532                         }
02533                         if (ent->client->saber[1].soundOff &&
02534                                 ent->client->saber[1].model[0])
02535                         {
02536                                 G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOff);
02537                         }
02538                         //prevent anything from being done for 400ms after holster
02539                         ent->client->ps.weaponTime = 400;
02540                 }
02541         }
02542 }

int CombatBotAI bot_state_t bs,
float  thinktime
 

Definition at line 4885 of file ai_main.c.

References bot_state_s::altChargeTime, bot_state_t, BotGetWeaponRange(), BWEAPONRANGE_MELEE, BWEAPONRANGE_SABER, gentity_s::client, bot_state_s::cur_ps, bot_state_s::currentEnemy, bot_state_s::doAltAttack, bot_state_s::doAttack, bot_state_s::eye, bot_state_s::frame_Enemy_Len, InFieldOfVision(), level, MELEE_ATTACK_RANGE, entityState_s::origin, playerState_s::origin, gclient_s::ps, Q_irand(), gentity_s::s, SABER_ATTACK_RANGE, ShouldSecondaryFire(), level_locals_t::time, vec3_t, vectoangles(), VectorCopy, VectorSubtract, bot_state_s::viewangles, playerState_s::weapon, WEAPON_CHARGING, WEAPON_CHARGING_ALT, playerState_s::weaponChargeTime, playerState_s::weaponstate, WP_ROCKET_LAUNCHER, and WP_THERMAL.

Referenced by StandardBotAI().

04886 {
04887         vec3_t eorg, a;
04888         int secFire;
04889         float fovcheck;
04890 
04891         if (!bs->currentEnemy)
04892         {
04893                 return 0;
04894         }
04895 
04896         if (bs->currentEnemy->client)
04897         {
04898                 VectorCopy(bs->currentEnemy->client->ps.origin, eorg);
04899         }
04900         else
04901         {
04902                 VectorCopy(bs->currentEnemy->s.origin, eorg);
04903         }
04904 
04905         VectorSubtract(eorg, bs->eye, a);
04906         vectoangles(a, a);
04907 
04908         if (BotGetWeaponRange(bs) == BWEAPONRANGE_SABER)
04909         {
04910                 if (bs->frame_Enemy_Len <= SABER_ATTACK_RANGE)
04911                 {
04912                         bs->doAttack = 1;
04913                 }
04914         }
04915         else if (BotGetWeaponRange(bs) == BWEAPONRANGE_MELEE)
04916         {
04917                 if (bs->frame_Enemy_Len <= MELEE_ATTACK_RANGE)
04918                 {
04919                         bs->doAttack = 1;
04920                 }
04921         }
04922         else
04923         {
04924                 if (bs->cur_ps.weapon == WP_THERMAL || bs->cur_ps.weapon == WP_ROCKET_LAUNCHER)
04925                 { //be careful with the hurty weapons
04926                         fovcheck = 40;
04927 
04928                         if (bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT &&
04929                                 bs->cur_ps.weapon == WP_ROCKET_LAUNCHER)
04930                         { //if we're charging the weapon up then we can hold fire down within a normal fov
04931                                 fovcheck = 60;
04932                         }
04933                 }
04934                 else
04935                 {
04936                         fovcheck = 60;
04937                 }
04938 
04939                 if (bs->cur_ps.weaponstate == WEAPON_CHARGING ||
04940                         bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT)
04941                 {
04942                         fovcheck = 160;
04943                 }
04944 
04945                 if (bs->frame_Enemy_Len < 128)
04946                 {
04947                         fovcheck *= 2;
04948                 }
04949 
04950                 if (InFieldOfVision(bs->viewangles, fovcheck, a))
04951                 {
04952                         if (bs->cur_ps.weapon == WP_THERMAL)
04953                         {
04954                                 if (((level.time - bs->cur_ps.weaponChargeTime) < (bs->frame_Enemy_Len*2) &&
04955                                         (level.time - bs->cur_ps.weaponChargeTime) < 4000 &&
04956                                         bs->frame_Enemy_Len > 64) ||
04957                                         (bs->cur_ps.weaponstate != WEAPON_CHARGING &&
04958                                         bs->cur_ps.weaponstate != WEAPON_CHARGING_ALT))
04959                                 {
04960                                         if (bs->cur_ps.weaponstate != WEAPON_CHARGING && bs->cur_ps.weaponstate != WEAPON_CHARGING_ALT)
04961                                         {
04962                                                 if (bs->frame_Enemy_Len > 512 && bs->frame_Enemy_Len < 800)
04963                                                 {
04964                                                         bs->doAltAttack = 1;
04965                                                         //bs->doAttack = 1;
04966                                                 }
04967                                                 else
04968                                                 {
04969                                                         bs->doAttack = 1;
04970                                                         //bs->doAltAttack = 1;
04971                                                 }
04972                                         }
04973 
04974                                         if (bs->cur_ps.weaponstate == WEAPON_CHARGING)
04975                                         {
04976                                                 bs->doAttack = 1;
04977                                         }
04978                                         else if (bs->cur_ps.weaponstate == WEAPON_CHARGING_ALT)
04979                                         {
04980                                                 bs->doAltAttack = 1;
04981                                         }
04982                                 }
04983                         }
04984                         else
04985                         {
04986                                 secFire = ShouldSecondaryFire(bs);
04987 
04988                                 if (bs->cur_ps.weaponstate != WEAPON_CHARGING_ALT &&
04989                                         bs->cur_ps.weaponstate != WEAPON_CHARGING)
04990                                 {
04991                                         bs->altChargeTime = Q_irand(500, 1000);
04992                                 }
04993 
04994                                 if (secFire == 1)
04995                                 {
04996                                         bs->doAltAttack = 1;
04997                                 }
04998                                 else if (!secFire)
04999                                 {
05000                                         if (bs->cur_ps.weapon != WP_THERMAL)
05001                                         {
05002                                                 if (bs->cur_ps.weaponstate != WEAPON_CHARGING ||
05003                                                         bs->altChargeTime > (level.time - bs->cur_ps.weaponChargeTime))
05004                                                 {
05005                                                         bs->doAttack = 1;
05006                                                 }
05007                                         }
05008                                         else
05009                                         {
05010                                                 bs->doAttack = 1;
05011                                         }
05012                                 }
05013 
05014                                 if (secFire == 2)
05015                                 { //released a charge
05016                                         return 1;
05017                                 }
05018                         }
05019                 }
05020         }
05021 
05022         return 0;
05023 }

void CommanderBotAI bot_state_t bs  ) 
 

Definition at line 4252 of file ai_main.c.

References bot_state_t, CommanderBotCTFAI(), CommanderBotSiegeAI(), CommanderBotTeamplayAI(), g_gametype, GT_CTF, GT_CTY, GT_SIEGE, GT_TEAM, and vmCvar_t::integer.

Referenced by StandardBotAI().

04253 {
04254         if (g_gametype.integer == GT_CTF || g_gametype.integer == GT_CTY)
04255         {
04256                 CommanderBotCTFAI(bs);
04257         }
04258         else if (g_gametype.integer == GT_SIEGE)
04259         {
04260                 CommanderBotSiegeAI(bs);
04261         }
04262         else if (g_gametype.integer == GT_TEAM)
04263         {
04264                 CommanderBotTeamplayAI(bs);
04265         }
04266 }

void CommanderBotCTFAI bot_state_t bs  ) 
 

Definition at line 3911 of file ai_main.c.

References bot_state_t, botstates, gentity_s::client, bot_state_s::client, level_locals_t::clients, bot_state_s::ctfState, CTFSTATE_ATTACKER, CTFSTATE_DEFENDER, CTFSTATE_GETFLAGHOME, CTFSTATE_GUARDCARRIER, CTFSTATE_RETRIEVAL, g_entities, gentity_t, level, MAX_CLIENTS, entityState_s::number, OnSameTeam(), playerState_s::powerups, gclient_s::ps, PW_BLUEFLAG, PW_REDFLAG, gentity_s::s, bot_state_s::squadLeader, and TEAM_RED.

Referenced by CommanderBotAI().

03912 {
03913         int i = 0;
03914         gentity_t *ent;
03915         int squadmates = 0;
03916         gentity_t *squad[MAX_CLIENTS];
03917         int defendAttackPriority = 0; //0 == attack, 1 == defend
03918         int guardDefendPriority = 0; //0 == defend, 1 == guard
03919         int attackRetrievePriority = 0; //0 == retrieve, 1 == attack
03920         int myFlag = 0;
03921         int enemyFlag = 0;
03922         int enemyHasOurFlag = 0;
03923         int weHaveEnemyFlag = 0;
03924         int numOnMyTeam = 0;
03925         int numOnEnemyTeam = 0;
03926         int numAttackers = 0;
03927         int numDefenders = 0;
03928 
03929         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
03930         {
03931                 myFlag = PW_REDFLAG;
03932         }
03933         else
03934         {
03935                 myFlag = PW_BLUEFLAG;
03936         }
03937 
03938         if (level.clients[bs->client].sess.sessionTeam == TEAM_RED)
03939         {
03940                 enemyFlag = PW_BLUEFLAG;
03941         }
03942         else
03943         {
03944                 enemyFlag = PW_REDFLAG;
03945         }
03946 
03947         while (i < MAX_CLIENTS)
03948         {
03949                 ent = &g_entities[i];
03950 
03951                 if (ent && ent->client)
03952                 {
03953                         if (ent->client->ps.powerups[enemyFlag] && OnSameTeam(&g_entities[bs->client], ent))
03954                         {
03955                                 weHaveEnemyFlag = 1;
03956                         }
03957                         else if (ent->client->ps.powerups[myFlag] && !OnSameTeam(&g_entities[bs->client], ent))
03958                         {
03959                                 enemyHasOurFlag = 1;
03960                         }
03961 
03962                         if (OnSameTeam(&g_entities[bs->client], ent))
03963                         {
03964                                 numOnMyTeam++;
03965                         }
03966                         else
03967                         {
03968                                 numOnEnemyTeam++;
03969                         }
03970 
03971                         if (botstates[ent->s.number])
03972                         {
03973                                 if (botstates[ent->s.number]->ctfState == CTFSTATE_ATTACKER ||
03974                                         botstates[ent->s.number]->ctfState == CTFSTATE_RETRIEVAL)
03975                                 {
03976                                         numAttackers++;
03977                                 }
03978                                 else
03979                                 {
03980                                         numDefenders++;
03981                                 }
03982                         }
03983                         else
03984                         { //assume real players to be attackers in our logic
03985                                 numAttackers++;
03986                         }
03987                 }
03988                 i++;
03989         }
03990 
03991         i = 0;
03992 
03993         while (i < MAX_CLIENTS)
03994         {
03995                 ent = &g_entities[i];
03996 
03997                 if (ent && ent->client && botstates[i] && botstates[i]->squadLeader && botstates[i]->squadLeader->s.number == bs->client && i != bs->client)
03998                 {
03999                         squad[squadmates] = ent;
04000                         squadmates++;
04001                 }
04002 
04003                 i++;
04004         }
04005 
04006         squad[squadmates] = &g_entities[bs->client];
04007         squadmates++;
04008 
04009         i = 0;
04010 
04011         if (enemyHasOurFlag && !weHaveEnemyFlag)
04012         { //start off with an attacker instead of a retriever if we don't have the enemy flag yet so that they can't capture it first.
04013           //after that we focus on getting our flag back.
04014                 attackRetrievePriority = 1;
04015         }
04016 
04017         while (i < squadmates)
04018         {
04019                 if (squad[i] && squad[i]->client && botstates[squad[i]->s.number])
04020                 {
04021                         if (botstates[squad[i]->s.number]->ctfState != CTFSTATE_GETFLAGHOME)
04022                         { //never tell a bot to stop trying to bring the flag to the base
04023                                 if (defendAttackPriority)
04024                                 {
04025                                         if (weHaveEnemyFlag)
04026                                         {
04027                                                 if (guardDefendPriority)
04028                                                 {
04029                                                         botstates[squad[i]->s.number]->ctfState = CTFSTATE_GUARDCARRIER;
04030                                                         guardDefendPriority = 0;
04031                                                 }
04032                                                 else
04033                                                 {
04034                                                         botstates[squad[i]->s.number]->ctfState = CTFSTATE_DEFENDER;
04035                                                         guardDefendPriority = 1;
04036                                                 }
04037                                         }
04038                                         else
04039                                         {
04040                                                 botstates[squad[i]->s.number]->ctfState = CTFSTATE_DEFENDER;
04041                                         }
04042                                         defendAttackPriority = 0;
04043                                 }
04044                                 else
04045                                 {
04046                                         if (enemyHasOurFlag)
04047                                         {
04048                                                 if (attackRetrievePriority)
04049                                                 {
04050                                                         botstates[squad[i]->s.number]->ctfState = CTFSTATE_ATTACKER;
04051                                                         attackRetrievePriority = 0;
04052                                                 }
04053                                                 else
04054                                                 {
04055                                                         botstates[squad[i]->s.number]->ctfState = CTFSTATE_RETRIEVAL;
04056                                                         attackRetrievePriority = 1;
04057                                                 }
04058                                         }
04059                                         else
04060                                         {
04061                                                 botstates[squad[i]->s.number]->ctfState = CTFSTATE_ATTACKER;
04062                                         }
04063                                         defendAttackPriority = 1;
04064                                 }
04065                         }
04066                         else if ((numOnMyTeam < 2 || !numAttackers) && enemyHasOurFlag)
04067                         { //I'm the only one on my team who will attack and the enemy has my flag, I have to go after him
04068                                 botstates[squad[i]->s.number]->ctfState = CTFSTATE_RETRIEVAL;
04069                         }
04070                 }
04071 
04072                 i++;
04073         }
04074 }

void CommanderBotSiegeAI bot_state_t bs  ) 
 

Definition at line 4077 of file ai_main.c.

References bot_state_t, botstates, bot_state_s::client, gentity_s::client, g_entities, gentity_t, bot_state_s::isSquadLeader, MAX_CLIENTS, entityState_s::number, OnSameTeam(), gentity_s::s, bot_state_s::siegeState, and bot_state_s::state_Forced.

Referenced by CommanderBotAI().

04078 {
04079         int i = 0;
04080         int squadmates = 0;
04081         int commanded = 0;
04082         int teammates = 0;
04083         gentity_t *squad[MAX_CLIENTS];
04084         gentity_t *ent;
04085         bot_state_t *bst;
04086 
04087         while (i < MAX_CLIENTS)
04088         {
04089                 ent = &g_entities[i];
04090 
04091                 if (ent && ent->client && OnSameTeam(&g_entities[bs->client], ent) && botstates[ent->s.number])
04092                 {
04093                         bst = botstates[ent->s.number];
04094 
04095                         if (bst && !bst->isSquadLeader && !bst->state_Forced)
04096                         {
04097                                 squad[squadmates] = ent;
04098                                 squadmates++;
04099                         }
04100                         else if (bst && !bst->isSquadLeader && bst->state_Forced)
04101                         { //count them as commanded
04102                                 commanded++;
04103                         }
04104                 }
04105 
04106                 if (ent && ent->client && OnSameTeam(&g_entities[bs->client], ent))
04107                 {
04108                         teammates++;
04109                 }
04110 
04111                 i++;
04112         }
04113         
04114         if (!squadmates)
04115         {
04116                 return;
04117         }
04118 
04119         //tell squad mates to do what I'm doing, up to half of team, let the other half make their own decisions
04120         i = 0;
04121 
04122         while (i < squadmates && squad[i])
04123         {
04124                 bst = botstates[squad[i]->s.number];
04125 
04126                 if (commanded > teammates/2)
04127                 {
04128                         break;
04129                 }
04130 
04131                 if (bst)
04132                 {
04133                         bst->state_Forced = bs->siegeState;
04134                         bst->siegeState = bs->siegeState;
04135                         commanded++;
04136                 }
04137 
04138                 i++;
04139         }
04140 }

void CommanderBotTeamplayAI bot_state_t bs  ) 
 

Definition at line 4158 of file ai_main.c.

References bot_state_t, botstates, bot_state_s::client, gentity_s::client, g_entities, gentity_t, gentity_s::health, bot_state_s::isSquadLeader, level, MAX_CLIENTS, entityState_s::number, OnSameTeam(), Q_irand(), gentity_s::s, bot_state_s::squadCannotLead, bot_state_s::squadLeader, bot_state_s::squadRegroupInterval, bot_state_s::state_Forced, bot_state_s::teamplayState, TEAMPLAYSTATE_ASSISTING, TEAMPLAYSTATE_FOLLOWING, TEAMPLAYSTATE_REGROUP, and level_locals_t::time.

Referenced by CommanderBotAI().

04159 {
04160         int i = 0;
04161         int squadmates = 0;
04162         int teammates = 0;
04163         int teammate_indanger = -1;
04164         int teammate_helped = 0;
04165         int foundsquadleader = 0;
04166         int worsthealth = 50;
04167         gentity_t *squad[MAX_CLIENTS];
04168         gentity_t *ent;
04169         bot_state_t *bst;
04170 
04171         while (i < MAX_CLIENTS)
04172         {
04173                 ent = &g_entities[i];
04174 
04175                 if (ent && ent->client && OnSameTeam(&g_entities[bs->client], ent) && botstates[ent->s.number])
04176                 {
04177                         bst = botstates[ent->s.number];
04178 
04179                         if (foundsquadleader && bst && bst->isSquadLeader)
04180                         { //never more than one squad leader
04181                                 bst->isSquadLeader = 0;
04182                         }
04183 
04184                         if (bst && !bst->isSquadLeader)
04185                         {
04186                                 squad[squadmates] = ent;
04187                                 squadmates++;
04188                         }
04189                         else if (bst)
04190                         {
04191                                 foundsquadleader = 1;
04192                         }
04193                 }
04194 
04195                 if (ent && ent->client && OnSameTeam(&g_entities[bs->client], ent))
04196                 {
04197                         teammates++;
04198 
04199                         if (ent->health < worsthealth)
04200                         {
04201                                 teammate_indanger = ent->s.number;
04202                                 worsthealth = ent->health;
04203                         }
04204                 }
04205 
04206                 i++;
04207         }
04208         
04209         if (!squadmates)
04210         {
04211                 return;
04212         }
04213 
04214         i = 0;
04215 
04216         while (i < squadmates && squad[i])
04217         {
04218                 bst = botstates[squad[i]->s.number];
04219 
04220                 if (bst && !bst->state_Forced)
04221                 { //only order if this guy is not being ordered directly by the real player team leader
04222                         if (teammate_indanger >= 0 && !teammate_helped)
04223                         { //send someone out to help whoever needs help most at the moment
04224                                 bst->teamplayState = TEAMPLAYSTATE_ASSISTING;
04225                                 bst->squadLeader = &g_entities[teammate_indanger];
04226                                 teammate_helped = 1;
04227                         }
04228                         else if ((teammate_indanger == -1 || teammate_helped) && bst->teamplayState == TEAMPLAYSTATE_ASSISTING)
04229                         { //no teammates need help badly, but this guy is trying to help them anyway, so stop
04230                                 bst->teamplayState = TEAMPLAYSTATE_FOLLOWING;
04231                                 bst->squadLeader = &g_entities[bs->client];
04232                         }
04233 
04234                         if (bs->squadRegroupInterval < level.time && Q_irand(1, 10) < 5)
04235                         { //every so often tell the squad to regroup for the sake of variation
04236                                 if (bst->teamplayState == TEAMPLAYSTATE_FOLLOWING)
04237                                 {
04238                                         bst->teamplayState = TEAMPLAYSTATE_REGROUP;
04239                                 }
04240 
04241                                 bs->isSquadLeader = 0;
04242                                 bs->squadCannotLead = level.time + 500;
04243                                 bs->squadRegroupInterval = level.time + Q_irand(45000, 65000);
04244                         }
04245                 }
04246 
04247                 i++;
04248         }       
04249 }

void CTFFlagMovement bot_state_t bs  ) 
 

Definition at line 5647 of file ai_main.c.

References BOT_FLAG_GET_DISTANCE, bot_state_t, gentity_s::classname, bot_state_s::client, droppedBlueFlag, droppedRedFlag, trace_t::entityNum, FL_DROPPED_ITEM, flagBlue, flagRed, gentity_s::flags, trace_t::fraction, gentity_t, bot_state_s::goalPosition, MASK_SOLID, NULL, entityState_s::number, bot_state_s::origin, entityState_s::pos, gentity_s::s, bot_state_s::staticFlagSpot, strcmp(), trap_Trace(), trajectory_t::trBase, vec3_t, VectorCopy, VectorSubtract, bot_state_s::wantFlag, and bot_state_s::wpDestination.

Referenced by StandardBotAI().

05648 {
05649         int diddrop = 0;
05650         gentity_t *desiredDrop = NULL;
05651         vec3_t a, mins, maxs;
05652         trace_t tr;
05653 
05654         mins[0] = -15;
05655         mins[1] = -15;
05656         mins[2] = -7;
05657         maxs[0] = 15;
05658         maxs[1] = 15;
05659         maxs[2] = 7;
05660 
05661         if (bs->wantFlag && (bs->wantFlag->flags & FL_DROPPED_ITEM))
05662         {
05663                 if (bs->staticFlagSpot[0] == bs->wantFlag->s.pos.trBase[0] &&
05664                         bs->staticFlagSpot[1] == bs->wantFlag->s.pos.trBase[1] &&
05665                         bs->staticFlagSpot[2] == bs->wantFlag->s.pos.trBase[2])
05666                 {
05667                         VectorSubtract(bs->origin, bs->wantFlag->s.pos.trBase, a);
05668 
05669                         if (VectorLength(a) <= BOT_FLAG_GET_DISTANCE)
05670                         {
05671                                 VectorCopy(bs->wantFlag->s.pos.trBase, bs->goalPosition);
05672                                 return;
05673                         }
05674                         else
05675                         {
05676                                 bs->wantFlag = NULL;
05677                         }
05678                 }
05679                 else
05680                 {
05681                         bs->wantFlag = NULL;
05682                 }
05683         }
05684         else if (bs->wantFlag)
05685         {
05686                 bs->wantFlag = NULL;
05687         }
05688 
05689         if (flagRed && flagBlue)
05690         {
05691                 if (bs->wpDestination == flagRed ||
05692                         bs->wpDestination == flagBlue)
05693                 {
05694                         if (bs->wpDestination == flagRed && droppedRedFlag && (droppedRedFlag->flags & FL_DROPPED_ITEM) && droppedRedFlag->classname && strcmp(droppedRedFlag->classname, "freed") != 0)
05695                         {
05696                                 desiredDrop = droppedRedFlag;
05697                                 diddrop = 1;
05698                         }
05699                         if (bs->wpDestination == flagBlue && droppedBlueFlag && (droppedBlueFlag->flags & FL_DROPPED_ITEM) && droppedBlueFlag->classname && strcmp(droppedBlueFlag->classname, "freed") != 0)
05700                         {
05701                                 desiredDrop = droppedBlueFlag;
05702                                 diddrop = 1;
05703                         }
05704 
05705                         if (diddrop && desiredDrop)
05706                         {
05707                                 VectorSubtract(bs->origin, desiredDrop->s.pos.trBase, a);
05708 
05709                                 if (VectorLength(a) <= BOT_FLAG_GET_DISTANCE)
05710                                 {
05711                                         trap_Trace(&tr, bs->origin, mins, maxs, desiredDrop->s.pos.trBase, bs->client, MASK_SOLID);
05712 
05713                                         if (tr.fraction == 1 || tr.entityNum == desiredDrop->s.number)
05714                                         {
05715                                                 VectorCopy(desiredDrop->s.pos.trBase, bs->goalPosition);
05716                                                 VectorCopy(desiredDrop->s.pos.trBase, bs->staticFlagSpot);
05717                                                 return;
05718                                         }
05719                                 }
05720                         }
05721                 }
05722         }
05723 }

int CTFTakesPriority bot_state_t bs  ) 
 

Definition at line 2804 of file ai_main.c.

References BOT_MAX_WEAPON_CHASE_CTF, BOT_MAX_WEAPON_GATHER_TIME, bot_state_t, BotDefendFlag(), BotGetEnemyFlag(), BotGetFlagBack(), BotGetFlagHome(),