/* ================== BotChat_Kill ================== */ int BotChat_Kill(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1); // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (bs->lastkilledplayer == bs->client) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; if (!BotValidChatPosition(bs)) return qfalse; // if (BotVisibleEnemies(bs)) return qfalse; // EasyClientName(bs->lastkilledplayer, name, 32); // bs->chatto = CHAT_ALL; if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) { BotAI_BotInitialChat(bs, "kill_teammate", name, NULL); bs->chatto = CHAT_TEAM; } else { //don't chat in teamplay if (TeamPlayIsOn()) { #ifdef MISSIONPACK trap_EA_Command(bs->client, "vtaunt"); #endif return qfalse; // don't wait } // if (bs->enemydeathtype == MOD_GAUNTLET) { BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL); } else if (bs->enemydeathtype == MOD_RAILGUN) { BotAI_BotInitialChat(bs, "kill_rail", name, NULL); } else if (bs->enemydeathtype == MOD_TELEFRAG) { BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL); } #ifdef MISSIONPACK else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze")) BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL); #endif //choose between insult and praise else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { BotAI_BotInitialChat(bs, "kill_insult", name, NULL); } else { BotAI_BotInitialChat(bs, "kill_praise", name, NULL); } } bs->lastchat_time = FloatTime(); return qtrue; }
/* ============== BotChangeViewAngles ============== */ void BotChangeViewAngles( bot_state_t *bs, float thinktime ) { float diff, factor, maxchange, anglespeed; int i; if ( bs->ideal_viewangles[PITCH] > 180 ) { bs->ideal_viewangles[PITCH] -= 360; } // if ( bs->enemy >= 0 ) { factor = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01, 1 ); maxchange = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800 ); } else { factor = 0.25; maxchange = 300; } maxchange *= thinktime; for ( i = 0; i < 2; i++ ) { diff = abs( AngleDifference( bs->viewangles[i], bs->ideal_viewangles[i] ) ); anglespeed = diff * factor; if ( anglespeed > maxchange ) { anglespeed = maxchange; } bs->viewangles[i] = BotChangeViewAngle( bs->viewangles[i], bs->ideal_viewangles[i], anglespeed ); //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);` //bs->viewangles[i] = bs->ideal_viewangles[i]; } if ( bs->viewangles[PITCH] > 180 ) { bs->viewangles[PITCH] -= 360; } //elementary action: view trap_EA_View( bs->client, bs->viewangles ); }
/* ================== BotChat_Kill ================== */ int BotChat_Kill( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1 ); //if fast chat is off if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( bs->lastkilledplayer == bs->client ) { return qfalse; } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } if ( !BotValidChatPosition( bs ) ) { return qfalse; } // EasyClientName( bs->lastkilledplayer, name, 32 ); // bs->chatto = CHAT_ALL; if ( TeamPlayIsOn() && BotSameTeam( bs, bs->lastkilledplayer ) ) { BotAI_BotInitialChat( bs, "kill_teammate", name, NULL ); bs->chatto = CHAT_TEAM; } else { //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } // if ( bs->enemydeathtype == MOD_GAUNTLET ) { BotAI_BotInitialChat( bs, "kill_gauntlet", name, NULL ); } else if ( bs->enemydeathtype == MOD_RAILGUN ) { BotAI_BotInitialChat( bs, "kill_rail", name, NULL ); } else if ( bs->enemydeathtype == MOD_TELEFRAG ) { BotAI_BotInitialChat( bs, "kill_telefrag", name, NULL ); } //choose between insult and praise else if ( random() < trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1 ) ) { BotAI_BotInitialChat( bs, "kill_insult", name, NULL ); } else { BotAI_BotInitialChat( bs, "kill_praise", name, NULL ); } } bs->lastchat_time = trap_AAS_Time(); return qtrue; }
/* ============== BotChangeViewAngles ============== */ void BotChangeViewAngles(bot_state_t * bs, float thinktime) { float diff, factor, maxchange, anglespeed, disired_speed; int i; if (bs->ideal_viewangles[PITCH] > 180) bs->ideal_viewangles[PITCH] -= 360; // if (bs->enemy >= 0) { factor = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_FACTOR, 0.01f, 1); maxchange = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_VIEW_MAXCHANGE, 1, 1800); } else { factor = 0.05f; maxchange = 360; } if (maxchange < 240) maxchange = 240; maxchange *= thinktime; for (i = 0; i < 2; i++) { // if (bot_challenge.integer) { //smooth slowdown view model diff = abs(AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i])); anglespeed = diff * factor; if (anglespeed > maxchange) anglespeed = maxchange; bs->viewangles[i] = BotChangeViewAngle(bs->viewangles[i], bs->ideal_viewangles[i], anglespeed); } else { //over reaction view model bs->viewangles[i] = AngleMod(bs->viewangles[i]); bs->ideal_viewangles[i] = AngleMod(bs->ideal_viewangles[i]); diff = AngleDifference(bs->viewangles[i], bs->ideal_viewangles[i]); disired_speed = diff * factor; bs->viewanglespeed[i] += (bs->viewanglespeed[i] - disired_speed); if (bs->viewanglespeed[i] > 180) bs->viewanglespeed[i] = maxchange; if (bs->viewanglespeed[i] < -180) bs->viewanglespeed[i] = -maxchange; anglespeed = bs->viewanglespeed[i]; if (anglespeed > maxchange) anglespeed = maxchange; if (anglespeed < -maxchange) anglespeed = -maxchange; bs->viewangles[i] += anglespeed; bs->viewangles[i] = AngleMod(bs->viewangles[i]); //demping bs->viewanglespeed[i] *= 0.45 * (1 - factor); } //BotAI_Print(PRT_MESSAGE, "ideal_angles %f %f\n", bs->ideal_viewangles[0], bs->ideal_viewangles[1], bs->ideal_viewangles[2]);` //bs->viewangles[i] = bs->ideal_viewangles[i]; } //bs->viewangles[PITCH] = 0; if (bs->viewangles[PITCH] > 180) bs->viewangles[PITCH] -= 360; //elementary action: view trap_EA_View(bs->client, bs->viewangles); }
/* ================== BotChat_StartLevel ================== */ int BotChat_StartLevel(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; //don't chat in teamplay if (TeamPlayIsOn()) { #ifdef MISSIONPACK trap_EA_Command(bs->client, "vtaunt"); #endif return qfalse; } // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; BotAI_BotInitialChat(bs, "level_start", EasyClientName(bs->client, name, 32), // 0 NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_EnterGame ================== */ int BotChat_EnterGame(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; if (!BotValidChatPosition(bs)) return qfalse; BotAI_BotInitialChat(bs, "game_enter", EasyClientName(bs->client, name, 32), // 0 BotRandomOpponentName(bs), // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* =================== BotShouldRocketJump =================== */ qboolean BotShouldRocketJump(bot_state_t *bs) { float rocketjumper; // Don't rocket jump if the server turned it off for bots if (!bot_rocketjump.integer) return qfalse; // The bot must have a rocket launcher with sufficient ammo if (!BotHasWeapon(bs, WP_ROCKET_LAUNCHER, 3)) return qfalse; // Damage related checks don't matter if the bot has a battle suit if (!bs->ps->powerups[PW_BATTLESUIT]) { // Rocket jumping with the Quad is too painful if (bs->ps->powerups[PW_QUAD]) return qfalse; // Don't jump if the bot is too hurt if (EntityHealth(bs->ent) < 100) return qfalse; } // Be willing to rocket jump if the bot likes doing so rocketjumper = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_WEAPONJUMPING, 0, 1); return (rocketjumper >= 0.5); }
/* ================== BotChat_HitNoKill ================== */ int BotChat_HitNoKill(bot_state_t *bs) { char name[32], *weap; float rnd; aas_entityinfo_t entinfo; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1); //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd * 0.5) return qfalse; } if (!BotValidChatPosition(bs)) return qfalse; // if (BotVisibleEnemies(bs)) return qfalse; // BotEntityInfo(bs->enemy, &entinfo); if (EntityIsShooting(&entinfo)) return qfalse; // ClientName(bs->enemy, name, sizeof(name)); weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod); // BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_ExitGame ================== */ int BotChat_ExitGame( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1 ); if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } // BotAI_BotInitialChat( bs, "game_exit", EasyClientName( bs->client, name, 32 ), // 0 BotRandomOpponentName( bs ), // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 NULL ); bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_HitNoDeath ================== */ int BotChat_HitNoDeath( bot_state_t *bs ) { char name[32]; const char* weap; float rnd; int lasthurt_client; aas_entityinfo_t entinfo; lasthurt_client = g_entities[bs->client].client->lasthurt_client; if ( !lasthurt_client ) { return qfalse; } if ( lasthurt_client == bs->client ) { return qfalse; } // if ( lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS ) { return qfalse; } // if ( bot_nochat.integer ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1 ); //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } //if fast chat is off if ( !bot_fastchat.integer ) { if ( random() > rnd * 0.5 ) { return qfalse; } } if ( !BotValidChatPosition( bs ) ) { return qfalse; } //if the enemy is visible if ( BotEntityVisible( bs->client, bs->eye, bs->viewangles, 360, bs->enemy ) ) { return qfalse; } // BotEntityInfo( bs->enemy, &entinfo ); if ( EntityIsShooting( &entinfo ) ) { return qfalse; } // ClientName( lasthurt_client, name, sizeof( name ) ); weap = BotWeaponNameForMeansOfDeath( g_entities[bs->client].client->lasthurt_mod ); // BotAI_BotInitialChat( bs, "hit_nodeath", name, weap, NULL ); bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_StartLevel ================== */ int BotChat_StartLevel( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( BotIsObserver( bs ) ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1 ); if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } BotAI_BotInitialChat( bs, "level_start", EasyClientName( bs->client, name, 32 ), // 0 NULL ); bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_HitTalking ================== */ int BotChat_HitTalking(bot_state_t *bs) { char name[32], *weap; int lasthurt_client; float rnd; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; lasthurt_client = g_entities[bs->client].client->lasthurt_client; if (!lasthurt_client) return qfalse; if (lasthurt_client == bs->client) return qfalse; // if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse; // rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1); //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd * 0.5) return qfalse; } if (!BotValidChatPosition(bs)) return qfalse; // ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name)); weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod); // BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
void BotMatch_WrongWall(bot_state_t* bs, bot_match_t *match){ char netname[MAX_MESSAGE_SIZE]; char buf[MAX_INFO_STRING]; int client; if(gametype != GT_SPRAY) return; // talking about me ? (avoid clientfromname, its ambiguous) trap_BotMatchVariable(match, NETNAME, netname, sizeof(netname)); trap_GetConfigstring(CS_PLAYERS + bs->client, buf, sizeof(buf)); Q_CleanStr( buf ); if (!Q_stricmp(Info_ValueForKey(buf, "n"), netname)){ // could be someone with same name, so make (more) sure if( ClientInSprayroom(bs->client) ){ bs->which_wall = BotChooseCorrectWall(bs); bs->enemy = -1; // chat BotAI_BotInitialChat(bs, "wall_missed", NULL); trap_BotEnterChat(bs->cs, 0, CHAT_ALL); return; } } // check if opposite team client = ClientFromName(netname); if(!BotSameTeam(bs, client)){ float rnd; // flame rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1); if(random() > rnd) return; BotAI_BotInitialChat(bs, "wall_insult", netname, NULL); trap_BotEnterChat(bs->cs, 0, CHAT_ALL); } }
/* ================== BotChat_EnemySuicide ================== */ int BotChat_EnemySuicide(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; if (BotNumActivePlayers() <= 1) return qfalse; // rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENEMYSUICIDE, 0, 1); //don't chat in teamplay if (TeamPlayIsOn()) return qfalse; // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //if fast chat is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (!BotValidChatPosition(bs)) return qfalse; // if (BotVisibleEnemies(bs)) return qfalse; // if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32); else strcpy(name, ""); BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* ======================================================================================================================================= BotChat_ExitGame ======================================================================================================================================= */ int BotChat_ExitGame(bot_state_t *bs) { char name[32]; float rnd; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) { return qfalse; } // don't chat in teamplay if (TeamPlayIsOn()) { return qfalse; } // don't chat in tournament mode if (gametype == GT_TOURNAMENT) { return qfalse; } rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1); if (random() > rnd) { return qfalse; } if (BotNumActivePlayers() <= 1) { return qfalse; } BotAI_BotInitialChat(bs, "game_exit", EasyClientName(bs->client, name, 32), BotRandomOpponentName(bs), "[invalid var]", "[invalid var]", BotMapTitle(), NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
int BotTeamCarrierVisible( bot_state_t *bs ) { int i; float vis; aas_entityinfo_t entinfo; gentity_t *ent; float f, alertness; float squaredist; vec3_t dir; int areanum; alertness = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_ALERTNESS, 0, 1 ); for ( i = 0; i < maxclients && i < MAX_CLIENTS; i++ ) { if ( i == bs->client ) continue; ent = &g_entities[ i ]; if ( !ent->inuse || !ent->target_ent ) continue; BotEntityInfo( ent->target_ent->s.number, &entinfo ); if ( !entinfo.valid || !( entinfo.powerups & ( 1 << PW_BATTLESUIT ) ) ) continue; if ( !BotSameTeam( bs, i ) ) continue; VectorSubtract( entinfo.origin, bs->origin, dir ); squaredist = VectorLengthSquared( dir ); if ( squaredist > Square( 900.0 + alertness * 4000.0 ) ) continue; f = 90 + 90 - ( 90 - ( squaredist > Square( 810 ) ? Square( 810 ) : squaredist ) / ( 810 * 9 ) ); vis = BotEntityVisible( bs->entitynum, bs->eye, bs->viewangles, f, entinfo.number ); if ( vis <= 0 ) continue; areanum = BotPointAreaNum( entinfo.origin ); if ( trap_AAS_AreaTravelTimeToGoalArea( bs->areanum, bs->origin, areanum, bs->tfl ) ) { return entinfo.number; } } return -1; }
/* ================== BotChat_EndLevel ================== */ int BotChat_EndLevel( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( BotIsObserver( bs ) ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1 ); if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } // if ( BotIsFirstInRankings( bs ) ) { BotAI_BotInitialChat( bs, "level_end_victory", EasyClientName( bs->client, name, 32 ), // 0 BotRandomOpponentName( bs ), // 1 "[invalid var]", // 2 BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL ); } else if ( BotIsLastInRankings( bs ) ) { BotAI_BotInitialChat( bs, "level_end_lose", EasyClientName( bs->client, name, 32 ), // 0 BotRandomOpponentName( bs ), // 1 BotFirstClientInRankings(), // 2 "[invalid var]", // 3 BotMapTitle(), // 4 NULL ); } else { BotAI_BotInitialChat( bs, "level_end", EasyClientName( bs->client, name, 32 ), // 0 BotRandomOpponentName( bs ), // 1 BotFirstClientInRankings(), // 2 BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL ); } bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_EndLevel ================== */ int BotChat_EndLevel(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; // teamplay if (TeamPlayIsOn()) { #ifdef MISSIONPACK if (BotIsFirstInRankings(bs)) { trap_EA_Command(bs->client, "vtaunt"); } #endif return qtrue; } // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1); if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; // if (BotIsFirstInRankings(bs)) { BotAI_BotInitialChat(bs, "level_end_victory", EasyClientName(bs->client, name, 32), // 0 BotRandomOpponentName(bs), // 1 "[invalid var]", // 2 BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL); } else if (BotIsLastInRankings(bs)) { BotAI_BotInitialChat(bs, "level_end_lose", EasyClientName(bs->client, name, 32), // 0 BotRandomOpponentName(bs), // 1 BotFirstClientInRankings(), // 2 "[invalid var]", // 3 BotMapTitle(), // 4 NULL); } else { BotAI_BotInitialChat(bs, "level_end", EasyClientName(bs->client, name, 32), // 0 BotRandomOpponentName(bs), // 1 BotFirstClientInRankings(), // 2 BotLastClientInRankings(), // 3 BotMapTitle(), // 4 NULL); } bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* =============== BotReactionLoad (Re)load the bot's reaction times. =============== */ void BotReactionLoad(bot_state_t *bs) { float reaction_char; // The reaction time characteristic needs some serious massaging. This // value is between 0 and 5 and originally represented how long the bot // would wait before firing at a target. Now it's just the measure of // how long it takes the bot to start start reacting to any change it // notices, and is primarily used in aiming. // // NOTE: Actual reaction times could be between 0 and 5, but that range // is clearly unreasonable. This code translates the reaction time to // a value between 0.0 and 1.0, and then scales it between the minimum // and maximum reaction times. // // NOTE: Low values here are good and correspond to lower reaction times. // This is not a skill value. reaction_char = 0.2 * trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_REACTIONTIME, 0.0, 5.0); // Scale the reaction characteristic from [0, 1] to [min, max] bs->react_time = interpolate(bot_reaction_min.value, bot_reaction_max.value, reaction_char); }
/* ================== BotChat_EnemySuicide ================== */ int BotChat_EnemySuicide( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } // rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1 ); //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } //if fast chat is off if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( !BotValidChatPosition( bs ) ) { return qfalse; } // if ( bs->enemy >= 0 ) { EasyClientName( bs->enemy, name, 32 ); } else { strcpy( name, "" );} BotAI_BotInitialChat( bs, "enemy_suicide", name, NULL ); bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ======================================================================================================================================= BotChat_HitNoDeath ======================================================================================================================================= */ int BotChat_HitNoDeath(bot_state_t *bs) { char name[32], *weap; float rnd; int lasthurt_client; aas_entityinfo_t entinfo; lasthurt_client = g_entities[bs->client].client->lasthurt_client; if (!lasthurt_client) { return qfalse; } if (lasthurt_client == bs->client) { return qfalse; } if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) { return qfalse; } if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) { return qfalse; } if (BotNumActivePlayers() <= 1) { return qfalse; } rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1); // don't chat in teamplay if (TeamPlayIsOn()) { return qfalse; } // don't chat in tournament mode if (gametype == GT_TOURNAMENT) { return qfalse; } if (random() > rnd * 0.5) { return qfalse; } if (!BotValidChatPosition(bs)) { return qfalse; } if (BotVisibleEnemies(bs)) { return qfalse; } if (bs->enemy >= MAX_CLIENTS) { return qfalse; } if (bs->enemy >= 0) { // get the entity information BotEntityInfo(bs->enemy, &entinfo); if (EntityIsShooting(&entinfo)) { return qfalse; } } ClientName(lasthurt_client, name, sizeof(name)); weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod); BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL); bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_Death ================== */ int BotChat_Death( bot_state_t *bs ) { char name[32]; float rnd; if ( bot_nochat.integer ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1 ); //if fast chatting is off if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } // if ( bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS ) { EasyClientName( bs->lastkilledby, name, 32 ); } else { strcpy( name, "[world]" ); } // if ( TeamPlayIsOn() && BotSameTeam( bs, bs->lastkilledby ) ) { if ( bs->lastkilledby == bs->client ) { return qfalse; } BotAI_BotInitialChat( bs, "death_teammate", name, NULL ); bs->chatto = CHAT_TEAM; } else { //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } // if ( bs->botdeathtype == MOD_WATER ) { BotAI_BotInitialChat( bs, "death_drown", BotRandomOpponentName( bs ), NULL ); } else if ( bs->botdeathtype == MOD_SLIME ) { BotAI_BotInitialChat( bs, "death_slime", BotRandomOpponentName( bs ), NULL ); } else if ( bs->botdeathtype == MOD_LAVA ) { BotAI_BotInitialChat( bs, "death_lava", BotRandomOpponentName( bs ), NULL ); } else if ( bs->botdeathtype == MOD_FALLING ) { BotAI_BotInitialChat( bs, "death_cratered", BotRandomOpponentName( bs ), NULL ); } else if ( bs->botsuicide || //all other suicides by own weapon bs->botdeathtype == MOD_CRUSH || bs->botdeathtype == MOD_SUICIDE || bs->botdeathtype == MOD_TARGET_LASER || bs->botdeathtype == MOD_TRIGGER_HURT || bs->botdeathtype == MOD_UNKNOWN ) { BotAI_BotInitialChat( bs, "death_suicide", BotRandomOpponentName( bs ), NULL ); } else if ( bs->botdeathtype == MOD_TELEFRAG ) { BotAI_BotInitialChat( bs, "death_telefrag", name, NULL ); } else { if ( ( bs->botdeathtype == MOD_GAUNTLET || bs->botdeathtype == MOD_RAILGUN || bs->botdeathtype == MOD_BFG || bs->botdeathtype == MOD_BFG_SPLASH ) && random() < 0.5 ) { if ( bs->botdeathtype == MOD_GAUNTLET ) { BotAI_BotInitialChat( bs, "death_gauntlet", name, // 0 BotWeaponNameForMeansOfDeath( bs->botdeathtype ), // 1 NULL ); } else if ( bs->botdeathtype == MOD_RAILGUN ) { BotAI_BotInitialChat( bs, "death_rail", name, // 0 BotWeaponNameForMeansOfDeath( bs->botdeathtype ), // 1 NULL ); } else { BotAI_BotInitialChat( bs, "death_bfg", name, // 0 BotWeaponNameForMeansOfDeath( bs->botdeathtype ), // 1 NULL ); } } //choose between insult and praise else if ( random() < trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1 ) ) { BotAI_BotInitialChat( bs, "death_insult", name, // 0 BotWeaponNameForMeansOfDeath( bs->botdeathtype ), // 1 NULL ); } else { BotAI_BotInitialChat( bs, "death_praise", name, // 0 BotWeaponNameForMeansOfDeath( bs->botdeathtype ), // 1 NULL ); } } bs->chatto = CHAT_ALL; } bs->lastchat_time = trap_AAS_Time(); return qtrue; }
/* ================== BotWeaponCharsLoad Load and store the weapon characteristics for the specified weapon. ================== */ void BotWeaponCharsLoad(bot_state_t *bs, int weapon) { int acc_char, skill_char; #ifdef DEBUG_AI // Use standardized accuracies and weapon skills if requested if (bs->debug_flags & BOT_DEBUG_MAKE_SKILL_STANDARD) { switch ( (int)(bs->settings.skill + 0.5) ) { default: case 5: bs->weapon_char_acc[weapon] = 1.0; bs->weapon_char_skill[weapon] = 1.0; break; case 4: bs->weapon_char_acc[weapon] = 0.65; bs->weapon_char_skill[weapon] = 0.65; break; case 3: bs->weapon_char_acc[weapon] = 0.40; bs->weapon_char_skill[weapon] = 0.40; break; case 2: bs->weapon_char_acc[weapon] = 0.25; bs->weapon_char_skill[weapon] = 0.25; break; case 1: bs->weapon_char_acc[weapon] = 0.12; bs->weapon_char_skill[weapon] = 0.12; break; } return; } #endif // Most weapons have different accuracies and skill characteristics switch (weapon) { case WP_MACHINEGUN: acc_char = CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN; skill_char = CHARACTERISTIC_AIM_SKILL; break; case WP_SHOTGUN: acc_char = CHARACTERISTIC_AIM_ACCURACY_SHOTGUN; skill_char = CHARACTERISTIC_AIM_SKILL; break; case WP_GRENADE_LAUNCHER: acc_char = CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER; skill_char = CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER; break; case WP_ROCKET_LAUNCHER: acc_char = CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER; skill_char = CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER; break; case WP_LIGHTNING: acc_char = CHARACTERISTIC_AIM_ACCURACY_LIGHTNING; skill_char = CHARACTERISTIC_AIM_SKILL; break; case WP_RAILGUN: acc_char = CHARACTERISTIC_AIM_ACCURACY_RAILGUN; skill_char = CHARACTERISTIC_AIM_SKILL; break; case WP_PLASMAGUN: acc_char = CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN; skill_char = CHARACTERISTIC_AIM_SKILL_PLASMAGUN; break; case WP_BFG: acc_char = CHARACTERISTIC_AIM_ACCURACY_BFG10K; skill_char = CHARACTERISTIC_AIM_SKILL_BFG10K; break; default: acc_char = CHARACTERISTIC_AIM_ACCURACY; skill_char = CHARACTERISTIC_AIM_SKILL; break; } // Lookup reasonably bounded accuracy and skill values // // NOTE: For reference, the bot files list different skill values for // level 3, 4, and 5 bots. Level 1 and 2 skills are computed as a // factor of level 3 skill. The bot skill values are generally // interpolated to the following ranges: // 5: 0.75 to 1.00 // 4: 0.40 to 0.90 // 3: 0.25 to 0.60 // 2: 0.15 to 0.36 // 2: 0.07 to 0.18 bs->weapon_char_acc [weapon] = trap_Characteristic_BFloat(bs->character, acc_char, 0.1, 1); bs->weapon_char_skill[weapon] = trap_Characteristic_BFloat(bs->character, skill_char, 0.1, 1); // Skill 1-3 bots have identical characteristics, so this code // must manually decrease the accuracies of lower skilled bots // NOTE: The original code set handicaps instead of scaling these values if (bs->settings.skill <= 1) { bs->weapon_char_acc [weapon] *= 0.30; bs->weapon_char_skill[weapon] *= 0.30; } else if (bs->settings.skill <= 2) { bs->weapon_char_acc [weapon] *= 0.60; bs->weapon_char_skill[weapon] *= 0.60; } }
/* ================== BotChat_Death ================== */ int BotChat_Death(bot_state_t *bs) { char name[32]; float rnd; if (bot_nochat.integer) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1); // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //if fast chatting is off if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; // if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS) EasyClientName(bs->lastkilledby, name, 32); else strcpy(name, "[world]"); // if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) { if (bs->lastkilledby == bs->client) return qfalse; BotAI_BotInitialChat(bs, "death_teammate", name, NULL); bs->chatto = CHAT_TEAM; } else { //teamplay if (TeamPlayIsOn()) { #ifdef MISSIONPACK trap_EA_Command(bs->client, "vtaunt"); #endif return qtrue; } // if (bs->botdeathtype == MOD_WATER) BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL); else if (bs->botdeathtype == MOD_SLIME) BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL); else if (bs->botdeathtype == MOD_LAVA) BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL); else if (bs->botdeathtype == MOD_FALLING) BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL); else if (bs->botsuicide || //all other suicides by own weapon bs->botdeathtype == MOD_CRUSH || bs->botdeathtype == MOD_SUICIDE || bs->botdeathtype == MOD_TARGET_LASER || bs->botdeathtype == MOD_TRIGGER_HURT || bs->botdeathtype == MOD_UNKNOWN) BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL); else if (bs->botdeathtype == MOD_TELEFRAG) BotAI_BotInitialChat(bs, "death_telefrag", name, NULL); #ifdef MISSIONPACK else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze")) BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL); #endif else { if ((bs->botdeathtype == MOD_GAUNTLET || bs->botdeathtype == MOD_RAILGUN || bs->botdeathtype == MOD_BFG || bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) { if (bs->botdeathtype == MOD_GAUNTLET) BotAI_BotInitialChat(bs, "death_gauntlet", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); else if (bs->botdeathtype == MOD_RAILGUN) BotAI_BotInitialChat(bs, "death_rail", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); else BotAI_BotInitialChat(bs, "death_bfg", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); } //choose between insult and praise else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) { BotAI_BotInitialChat(bs, "death_insult", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); } else { BotAI_BotInitialChat(bs, "death_praise", name, // 0 BotWeaponNameForMeansOfDeath(bs->botdeathtype), // 1 NULL); } } bs->chatto = CHAT_ALL; } bs->lastchat_time = FloatTime(); 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; }
/* * 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; }
/* ============= BotInitialize Initialize all internal data in the bot state ============= */ void BotInitialize(bot_state_t *bs) { int i; char gender[MAX_CHARACTERISTIC_PATH]; char userinfo[MAX_INFO_STRING]; // No valid last command time exists, but make the bot do its AI as if nothing // special has happened recently bs->last_command_time_ms = server_time_ms; // Set the team (red, blue, or free) when not in tournament mode if (g_gametype.integer != GT_TOURNAMENT) trap_EA_Command(bs->client, va("team %s", bs->settings.team)); // Set the bot gender trap_Characteristic_String(bs->character, CHARACTERISTIC_GENDER, gender, sizeof(gender)); trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo)); Info_SetValueForKey(userinfo, "sex", gender); trap_SetUserinfo(bs->client, userinfo); // Set the chat gender if (gender[0] == 'm' || gender[0] == 'M') trap_BotSetChatGender(bs->cs, CHAT_GENDERMALE); else if (gender[0] == 'f' || gender[0] == 'F') trap_BotSetChatGender(bs->cs, CHAT_GENDERFEMALE); else trap_BotSetChatGender(bs->cs, CHAT_GENDERLESS); // Set the chat name trap_BotSetChatName(bs->cs, EntityNameFast(bs->ent), bs->client); #ifdef DEBUG_AI // Initialize debug settings bs->debug_flags = 0x00000000; bs->use_weapon = WP_NONE; #endif // Load the skill and accuracy characteristics for each weapon for (i = 0; i < WP_NUM_WEAPONS; i++) BotWeaponCharsLoad(bs, i); // Load the bot's reaction times BotReactionLoad(bs); // Cache the chat attack characteristic, since it's used a lot bs->chat_attack = (.5 <= trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_EASY_FRAGGER, 0, 1)); // Initialize enemies BotAimEnemySet(bs, NULL, NULL); bs->goal_enemy = NULL; // Initialize the awareness engine BotAwarenessReset(bs); // Initialize the main goal BotGoalReset(bs); // Item tracking, timing, and statistics BotItemReset(bs); // Accuracy data for different aim zones BotAccuracyReset(bs); }
/* ================== BotChat_Random ================== */ int BotChat_Random( bot_state_t *bs ) { float rnd; char name[32]; if ( bot_nochat.integer ) { return qfalse; } if ( BotIsObserver( bs ) ) { return qfalse; } if ( bs->lastchat_time > trap_AAS_Time() - 3 ) { return qfalse; } //don't chat in teamplay if ( TeamPlayIsOn() ) { return qfalse; } //don't chat when doing something important :) if ( bs->ltgtype == LTG_TEAMHELP || bs->ltgtype == LTG_TEAMACCOMPANY || bs->ltgtype == LTG_RUSHBASE ) { return qfalse; } // rnd = trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1 ); if ( random() > bs->thinktime * 0.1 ) { return qfalse; } if ( !bot_fastchat.integer ) { if ( random() > rnd ) { return qfalse; } if ( random() > 0.25 ) { return qfalse; } } if ( BotNumActivePlayers() <= 1 ) { return qfalse; } if ( !BotValidChatPosition( bs ) ) { return qfalse; } // if ( bs->lastkilledplayer == bs->client ) { strcpy( name, BotRandomOpponentName( bs ) ); } else { EasyClientName( bs->lastkilledplayer, name, sizeof( name ) ); } // if ( random() < trap_Characteristic_BFloat( bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1 ) ) { BotAI_BotInitialChat( bs, "random_misc", BotRandomOpponentName( bs ), // 0 name, // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL ); } else { BotAI_BotInitialChat( bs, "random_insult", BotRandomOpponentName( bs ), // 0 name, // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL ); } bs->lastchat_time = trap_AAS_Time(); bs->chatto = CHAT_ALL; return qtrue; }
/* ================== BotChat_Random ================== */ int BotChat_Random(bot_state_t *bs) { float rnd; char name[32]; if (bot_nochat.integer) return qfalse; if (BotIsObserver(bs)) return qfalse; if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse; // don't chat in tournament mode if (gametype == GT_TOURNAMENT) return qfalse; //don't chat when doing something important :) if (bs->ltgtype == LTG_TEAMHELP || bs->ltgtype == LTG_TEAMACCOMPANY || bs->ltgtype == LTG_RUSHBASE) return qfalse; // rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1); if (random() > bs->thinktime * 0.1) return qfalse; if (!bot_fastchat.integer) { if (random() > rnd) return qfalse; if (random() > 0.25) return qfalse; } if (BotNumActivePlayers() <= 1) return qfalse; // if (!BotValidChatPosition(bs)) return qfalse; // if (BotVisibleEnemies(bs)) return qfalse; // if (bs->lastkilledplayer == bs->client) { strcpy(name, BotRandomOpponentName(bs)); } else { EasyClientName(bs->lastkilledplayer, name, sizeof(name)); } if (TeamPlayIsOn()) { #ifdef MISSIONPACK trap_EA_Command(bs->client, "vtaunt"); #endif return qfalse; // don't wait } // if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) { BotAI_BotInitialChat(bs, "random_misc", BotRandomOpponentName(bs), // 0 name, // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL); } else { BotAI_BotInitialChat(bs, "random_insult", BotRandomOpponentName(bs), // 0 name, // 1 "[invalid var]", // 2 "[invalid var]", // 3 BotMapTitle(), // 4 BotRandomWeaponName(), // 5 NULL); } bs->lastchat_time = FloatTime(); bs->chatto = CHAT_ALL; return qtrue; }