/** * Decide which target to attack * @param self */ void BotFindTarget( gentity_t *self ){ int enemy; gentity_t *target; enemy = botFindEnemy( self, g_human_range.integer ); if(enemy > BOT_NO_ENEMY) { target = &g_entities[ enemy ]; //If we changed target, reset hit timer if(self->bot->Enemy != target) { botResetHitTarget( self ); self->bot->var.angleToTarget = botGetAngleToTarget(self,target); } self->bot->Enemy = target; if(botGetDistanceBetweenPlayer( self , self->bot->Enemy ) < 100) { self->bot->think.state[ THINK_LEVEL_MAX ] = ATTACK; } else { self->bot->think.state[ THINK_LEVEL_2 ] = ATTACK; } //G_BotDebug(self, BOT_VERB_DETAIL, BOT_DEBUG_COMMON + BOT_DEBUG_TARGET, "Enemy Found: %s\n", target->client ? target->client->pers.netname : target->classname); } else { //If we don't find an enemy, try using radar BotResetState( self, ATTACK ); self->bot->Enemy = NULL; self->bot->var.angleToTarget = 0; } }
/* ============== BotAILoadMap ============== */ int BotAILoadMap( int restart ) { int i; vmCvar_t mapname; if (!restart) { trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM ); trap_BotLibLoadMap( mapname.string ); } //initialize physics BotInitPhysicsSettings(); //ai_move.h //initialize the items in the level BotInitLevelItems(); //ai_goal.h BotSetBrushModelTypes(); //ai_move.h for (i = 0; i < MAX_CLIENTS; i++) { if (botstates[i] && botstates[i]->inuse) { BotResetState( botstates[i] ); botstates[i]->setupcount = 4; } } BotSetupDeathmatchAI(); return qtrue; }
/* ============== BotAILoadMap ============== */ int BotAILoadMap( int restart ) { int i; for (i = 0; i < MAX_CLIENTS; i++) { if (botstates[i] && botstates[i]->inuse) { BotResetState( botstates[i] ); botstates[i]->setupcount = 4; } } return qtrue; }
/* ============== BotAILoadMap ============== */ int BotAILoadMap( int restart ) { int i; vmCvar_t mapname; if ( !restart ) { trap_Cvar_Register( &mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM ); trap_BotLibLoadMap( mapname.string ); } for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( botstates[i] && botstates[i]->inuse ) { BotResetState( botstates[i] ); botstates[i]->setupcount = 4; } } BotSetupDeathmatchAI(); return BLERR_NOERROR; }
/* * BotAILoadMap */ int BotAILoadMap(int restart) { int i; Vmcvar mapname; if(!restart){ trap_cvarregister(&mapname, "mapname", "", CVAR_SERVERINFO | CVAR_ROM); trap_BotLibLoadMap(mapname.string); } for(i = 0; i < MAX_CLIENTS; i++) if(botstates[i] && botstates[i]->inuse){ BotResetState(botstates[i]); botstates[i]->setupcount = 4; } BotSetupDeathmatchAI(); return qtrue; }
/* ============== BotAILoadMap ============== */ int BotAILoadMap( int restart ) { int i; cvar_t *mapname; if (!restart) { mapname = Cvar_Get("mapname", "", CVAR_SERVERINFO | CVAR_ROM ); botlib_export->BotLibLoadMap( mapname->string ); } for (i = 0; i < MAX_CLIENTS; i++) { if (botstates[i] && botstates[i]->inuse) { BotResetState( botstates[i] ); botstates[i]->setupcount = 4; } } BotSetupDeathmatchAI(); return qtrue; }
/** * Main Think process * This function must only contain logic blocks (IF, SWITCH, etc) and * state suggestions. * The intention of this function is to suggest a state to bots * on different thinking levels based on current state. * DO NOT reset timers here or implement any action (except to reset some value) * @param self [gentity_t] a BOT */ void BotThink( gentity_t *self ) { //We suggest to explore unless they are in manual mode if(!g_bot_manual.integer) { self->bot->think.state[ THINK_LEVEL_MIN ] = EXPLORE; } //We search for any target. If found, we suggest ATTACK if(!self->bot->Enemy) { BotFindTarget( self ); } else { if(BotKeepThinking( self , THINK_LEVEL_2)) { BotFindTarget( self ); } } switch(self->bot->state) { case RETREAT: if(self->bot->path.numCrumb == 0) { BotResetState( self, RETREAT); } break; case ATTACK: //TODO: this first IF condition should be inside ATTACK function as we need to //keep record that it was able to kill it. Depending on target type, it should //decide what state should be next. //In case your enemy became your friend, don't shoot at him/her! if(self->bot->Enemy && self->bot->Enemy->client) { if(OnSameTeam( self, self->bot->Enemy)) { self->bot->Enemy = NULL; //Say: I know I was too much for you. You came to the right side } } G_BotDebug(self, BOT_VERB_DETAIL, BOT_DEBUG_COMMON, "Enemy: %p\n",self->bot->Enemy); if(self->bot->Enemy){ if(self->bot->Enemy->health <= 0) { self->bot->Enemy = NULL; self->client->pers.cmd.buttons = 0; BotResetState( self, ATTACK ); BotClearQueue( self ); } } else { BotResetState( self, ATTACK ); BotClearQueue( self ); } ///////////////////////// LEVEL 2 ///////////////////////// if(BotKeepThinking( self , THINK_LEVEL_2)) { if(self->bot->Enemy) { if(botGetDistanceBetweenPlayer(self, self->bot->Enemy) > g_human_range.integer) { self->bot->Enemy = NULL; BotResetState( self, ATTACK ); } } } ///////////////////////// LEVEL 3 ///////////////////////// if(BotKeepThinking( self , THINK_LEVEL_3)) { } ///////////////////////// LEVEL MAX ///////////////////////// if(BotKeepThinking( self , THINK_LEVEL_MAX)) { } break; case FOLLOW: //In case your friend became your enemy, don't follow him/her! if(OnSameTeam( self , self->bot->Enemy )) { self->bot->Friend = NULL; //Say: traitor! I will burn you house down and eat all your plants! } //If your friend is blocked, forget it (maybe he will follow you) if(self->bot->Friend->bot) { if(self->bot->Friend->bot->path.state == BLOCKED) { self->bot->Friend = NULL; } } if(self->bot->Friend) { if(self->bot->Friend->health <= 0) { //TODO: report to CHAT function self->bot->Friend = NULL; BotResetState( self, FOLLOW ); } } else { BotResetState( self, FOLLOW ); } ///////////////////////// LEVEL 2 ///////////////////////// if(BotKeepThinking( self , THINK_LEVEL_2)) { if(self->bot->Friend) { //TODO: change fixed value to a variable if(botGetDistanceBetweenPlayer(self, self->bot->Enemy) > 300) { self->bot->Friend = NULL; BotResetState( self, FOLLOW ); } } } break; case HEAL: //wait until you are 100% if(botGetHealthPct( self ) == 100) { if(self->bot->Struct) { self->bot->Struct = NULL; } BotResetState( self, HEAL ); } break; case REPAIR: if(self->bot->Struct) { if(self->bot->Struct->health == BG_Buildable( self->bot->Struct->s.modelindex )->health) { self->bot->Struct = NULL; BotResetState( self, REPAIR ); } } else { BotResetState( self, REPAIR ); } break; default: break; } G_BotDebug(self, BOT_VERB_DETAIL, BOT_DEBUG_COMMON + BOT_DEBUG_THINK,"COMMON THINK: LVL1:%d, LVL2:%d, LVL3:%d, MAX:%d \n", self->bot->think.state[ THINK_LEVEL_1 ], self->bot->think.state[ THINK_LEVEL_2 ], self->bot->think.state[ THINK_LEVEL_3 ], self->bot->think.state[ THINK_LEVEL_MAX ] ); }