/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -------------------------------------------------------------- The ACE Bot is a product of Steve Yeager, and is available from the ACE Bot homepage, at http://www.axionfx.com/ace. This program is a modification of the ACE Bot, and is therefore in NO WAY supported by Steve Yeager. */ #include "../g_local.h" #include "ai_local.h" //=============================================================== // // BOT SPAWN // //=============================================================== //==================================== // Stuff to generate pseudo-random names AQ2 //==================================== #define NUMNAMES 10 char *names1[NUMNAMES] = { "Bad", "d3th", "L33t", "Fasst", "mAx", "l3thal", "kw1k", "Hard", "Angel", "Red"}; char *names2[NUMNAMES] = { "Moon", "eevil", "wakko", "d00d", "killa", "dog", "sodja", "joos", "frags", "akimbo" }; char *names3[NUMNAMES] = { "An", "Bal", "Calen", "Cor", "Fan", "Gil", "Hal", "Lin", "Mal", "Per"}; char *names4[NUMNAMES] = { "adan", "rog", "born", "dor", "fing", "galad", "iel", "loss", "orch", "riel" }; qboolean nameused[NUMNAMES][NUMNAMES]; //==================================== // New random bot naming routine //==================================== void SetBotNames( char *bot_name ) { int part1,part2; part1 = part2 = 0; do { part1 = rand()% NUMNAMES; part2 = rand()% NUMNAMES; }while( nameused[part1][part2]); // Mark that name as used nameused[part1][part2] = true; // Now put the name together if( random() < 0.5 ) { strcpy( bot_name, names1[part1]); strcat( bot_name, names2[part2]); } else { strcpy( bot_name, names3[part1]); strcat( bot_name, names4[part2]); } } /////////////////////////////////////////////////////////////////////// // Respawn the bot /////////////////////////////////////////////////////////////////////// void BOT_Respawn (edict_t *self) { CopyToBodyQue (self); PutClientInServer (self); // add a teleportation effect self->s.event = EV_PLAYER_TELEPORT; // hold in place briefly self->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT; self->client->ps.pmove.pm_time = 14; self->client->respawn_time = level.time; AI_ResetWeights(self); AI_ResetNavigation(self); } /////////////////////////////////////////////////////////////////////// // Find a free client spot - //jabot092(2) /////////////////////////////////////////////////////////////////////// edict_t *BOT_FindFreeClient (void) { edict_t *bot; edict_t *ent; int i; int max_count=0; bot = NULL; for( i = 0, ent = g_edicts + 1; i < game.maxclients; i++, ent++ ) { if( !ent->inuse && bot == NULL ) bot = ent; //count bots for bot names if( ent->count > max_count ) max_count = ent->count; } if (bot == NULL || (max_count + 2) >= game.maxclients ) //always leave room for 1 player return NULL; bot->count = max_count + 1; // Will become bot name... return bot; } /////////////////////////////////////////////////////////////////////// // Set the name of the bot and update the userinfo /////////////////////////////////////////////////////////////////////// void BOT_SetName(edict_t *bot, char *name, char *skin, char *team) { float rnd; char userinfo[MAX_INFO_STRING]; char bot_skin[MAX_INFO_STRING]; char bot_name[MAX_INFO_STRING]; // Set the name for the bot. // name if(strlen(name) == 0) SetBotNames(bot_name); else strcpy(bot_name,name); // skin if(strlen(skin) == 0) { // randomly choose skin rnd = random(); if(rnd < 0.05) sprintf(bot_skin,"female/athena"); else if(rnd < 0.1) sprintf(bot_skin,"female/brianna"); else if(rnd < 0.15) sprintf(bot_skin,"female/cobalt"); else if(rnd < 0.2) sprintf(bot_skin,"female/ensign"); else if(rnd < 0.25) sprintf(bot_skin,"female/jezebel"); else if(rnd < 0.3) sprintf(bot_skin,"female/jungle"); else if(rnd < 0.35) sprintf(bot_skin,"female/lotus"); else if(rnd < 0.4) sprintf(bot_skin,"female/stiletto"); else if(rnd < 0.45) sprintf(bot_skin,"female/venus"); else if(rnd < 0.5) sprintf(bot_skin,"female/voodoo"); else if(rnd < 0.55) sprintf(bot_skin,"male/cipher"); else if(rnd < 0.6) sprintf(bot_skin,"male/flak"); else if(rnd < 0.65) sprintf(bot_skin,"male/grunt"); else if(rnd < 0.7) sprintf(bot_skin,"male/howitzer"); else if(rnd < 0.75) sprintf(bot_skin,"male/major"); else if(rnd < 0.8) sprintf(bot_skin,"male/nightops"); else if(rnd < 0.85) sprintf(bot_skin,"male/pointman"); else if(rnd < 0.9) sprintf(bot_skin,"male/psycho"); else if(rnd < 0.95) sprintf(bot_skin,"male/razor"); else sprintf(bot_skin,"male/sniper"); } else strcpy(bot_skin,skin); // initialise userinfo memset (userinfo, 0, sizeof(userinfo)); // add bot's name/skin/hand to userinfo Info_SetValueForKey (userinfo, "name", bot_name); Info_SetValueForKey (userinfo, "skin", bot_skin); Info_SetValueForKey (userinfo, "hand", "2"); // bot is center handed for now! ClientConnect (bot, userinfo); // ACESP_SaveBots(); // make sure to save the bots } //========================================== // BOT_NextCTFTeam // Get the emptier CTF team //========================================== int BOT_NextCTFTeam() { int i; int onteam1 = 0; int onteam2 = 0; edict_t *self; // Only use in CTF games if (!ctf->value) return 0; for (i = 0; i < game.maxclients + 1; i++) { self = g_edicts +i + 1; if (self->inuse && self->client) { if (self->client->resp.ctf_team == CTF_TEAM1) onteam1++; else if (self->client->resp.ctf_team == CTF_TEAM2) onteam2++; } } if (onteam1 > onteam2) return (2); else if (onteam2 >= onteam1) return (1); return (1); } //========================================== // BOT_JoinCTFTeam // Assign a team for the bot //========================================== qboolean BOT_JoinCTFTeam (edict_t *ent, char *team_name) { char *s; int team; // edict_t *event; if (ent->client->resp.ctf_team != CTF_NOTEAM) return false; // find what ctf team if ((team_name !=NULL) && (strcmp(team_name, "blue") == 0)) team = CTF_TEAM2; else if ((team_name !=NULL) && (strcmp(team_name, "red") == 0)) team = CTF_TEAM1; else team = BOT_NextCTFTeam(); if (team == CTF_NOTEAM) return false; //join ctf team ent->svflags &= ~SVF_NOCLIENT; ent->client->resp.ctf_state = 1;//0? ent->client->resp.ctf_team = team; s = Info_ValueForKey (ent->client->pers.userinfo, "skin"); CTFAssignSkin(ent, s); PutClientInServer(ent); // hold in place briefly ent->client->ps.pmove.pm_flags = PMF_TIME_TELEPORT; ent->client->ps.pmove.pm_time = 14; Com_Printf ( "%s joined the %s team.\n", ent->client->pers.netname, CTFTeamName(ent->client->resp.ctf_team)); return true; } //========================================== // BOT_DMClass_JoinGame // put the bot into the game. //========================================== void BOT_DMClass_JoinGame (edict_t *ent, char *team_name) { if ( !BOT_JoinCTFTeam(ent, team_name) ) Com_Printf ( "%s joined the game.\n", ent->client->pers.netname); ent->think = AI_Think; ent->nextthink = level.time + FRAMETIME; //join game ent->movetype = MOVETYPE_WALK; ent->solid = SOLID_BBOX; ent->svflags &= ~SVF_NOCLIENT; ent->client->ps.gunindex = 0; if (!KillBox (ent)) { // could't spawn in? } gi.linkentity (ent); } //========================================== // BOT_StartAsSpectator //========================================== void BOT_StartAsSpectator (edict_t *ent) { // start as 'observer' ent->movetype = MOVETYPE_NOCLIP; ent->solid = SOLID_NOT; ent->svflags |= SVF_NOCLIENT; ent->client->resp.ctf_team = CTF_NOTEAM; ent->client->ps.gunindex = 0; gi.linkentity (ent); } //========================================== // BOT_JoinGame // 3 for teams and such //========================================== void BOT_JoinBlue (edict_t *ent) { BOT_DMClass_JoinGame( ent, "blue" ); } void BOT_JoinRed (edict_t *ent) { BOT_DMClass_JoinGame( ent, "red" ); } void BOT_JoinGame (edict_t *ent) { BOT_DMClass_JoinGame( ent, NULL ); } /////////////////////////////////////////////////////////////////////// // Spawn the bot /////////////////////////////////////////////////////////////////////// void BOT_SpawnBot (char *team, char *name, char *skin, char *userinfo) { edict_t *bot; if( !nav.loaded ) { Com_Printf("Can't spawn bots without a valid navigation file\n"); return; } bot = BOT_FindFreeClient (); if (!bot) { safe_bprintf (PRINT_MEDIUM, "Server is full, increase Maxclients.\n"); return; } //init the bot bot->inuse = true; bot->yaw_speed = 100; // To allow bots to respawn if(userinfo == NULL) BOT_SetName(bot, name, skin, team); else ClientConnect (bot, userinfo); G_InitEdict (bot); G_SpawnAI(bot); //jabot092(2) bot->ai->is_bot = true; InitClientResp (bot->client); PutClientInServer(bot); BOT_StartAsSpectator (bot); //skill bot->ai->pers.skillLevel = (int)(random()*MAX_BOT_SKILL); if (bot->ai->pers.skillLevel > MAX_BOT_SKILL) //fix if off-limits bot->ai->pers.skillLevel = MAX_BOT_SKILL; else if (bot->ai->pers.skillLevel < 0) bot->ai->pers.skillLevel = 0; BOT_DMclass_InitPersistant(bot); AI_ResetWeights(bot); AI_ResetNavigation(bot); bot->think = BOT_JoinGame; bot->nextthink = level.time + (int)(random()*6.0); if( ctf->value && team != NULL ) { if( !Q_stricmp( team, "blue" ) ) bot->think = BOT_JoinBlue; else if( !Q_stricmp( team, "red" ) ) bot->think = BOT_JoinRed; } AI_EnemyAdded (bot); // let the ai know we added another } /////////////////////////////////////////////////////////////////////// // Remove a bot by name or all bots /////////////////////////////////////////////////////////////////////// void BOT_RemoveBot(char *name) { int i; qboolean freed=false; edict_t *bot; for(i=0;ivalue;i++) { bot = g_edicts + i + 1; if( !bot->inuse || !bot->ai ) //jabot092(2) continue; if( bot->ai->is_bot && (!strcmp(bot->client->pers.netname,name) || !strcmp(name,"all"))) { bot->health = 0; player_die (bot, bot, bot, 100000, vec3_origin); // don't even bother waiting for death frames bot->deadflag = DEAD_DEAD; bot->inuse = false; freed = true; AI_EnemyRemoved (bot); G_FreeAI( bot ); //jabot092(2) //safe_bprintf (PRINT_MEDIUM, "%s removed\n", bot->client->pers.netname); } } // if(!freed && !Q_stricmp( name, "all") ) // safe_bprintf (PRINT_MEDIUM, "%s not found\n", name); }