/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; gentity_t *ent; bot_entitystate_t state; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; G_CheckBotSpawn(); trap_Cvar_Update(&bot_rocketjump); trap_Cvar_Update(&bot_grapple); trap_Cvar_Update(&bot_fastchat); trap_Cvar_Update(&bot_nochat); trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); trap_Cvar_Update(&bot_droppedweight); trap_Cvar_Update(&bot_offhandgrapple); trap_Cvar_Update(&bot_shownodechanges); trap_Cvar_Update(&bot_showteamgoals); trap_Cvar_Update(&bot_reloadcharacters); BotUpdateInfoConfigStrings(); if (bot_pause.integer) { // execute bot user commands every frame for( i = 0; i < level.maxplayers; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].player->pers.connected != CON_CONNECTED ) { continue; } botstates[i]->lastucmd.forwardmove = 0; botstates[i]->lastucmd.rightmove = 0; botstates[i]->lastucmd.upmove = 0; botstates[i]->lastucmd.buttons = 0; botstates[i]->lastucmd.serverTime = time; trap_BotUserCommand(botstates[i]->playernum, &botstates[i]->lastucmd); } return qtrue; } if (bot_memorydump.integer) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_SetValue("bot_memorydump", 0); } if (bot_saveroutingcache.integer) { trap_BotLibVarSet("saveroutingcache", "1"); trap_Cvar_SetValue("bot_saveroutingcache", 0); } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time if (bot_thinktime.integer > 200) { trap_Cvar_SetValue("bot_thinktime", 200); } //if the bot think time changed we should reschedule the bots if (bot_thinktime.integer != lastbotthink_time) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time; else thinktime = bot_thinktime.integer; // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame((float) time / 1000); if (!trap_AAS_Initialized()) return qfalse; //update entities in the botlib for (i = 0; i < MAX_GENTITIES; i++) { ent = &g_entities[i]; ent->botvalid = qfalse; if (!ent->inuse) { trap_BotLibUpdateEntity(i, NULL); continue; } if (!ent->r.linked) { trap_BotLibUpdateEntity(i, NULL); continue; } if (ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update missiles if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update event only entities if (ent->s.eType > ET_EVENTS) { trap_BotLibUpdateEntity(i, NULL); continue; } #ifdef MISSIONPACK // never link prox mine triggers if (ent->s.contents == CONTENTS_TRIGGER) { if (ent->touch == ProximityMine_Trigger) { trap_BotLibUpdateEntity(i, NULL); continue; } } #endif // ent->botvalid = qtrue; ent->update_time = trap_AAS_Time() - ent->ltime; ent->ltime = trap_AAS_Time(); // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(ent->r.currentOrigin, state.origin); if (i < MAX_CLIENTS) { VectorCopy(ent->s.apos.trBase, state.angles); } else { VectorCopy(ent->r.currentAngles, state.angles); } VectorCopy( ent->r.absmin, state.absmins ); VectorCopy( ent->r.absmax, state.absmaxs ); state.type = ent->s.eType; state.flags = ent->s.eFlags; // if (ent->s.collisionType == CT_SUBMODEL) { state.solid = SOLID_BSP; //if the angles of the model changed if ( !VectorCompare( state.angles, ent->lastAngles ) ) { VectorCopy(state.angles, ent->lastAngles); state.relink = qtrue; } } else { state.solid = SOLID_BBOX; VectorCopy(state.angles, ent->lastAngles); } //previous frame visorigin VectorCopy( ent->visorigin, ent->lastvisorigin ); //if the origin changed if ( !VectorCompare( state.origin, ent->visorigin ) ) { VectorCopy( state.origin, ent->visorigin ); state.relink = qtrue; } //if the bounding box size changed if (!VectorCompare(ent->s.mins, ent->lastMins) || !VectorCompare(ent->s.maxs, ent->lastMaxs)) { VectorCopy( ent->s.mins, ent->lastMins ); VectorCopy( ent->s.maxs, ent->lastMaxs ); state.relink = qtrue; } // trap_BotLibUpdateEntity(i, &state); } BotAIRegularUpdate(); } floattime = trap_AAS_Time(); // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (!trap_AAS_Initialized()) return qfalse; if (g_entities[i].player->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].player->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->playernum, &botstates[i]->lastucmd); } return qtrue; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame( int time ) { int i; gentity_t *ent; bot_entitystate_t state; //entityState_t entitystate; //vec3_t mins = {-15, -15, -24}, maxs = {15, 15, 32}; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; if ( g_gametype.integer != GT_SINGLE_PLAYER ) { G_CheckBotSpawn(); } trap_Cvar_Update( &bot_rocketjump ); trap_Cvar_Update( &bot_grapple ); trap_Cvar_Update( &bot_fastchat ); trap_Cvar_Update( &bot_nochat ); trap_Cvar_Update( &bot_testrchat ); trap_Cvar_Update( &bot_thinktime ); // Ridah, set the default AAS world trap_AAS_SetCurrentWorld( 0 ); trap_Cvar_Update( &memorydump ); if ( memorydump.integer ) { trap_BotLibVarSet( "memorydump", "1" ); trap_Cvar_Set( "memorydump", "0" ); } //if the bot think time changed we should reschedule the bots if ( bot_thinktime.integer != lastbotthink_time ) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if ( elapsed_time > bot_thinktime.integer ) { thinktime = elapsed_time; } else { thinktime = bot_thinktime.integer;} // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame( (float) time / 1000 ); // Ridah, only check the default world trap_AAS_SetCurrentWorld( 0 ); if ( !trap_AAS_Initialized() ) { return BLERR_NOERROR; } //update entities in the botlib for ( i = 0; i < MAX_GENTITIES; i++ ) { // Ridah, in single player, we only need client entity information if ( g_gametype.integer == GT_SINGLE_PLAYER && i > level.maxclients ) { break; } ent = &g_entities[i]; if ( !ent->inuse ) { continue; } if ( !ent->r.linked ) { continue; } if ( ent->r.svFlags & SVF_NOCLIENT ) { continue; } // memset( &state, 0, sizeof( bot_entitystate_t ) ); // VectorCopy( ent->r.currentOrigin, state.origin ); VectorCopy( ent->r.currentAngles, state.angles ); VectorCopy( ent->s.origin2, state.old_origin ); VectorCopy( ent->r.mins, state.mins ); VectorCopy( ent->r.maxs, state.maxs ); state.type = ent->s.eType; state.flags = ent->s.eFlags; if ( ent->r.bmodel ) { state.solid = SOLID_BSP; } else { state.solid = SOLID_BBOX;} state.groundent = ent->s.groundEntityNum; state.modelindex = ent->s.modelindex; state.modelindex2 = ent->s.modelindex2; state.frame = ent->s.frame; //state.event = ent->s.event; //state.eventParm = ent->s.eventParm; state.powerups = ent->s.powerups; state.legsAnim = ent->s.legsAnim; state.torsoAnim = ent->s.torsoAnim; // state.weapAnim = ent->s.weapAnim; //----(SA) //----(SA) didn't want to comment in as I wasn't sure of any implications of changing the aas_entityinfo_t and bot_entitystate_t structures. state.weapon = ent->s.weapon; /* if (!BotAI_GetEntityState(i, &entitystate)) continue; // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(entitystate.pos.trBase, state.origin); VectorCopy(entitystate.angles, state.angles); VectorCopy(ent->s.origin2, state.old_origin); //VectorCopy(ent->r.mins, state.mins); //VectorCopy(ent->r.maxs, state.maxs); state.type = entitystate.eType; state.flags = entitystate.eFlags; if (ent->r.bmodel) state.solid = SOLID_BSP; else state.solid = SOLID_BBOX; state.modelindex = entitystate.modelindex; state.modelindex2 = entitystate.modelindex2; state.frame = entitystate.frame; state.event = entitystate.event; state.eventParm = entitystate.eventParm; state.powerups = entitystate.powerups; state.legsAnim = entitystate.legsAnim; state.torsoAnim = entitystate.torsoAnim; state.weapon = entitystate.weapon; */ // trap_BotLibUpdateEntity( i, &state ); } BotAIRegularUpdate(); } // Ridah, in single player, don't need bot's thinking if ( g_gametype.integer == GT_SINGLE_PLAYER ) { return BLERR_NOERROR; } // execute scheduled bot AI for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !botstates[i] || !botstates[i]->inuse ) { continue; } // Ridah if ( g_entities[i].r.svFlags & SVF_CASTAI ) { continue; } // done. // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if ( !trap_AAS_Initialized() ) { return BLERR_NOERROR; } if ( g_entities[i].client->pers.connected == CON_CONNECTED ) { BotAI( i, (float) thinktime / 1000 ); } } } // execute bot user commands every frame for ( i = 0; i < MAX_CLIENTS; i++ ) { if ( !botstates[i] || !botstates[i]->inuse ) { continue; } // Ridah if ( g_entities[i].r.svFlags & SVF_CASTAI ) { continue; } // done. if ( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput( botstates[i], time ); trap_BotUserCommand( botstates[i]->client, &botstates[i]->lastucmd ); } return BLERR_NOERROR; }
/* ============== BotAISetupPlayer ============== */ int BotAISetupPlayer(int playernum, struct bot_settings_s *settings, qboolean restart) { char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH]; bot_state_t *bs; int errnum; if (!botstates[playernum]) botstates[playernum] = trap_Alloc(sizeof(bot_state_t), NULL); bs = botstates[playernum]; if (!bs) { return qfalse; } if (bs && bs->inuse) { BotAI_Print(PRT_FATAL, "BotAISetupPlayer: player %d already setup\n", playernum); return qfalse; } if (!trap_AAS_Initialized()) { BotAI_Print(PRT_FATAL, "AAS not initialized\n"); return qfalse; } //load the bot character bs->character = BotLoadCharacter(settings->characterfile, settings->skill); if (!bs->character) { BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile); return qfalse; } //copy the settings memcpy(&bs->settings, settings, sizeof(bot_settings_t)); //allocate a goal state bs->gs = BotAllocGoalState(playernum); //load the item weights Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH); errnum = BotLoadItemWeights(bs->gs, filename); if (errnum != BLERR_NOERROR) { BotFreeGoalState(bs->gs); BotAI_Print(PRT_FATAL, "BotLoadItemWeights failed\n"); return qfalse; } //allocate a weapon state bs->ws = BotAllocWeaponState(playernum); //load the weapon weights Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH); errnum = BotLoadWeaponWeights(bs->ws, filename); if (errnum != BLERR_NOERROR) { BotFreeGoalState(bs->gs); BotFreeWeaponState(bs->ws); BotAI_Print(PRT_FATAL, "BotLoadWeaponWeights failed\n"); return qfalse; } //allocate a chat state bs->cs = BotAllocChatState(); //load the chat file Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH); Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH); errnum = BotLoadChatFile(bs->cs, filename, name); if (errnum != BLERR_NOERROR) { BotFreeChatState(bs->cs); BotFreeGoalState(bs->gs); BotFreeWeaponState(bs->ws); BotAI_Print(PRT_FATAL, "BotLoadChatFile failed\n"); return qfalse; } //get the gender characteristic Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH); //set the chat gender if (*gender == 'f' || *gender == 'F') BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); else if (*gender == 'm' || *gender == 'M') BotSetChatGender(bs->cs, CHAT_GENDERMALE); else BotSetChatGender(bs->cs, CHAT_GENDERLESS); bs->inuse = qtrue; bs->playernum = playernum; bs->entitynum = playernum; bs->setupcount = 4; bs->entergame_time = FloatTime(); bs->ms = BotAllocMoveState(playernum); bs->walker = Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1); bs->revenge_enemy = -1; numbots++; trap_Cvar_Update( &bot_testichat ); if (bot_testichat.integer) { BotChatTest(bs); } //NOTE: reschedule the bot thinking BotScheduleBotThink(); //if interbreeding start with a mutation if (bot_interbreed) { BotMutateGoalFuzzyLogic(bs->gs, 1); } // if we kept the bot state if (restart) { BotReadSessionData(bs); } //bot has been setup succesfully return qtrue; }
/* ============== BotAISetupClient ============== */ int BotAISetupClient( int client, struct bot_settings_s *settings ) { char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH]; bot_state_t *bs; int errnum; if ( !botstates[client] ) { botstates[client] = G_Alloc( sizeof( bot_state_t ) ); } bs = botstates[client]; if ( bs && bs->inuse ) { BotAI_Print( PRT_FATAL, "client %d already setup\n", client ); return qfalse; } if ( !trap_AAS_Initialized() ) { BotAI_Print( PRT_FATAL, "AAS not initialized\n" ); return qfalse; } //load the bot character bs->character = trap_BotLoadCharacter( settings->characterfile, settings->skill ); if ( !bs->character ) { BotAI_Print( PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile ); return qfalse; } //copy the settings memcpy( &bs->settings, settings, sizeof( bot_settings_t ) ); //allocate a goal state bs->gs = trap_BotAllocGoalState( client ); //load the item weights trap_Characteristic_String( bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH ); errnum = trap_BotLoadItemWeights( bs->gs, filename ); if ( errnum != BLERR_NOERROR ) { trap_BotFreeGoalState( bs->gs ); return qfalse; } //allocate a weapon state bs->ws = trap_BotAllocWeaponState(); //load the weapon weights trap_Characteristic_String( bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH ); errnum = trap_BotLoadWeaponWeights( bs->ws, filename ); if ( errnum != BLERR_NOERROR ) { trap_BotFreeGoalState( bs->gs ); trap_BotFreeWeaponState( bs->ws ); return qfalse; } //allocate a chat state bs->cs = trap_BotAllocChatState(); //load the chat file trap_Characteristic_String( bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH ); trap_Characteristic_String( bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH ); errnum = trap_BotLoadChatFile( bs->cs, filename, name ); if ( errnum != BLERR_NOERROR ) { trap_BotFreeChatState( bs->cs ); trap_BotFreeGoalState( bs->gs ); trap_BotFreeWeaponState( bs->ws ); return qfalse; } //get the gender characteristic trap_Characteristic_String( bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH ); //set the chat gender if ( *gender == 'f' || *gender == 'F' ) { trap_BotSetChatGender( bs->cs, CHAT_GENDERFEMALE ); } else if ( *gender == 'm' || *gender == 'M' ) { trap_BotSetChatGender( bs->cs, CHAT_GENDERMALE ); } else { trap_BotSetChatGender( bs->cs, CHAT_GENDERLESS );} bs->inuse = qtrue; bs->client = client; bs->entitynum = client; bs->setupcount = 4; bs->entergame_time = trap_AAS_Time(); bs->ms = trap_BotAllocMoveState(); bs->walker = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_WALKER, 0, 1 ); numbots++; if ( trap_Cvar_VariableIntegerValue( "bot_testichat" ) ) { trap_BotLibVarSet( "bot_testichat", "1" ); BotChatTest( bs ); } //NOTE: reschedule the bot thinking BotScheduleBotThink(); // return qtrue; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; gentity_t *ent; bot_entitystate_t state; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; G_CheckBotSpawn(); trap_Cvar_Update(&bot_rocketjump); trap_Cvar_Update(&bot_grapple); trap_Cvar_Update(&bot_fastchat); trap_Cvar_Update(&bot_nochat); trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); if (bot_report.integer) { // BotTeamplayReport(); // trap_Cvar_Set("bot_report", "0"); BotUpdateInfoConfigStrings(); } if (bot_pause.integer) { // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } botstates[i]->lastucmd.forwardmove = 0; botstates[i]->lastucmd.rightmove = 0; botstates[i]->lastucmd.upmove = 0; botstates[i]->lastucmd.buttons = 0; botstates[i]->lastucmd.serverTime = time; trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; } if (bot_memorydump.integer) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_Set("bot_memorydump", "0"); } if (bot_saveroutingcache.integer) { trap_BotLibVarSet("saveroutingcache", "1"); trap_Cvar_Set("bot_saveroutingcache", "0"); } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time if (bot_thinktime.integer > 200) { trap_Cvar_Set("bot_thinktime", "200"); } //if the bot think time changed we should reschedule the bots if (bot_thinktime.integer != lastbotthink_time) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time; else thinktime = bot_thinktime.integer; // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame((float) time / 1000); if (!trap_AAS_Initialized()) return qfalse; //update entities in the botlib for (i = 0; i < MAX_GENTITIES; i++) { ent = &g_entities[i]; if (!ent->inuse) { trap_BotLibUpdateEntity(i, NULL); continue; } if (!ent->r.linked) { trap_BotLibUpdateEntity(i, NULL); continue; } if (ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update missiles if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update event only entities if (ent->s.eType > ET_EVENTS) { trap_BotLibUpdateEntity(i, NULL); continue; } #if 1 //def MPACK // never link prox mine triggers if (ent->r.contents == CONTENTS_TRIGGER) { if (ent->touch == ProximityMine_Trigger) { trap_BotLibUpdateEntity(i, NULL); continue; } } #endif // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(ent->r.currentOrigin, state.origin); if (i < MAX_CLIENTS) { VectorCopy(ent->s.apos.trBase, state.angles); } else { VectorCopy(ent->r.currentAngles, state.angles); } VectorCopy(ent->s.origin2, state.old_origin); VectorCopy(ent->r.mins, state.mins); VectorCopy(ent->r.maxs, state.maxs); state.type = ent->s.eType; state.flags = ent->s.eFlags; if (ent->r.bmodel) state.solid = SOLID_BSP; else state.solid = SOLID_BBOX; state.groundent = ent->s.groundEntityNum; state.modelindex = ent->s.modelindex; state.modelindex2 = ent->s.modelindex2; state.frame = ent->s.frame; state.event = ent->s.event; state.eventParm = ent->s.eventParm; state.powerups = ent->s.powerups; state.legsAnim = ent->s.legsAnim; state.torsoAnim = ent->s.torsoAnim; state.weapon = ent->s.weapon; // trap_BotLibUpdateEntity(i, &state); } BotAIRegularUpdate(); } floattime = trap_AAS_Time(); // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (!trap_AAS_Initialized()) return qfalse; if (g_entities[i].client->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; }
/* * BotAISetupClient */ int BotAISetupClient(int client, struct bot_settings_s *settings, qbool restart) { char filename[MAX_PATH], name[MAX_PATH], gender[MAX_PATH]; bot_state_t *bs; int errnum; if(!botstates[client]) botstates[client] = G_Alloc(sizeof(bot_state_t)); bs = botstates[client]; if(bs && bs->inuse){ BotAI_Print(PRT_FATAL, "BotAISetupClient: client %d already setup\n", client); return qfalse; } if(!trap_AAS_Initialized()){ BotAI_Print(PRT_FATAL, "AAS not initialized\n"); return qfalse; } /* load the bot character */ bs->character = trap_BotLoadCharacter(settings->characterfile, settings->skill); if(!bs->character){ BotAI_Print(PRT_FATAL, "couldn't load skill %f from %s\n", settings->skill, settings->characterfile); return qfalse; } /* copy the settings */ memcpy(&bs->settings, settings, sizeof(bot_settings_t)); /* allocate a goal state */ bs->gs = trap_BotAllocGoalState(client); /* load the item weights */ trap_Characteristic_String(bs->character, CHARACTERISTIC_ITEMWEIGHTS, filename, MAX_PATH); errnum = trap_BotLoadItemWeights(bs->gs, filename); if(errnum != BLERR_NOERROR){ trap_BotFreeGoalState(bs->gs); return qfalse; } /* allocate a weapon state */ bs->ws = trap_BotAllocWeaponState(); /* load the weapon weights */ trap_Characteristic_String(bs->character, CHARACTERISTIC_WEAPONWEIGHTS, filename, MAX_PATH); errnum = trap_BotLoadWeaponWeights(bs->ws, filename); if(errnum != BLERR_NOERROR){ trap_BotFreeGoalState(bs->gs); trap_BotFreeWeaponState(bs->ws); return qfalse; } /* allocate a chat state */ bs->cs = trap_BotAllocChatState(); /* load the chat file */ trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_FILE, filename, MAX_PATH); trap_Characteristic_String(bs->character, CHARACTERISTIC_CHAT_NAME, name, MAX_PATH); errnum = trap_BotLoadChatFile(bs->cs, filename, name); if(errnum != BLERR_NOERROR){ trap_BotFreeChatState(bs->cs); trap_BotFreeGoalState(bs->gs); trap_BotFreeWeaponState(bs->ws); return qfalse; } /* get the gender characteristic */ trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, MAX_PATH); /* set the chat gender */ if(*gender == 'f' || *gender == 'F') trap_BotSetChatGender( bs->cs, CHAT_GENDERFEMALE); else if(*gender == 'm' || *gender == 'M') trap_BotSetChatGender( bs->cs, CHAT_GENDERMALE); else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS); bs->inuse = qtrue; bs->client = client; bs->entitynum = client; bs->setupcount = 4; bs->entergame_time = FloatTime(); bs->ms = trap_BotAllocMoveState(); bs->walker = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WALKER, 0, 1); numbots++; if(trap_cvargeti("bot_testichat")){ trap_BotLibVarSet("bot_testichat", "1"); BotChatTest(bs); } /* NOTE: reschedule the bot thinking */ BotScheduleBotThink(); /* if interbreeding start with a mutation */ if(bot_interbreed) trap_BotMutateGoalFuzzyLogic(bs->gs, 1); /* if we kept the bot client */ if(restart) BotReadSessionData(bs); /* bot has been setup succesfully */ return qtrue; }
/* ============== BotAISetupClient ============== */ int BotAISetupClient(int client, struct bot_settings_s *settings, qboolean restart) { bot_state_t *bs; if (!botstates[client]) botstates[client] = (bot_state_t *) malloc(sizeof(bot_state_t)); //G_Alloc(sizeof(bot_state_t)); //rww - G_Alloc bad! malloc good. memset(botstates[client], 0, sizeof(bot_state_t)); bs = botstates[client]; if (bs && bs->inuse) { return qfalse; } memcpy(&bs->settings, settings, sizeof(bot_settings_t)); bs->client = client; //need to know the client number before doing personality stuff //initialize weapon weight defaults.. bs->botWeaponWeights[WP_NONE] = 0; bs->botWeaponWeights[WP_STUN_BATON] = 1; bs->botWeaponWeights[WP_SABER] = 0; bs->botWeaponWeights[WP_BRYAR_PISTOL] = 11; bs->botWeaponWeights[WP_BLASTER] = 12; bs->botWeaponWeights[WP_DISRUPTOR] = 13; bs->botWeaponWeights[WP_BOWCASTER] = 14; bs->botWeaponWeights[WP_REPEATER] = 15; bs->botWeaponWeights[WP_DEMP2] = 16; bs->botWeaponWeights[WP_FLECHETTE] = 17; bs->botWeaponWeights[WP_ROCKET_LAUNCHER] = 18; bs->botWeaponWeights[WP_THERMAL] = 14; bs->botWeaponWeights[WP_TRIP_MINE] = 0; bs->botWeaponWeights[WP_DET_PACK] = 0; bs->botWeaponWeights[WP_MELEE] = 1; BotUtilizePersonality(bs); if (g_gametype.integer == GT_DUEL || g_gametype.integer == GT_POWERDUEL) { bs->botWeaponWeights[WP_SABER] = 13; } #ifndef __MMO__ //allocate a goal state bs->gs = trap_BotAllocGoalState(client); //allocate a weapon state bs->ws = trap_BotAllocWeaponState(); #endif //__MMO__ bs->inuse = qtrue; bs->entitynum = client; bs->setupcount = 4; bs->entergame_time = FloatTime(); #ifndef __MMO__ bs->ms = trap_BotAllocMoveState(); #endif //__MMO__ numbots++; //NOTE: reschedule the bot thinking BotScheduleBotThink(); if (PlayersInGame()) { //don't talk to yourself BotDoChat(bs, "GeneralGreetings", 0); } return qtrue; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; if (gUpdateVars < level.time) { trap_Cvar_Update(&bot_pvstype); trap_Cvar_Update(&bot_camp); trap_Cvar_Update(&bot_attachments); trap_Cvar_Update(&bot_forgimmick); trap_Cvar_Update(&bot_honorableduelacceptance); #ifndef FINAL_BUILD trap_Cvar_Update(&bot_getinthecarrr); #endif gUpdateVars = level.time + 1000; } G_CheckBotSpawn(); //rww - addl bot frame functions if (gBotEdit) { trap_Cvar_Update(&bot_wp_info); BotWaypointRender(); } UpdateEventTracker(); //end rww //cap the bot think time //if the bot think time changed we should reschedule the bots if (BOT_THINK_TIME != lastbotthink_time) { lastbotthink_time = BOT_THINK_TIME; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; if (elapsed_time > BOT_THINK_TIME) thinktime = elapsed_time; else thinktime = BOT_THINK_TIME; // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (g_entities[i].client->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; }