Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

ai_chat.c (34653B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 
     24 /*****************************************************************************
     25  * name:		ai_chat.c
     26  *
     27  * desc:		Quake3 bot AI
     28  *
     29  * $Archive: /MissionPack/code/game/ai_chat.c $
     30  *
     31  *****************************************************************************/
     32 
     33 #include "g_local.h"
     34 #include "botlib.h"
     35 #include "be_aas.h"
     36 #include "be_ea.h"
     37 #include "be_ai_char.h"
     38 #include "be_ai_chat.h"
     39 #include "be_ai_gen.h"
     40 #include "be_ai_goal.h"
     41 #include "be_ai_move.h"
     42 #include "be_ai_weap.h"
     43 //
     44 #include "ai_main.h"
     45 #include "ai_dmq3.h"
     46 #include "ai_chat.h"
     47 #include "ai_cmd.h"
     48 #include "ai_dmnet.h"
     49 //
     50 #include "chars.h"				//characteristics
     51 #include "inv.h"				//indexes into the inventory
     52 #include "syn.h"				//synonyms
     53 #include "match.h"				//string matching types and vars
     54 
     55 // for the voice chats
     56 #ifdef MISSIONPACK // bk001205
     57 #include "../../ui/menudef.h"
     58 #endif
     59 
     60 #define TIME_BETWEENCHATTING	25
     61 
     62 
     63 /*
     64 ==================
     65 BotNumActivePlayers
     66 ==================
     67 */
     68 int BotNumActivePlayers(void) {
     69 	int i, num;
     70 	char buf[MAX_INFO_STRING];
     71 	static int maxclients;
     72 
     73 	if (!maxclients)
     74 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
     75 
     76 	num = 0;
     77 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
     78 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
     79 		//if no config string or no name
     80 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
     81 		//skip spectators
     82 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
     83 		//
     84 		num++;
     85 	}
     86 	return num;
     87 }
     88 
     89 /*
     90 ==================
     91 BotIsFirstInRankings
     92 ==================
     93 */
     94 int BotIsFirstInRankings(bot_state_t *bs) {
     95 	int i, score;
     96 	char buf[MAX_INFO_STRING];
     97 	static int maxclients;
     98 	playerState_t ps;
     99 
    100 	if (!maxclients)
    101 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
    102 
    103 	score = bs->cur_ps.persistant[PERS_SCORE];
    104 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
    105 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
    106 		//if no config string or no name
    107 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
    108 		//skip spectators
    109 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
    110 		//
    111 		BotAI_GetClientState(i, &ps);
    112 		if (score < ps.persistant[PERS_SCORE]) return qfalse;
    113 	}
    114 	return qtrue;
    115 }
    116 
    117 /*
    118 ==================
    119 BotIsLastInRankings
    120 ==================
    121 */
    122 int BotIsLastInRankings(bot_state_t *bs) {
    123 	int i, score;
    124 	char buf[MAX_INFO_STRING];
    125 	static int maxclients;
    126 	playerState_t ps;
    127 
    128 	if (!maxclients)
    129 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
    130 
    131 	score = bs->cur_ps.persistant[PERS_SCORE];
    132 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
    133 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
    134 		//if no config string or no name
    135 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
    136 		//skip spectators
    137 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
    138 		//
    139 		BotAI_GetClientState(i, &ps);
    140 		if (score > ps.persistant[PERS_SCORE]) return qfalse;
    141 	}
    142 	return qtrue;
    143 }
    144 
    145 /*
    146 ==================
    147 BotFirstClientInRankings
    148 ==================
    149 */
    150 char *BotFirstClientInRankings(void) {
    151 	int i, bestscore, bestclient;
    152 	char buf[MAX_INFO_STRING];
    153 	static char name[32];
    154 	static int maxclients;
    155 	playerState_t ps;
    156 
    157 	if (!maxclients)
    158 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
    159 
    160 	bestscore = -999999;
    161 	bestclient = 0;
    162 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
    163 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
    164 		//if no config string or no name
    165 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
    166 		//skip spectators
    167 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
    168 		//
    169 		BotAI_GetClientState(i, &ps);
    170 		if (ps.persistant[PERS_SCORE] > bestscore) {
    171 			bestscore = ps.persistant[PERS_SCORE];
    172 			bestclient = i;
    173 		}
    174 	}
    175 	EasyClientName(bestclient, name, 32);
    176 	return name;
    177 }
    178 
    179 /*
    180 ==================
    181 BotLastClientInRankings
    182 ==================
    183 */
    184 char *BotLastClientInRankings(void) {
    185 	int i, worstscore, bestclient;
    186 	char buf[MAX_INFO_STRING];
    187 	static char name[32];
    188 	static int maxclients;
    189 	playerState_t ps;
    190 
    191 	if (!maxclients)
    192 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
    193 
    194 	worstscore = 999999;
    195 	bestclient = 0;
    196 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
    197 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
    198 		//if no config string or no name
    199 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
    200 		//skip spectators
    201 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
    202 		//
    203 		BotAI_GetClientState(i, &ps);
    204 		if (ps.persistant[PERS_SCORE] < worstscore) {
    205 			worstscore = ps.persistant[PERS_SCORE];
    206 			bestclient = i;
    207 		}
    208 	}
    209 	EasyClientName(bestclient, name, 32);
    210 	return name;
    211 }
    212 
    213 /*
    214 ==================
    215 BotRandomOpponentName
    216 ==================
    217 */
    218 char *BotRandomOpponentName(bot_state_t *bs) {
    219 	int i, count;
    220 	char buf[MAX_INFO_STRING];
    221 	int opponents[MAX_CLIENTS], numopponents;
    222 	static int maxclients;
    223 	static char name[32];
    224 
    225 	if (!maxclients)
    226 		maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
    227 
    228 	numopponents = 0;
    229 	opponents[0] = 0;
    230 	for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
    231 		if (i == bs->client) continue;
    232 		//
    233 		trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
    234 		//if no config string or no name
    235 		if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
    236 		//skip spectators
    237 		if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
    238 		//skip team mates
    239 		if (BotSameTeam(bs, i)) continue;
    240 		//
    241 		opponents[numopponents] = i;
    242 		numopponents++;
    243 	}
    244 	count = random() * numopponents;
    245 	for (i = 0; i < numopponents; i++) {
    246 		count--;
    247 		if (count <= 0) {
    248 			EasyClientName(opponents[i], name, sizeof(name));
    249 			return name;
    250 		}
    251 	}
    252 	EasyClientName(opponents[0], name, sizeof(name));
    253 	return name;
    254 }
    255 
    256 /*
    257 ==================
    258 BotMapTitle
    259 ==================
    260 */
    261 
    262 char *BotMapTitle(void) {
    263 	char info[1024];
    264 	static char mapname[128];
    265 
    266 	trap_GetServerinfo(info, sizeof(info));
    267 
    268 	strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
    269 	mapname[sizeof(mapname)-1] = '\0';
    270 
    271 	return mapname;
    272 }
    273 
    274 
    275 /*
    276 ==================
    277 BotWeaponNameForMeansOfDeath
    278 ==================
    279 */
    280 
    281 char *BotWeaponNameForMeansOfDeath(int mod) {
    282 	switch(mod) {
    283 		case MOD_SHOTGUN: return "Shotgun";
    284 		case MOD_GAUNTLET: return "Gauntlet";
    285 		case MOD_MACHINEGUN: return "Machinegun";
    286 		case MOD_GRENADE:
    287 		case MOD_GRENADE_SPLASH: return "Grenade Launcher";
    288 		case MOD_ROCKET:
    289 		case MOD_ROCKET_SPLASH: return "Rocket Launcher";
    290 		case MOD_PLASMA:
    291 		case MOD_PLASMA_SPLASH: return "Plasmagun";
    292 		case MOD_RAILGUN: return "Railgun";
    293 		case MOD_LIGHTNING: return "Lightning Gun";
    294 		case MOD_BFG:
    295 		case MOD_BFG_SPLASH: return "BFG10K";
    296 #ifdef MISSIONPACK
    297 		case MOD_NAIL: return "Nailgun";
    298 		case MOD_CHAINGUN: return "Chaingun";
    299 		case MOD_PROXIMITY_MINE: return "Proximity Launcher";
    300 		case MOD_KAMIKAZE: return "Kamikaze";
    301 		case MOD_JUICED: return "Prox mine";
    302 #endif
    303 		case MOD_GRAPPLE: return "Grapple";
    304 		default: return "[unknown weapon]";
    305 	}
    306 }
    307 
    308 /*
    309 ==================
    310 BotRandomWeaponName
    311 ==================
    312 */
    313 char *BotRandomWeaponName(void) {
    314 	int rnd;
    315 
    316 #ifdef MISSIONPACK
    317 	rnd = random() * 11.9;
    318 #else
    319 	rnd = random() * 8.9;
    320 #endif
    321 	switch(rnd) {
    322 		case 0: return "Gauntlet";
    323 		case 1: return "Shotgun";
    324 		case 2: return "Machinegun";
    325 		case 3: return "Grenade Launcher";
    326 		case 4: return "Rocket Launcher";
    327 		case 5: return "Plasmagun";
    328 		case 6: return "Railgun";
    329 		case 7: return "Lightning Gun";
    330 #ifdef MISSIONPACK
    331 		case 8: return "Nailgun";
    332 		case 9: return "Chaingun";
    333 		case 10: return "Proximity Launcher";
    334 #endif
    335 		default: return "BFG10K";
    336 	}
    337 }
    338 
    339 /*
    340 ==================
    341 BotVisibleEnemies
    342 ==================
    343 */
    344 int BotVisibleEnemies(bot_state_t *bs) {
    345 	float vis;
    346 	int i;
    347 	aas_entityinfo_t entinfo;
    348 
    349 	for (i = 0; i < MAX_CLIENTS; i++) {
    350 
    351 		if (i == bs->client) continue;
    352 		//
    353 		BotEntityInfo(i, &entinfo);
    354 		//
    355 		if (!entinfo.valid) continue;
    356 		//if the enemy isn't dead and the enemy isn't the bot self
    357 		if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
    358 		//if the enemy is invisible and not shooting
    359 		if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
    360 			continue;
    361 		}
    362 		//if on the same team
    363 		if (BotSameTeam(bs, i)) continue;
    364 		//check if the enemy is visible
    365 		vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
    366 		if (vis > 0) return qtrue;
    367 	}
    368 	return qfalse;
    369 }
    370 
    371 /*
    372 ==================
    373 BotValidChatPosition
    374 ==================
    375 */
    376 int BotValidChatPosition(bot_state_t *bs) {
    377 	vec3_t point, start, end, mins, maxs;
    378 	bsp_trace_t trace;
    379 
    380 	//if the bot is dead all positions are valid
    381 	if (BotIsDead(bs)) return qtrue;
    382 	//never start chatting with a powerup
    383 	if (bs->inventory[INVENTORY_QUAD] ||
    384 		bs->inventory[INVENTORY_HASTE] ||
    385 		bs->inventory[INVENTORY_INVISIBILITY] ||
    386 		bs->inventory[INVENTORY_REGEN] ||
    387 		bs->inventory[INVENTORY_FLIGHT]) return qfalse;
    388 	//must be on the ground
    389 	//if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) return qfalse;
    390 	//do not chat if in lava or slime
    391 	VectorCopy(bs->origin, point);
    392 	point[2] -= 24;
    393 	if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
    394 	//do not chat if under water
    395 	VectorCopy(bs->origin, point);
    396 	point[2] += 32;
    397 	if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
    398 	//must be standing on the world entity
    399 	VectorCopy(bs->origin, start);
    400 	VectorCopy(bs->origin, end);
    401 	start[2] += 1;
    402 	end[2] -= 10;
    403 	trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
    404 	BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
    405 	if (trace.ent != ENTITYNUM_WORLD) return qfalse;
    406 	//the bot is in a position where it can chat
    407 	return qtrue;
    408 }
    409 
    410 /*
    411 ==================
    412 BotChat_EnterGame
    413 ==================
    414 */
    415 int BotChat_EnterGame(bot_state_t *bs) {
    416 	char name[32];
    417 	float rnd;
    418 
    419 	if (bot_nochat.integer) return qfalse;
    420 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    421 	//don't chat in teamplay
    422 	if (TeamPlayIsOn()) return qfalse;
    423 	// don't chat in tournament mode
    424 	if (gametype == GT_TOURNAMENT) return qfalse;
    425 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
    426 	if (!bot_fastchat.integer) {
    427 		if (random() > rnd) return qfalse;
    428 	}
    429 	if (BotNumActivePlayers() <= 1) return qfalse;
    430 	if (!BotValidChatPosition(bs)) return qfalse;
    431 	BotAI_BotInitialChat(bs, "game_enter",
    432 				EasyClientName(bs->client, name, 32),	// 0
    433 				BotRandomOpponentName(bs),				// 1
    434 				"[invalid var]",						// 2
    435 				"[invalid var]",						// 3
    436 				BotMapTitle(),							// 4
    437 				NULL);
    438 	bs->lastchat_time = FloatTime();
    439 	bs->chatto = CHAT_ALL;
    440 	return qtrue;
    441 }
    442 
    443 /*
    444 ==================
    445 BotChat_ExitGame
    446 ==================
    447 */
    448 int BotChat_ExitGame(bot_state_t *bs) {
    449 	char name[32];
    450 	float rnd;
    451 
    452 	if (bot_nochat.integer) return qfalse;
    453 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    454 	//don't chat in teamplay
    455 	if (TeamPlayIsOn()) return qfalse;
    456 	// don't chat in tournament mode
    457 	if (gametype == GT_TOURNAMENT) return qfalse;
    458 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
    459 	if (!bot_fastchat.integer) {
    460 		if (random() > rnd) return qfalse;
    461 	}
    462 	if (BotNumActivePlayers() <= 1) return qfalse;
    463 	//
    464 	BotAI_BotInitialChat(bs, "game_exit",
    465 				EasyClientName(bs->client, name, 32),	// 0
    466 				BotRandomOpponentName(bs),				// 1
    467 				"[invalid var]",						// 2
    468 				"[invalid var]",						// 3
    469 				BotMapTitle(),							// 4
    470 				NULL);
    471 	bs->lastchat_time = FloatTime();
    472 	bs->chatto = CHAT_ALL;
    473 	return qtrue;
    474 }
    475 
    476 /*
    477 ==================
    478 BotChat_StartLevel
    479 ==================
    480 */
    481 int BotChat_StartLevel(bot_state_t *bs) {
    482 	char name[32];
    483 	float rnd;
    484 
    485 	if (bot_nochat.integer) return qfalse;
    486 	if (BotIsObserver(bs)) return qfalse;
    487 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    488 	//don't chat in teamplay
    489 	if (TeamPlayIsOn()) {
    490 	    trap_EA_Command(bs->client, "vtaunt");
    491 	    return qfalse;
    492 	}
    493 	// don't chat in tournament mode
    494 	if (gametype == GT_TOURNAMENT) return qfalse;
    495 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
    496 	if (!bot_fastchat.integer) {
    497 		if (random() > rnd) return qfalse;
    498 	}
    499 	if (BotNumActivePlayers() <= 1) return qfalse;
    500 	BotAI_BotInitialChat(bs, "level_start",
    501 				EasyClientName(bs->client, name, 32),	// 0
    502 				NULL);
    503 	bs->lastchat_time = FloatTime();
    504 	bs->chatto = CHAT_ALL;
    505 	return qtrue;
    506 }
    507 
    508 /*
    509 ==================
    510 BotChat_EndLevel
    511 ==================
    512 */
    513 int BotChat_EndLevel(bot_state_t *bs) {
    514 	char name[32];
    515 	float rnd;
    516 
    517 	if (bot_nochat.integer) return qfalse;
    518 	if (BotIsObserver(bs)) return qfalse;
    519 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    520 	// teamplay
    521 	if (TeamPlayIsOn()) 
    522 	{
    523 		if (BotIsFirstInRankings(bs)) {
    524 			trap_EA_Command(bs->client, "vtaunt");
    525 		}
    526 		return qtrue;
    527 	}
    528 	// don't chat in tournament mode
    529 	if (gametype == GT_TOURNAMENT) return qfalse;
    530 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
    531 	if (!bot_fastchat.integer) {
    532 		if (random() > rnd) return qfalse;
    533 	}
    534 	if (BotNumActivePlayers() <= 1) return qfalse;
    535 	//
    536 	if (BotIsFirstInRankings(bs)) {
    537 		BotAI_BotInitialChat(bs, "level_end_victory",
    538 				EasyClientName(bs->client, name, 32),	// 0
    539 				BotRandomOpponentName(bs),				// 1
    540 				"[invalid var]",						// 2
    541 				BotLastClientInRankings(),				// 3
    542 				BotMapTitle(),							// 4
    543 				NULL);
    544 	}
    545 	else if (BotIsLastInRankings(bs)) {
    546 		BotAI_BotInitialChat(bs, "level_end_lose",
    547 				EasyClientName(bs->client, name, 32),	// 0
    548 				BotRandomOpponentName(bs),				// 1
    549 				BotFirstClientInRankings(),				// 2
    550 				"[invalid var]",						// 3
    551 				BotMapTitle(),							// 4
    552 				NULL);
    553 	}
    554 	else {
    555 		BotAI_BotInitialChat(bs, "level_end",
    556 				EasyClientName(bs->client, name, 32),	// 0
    557 				BotRandomOpponentName(bs),				// 1
    558 				BotFirstClientInRankings(),				// 2
    559 				BotLastClientInRankings(),				// 3
    560 				BotMapTitle(),							// 4
    561 				NULL);
    562 	}
    563 	bs->lastchat_time = FloatTime();
    564 	bs->chatto = CHAT_ALL;
    565 	return qtrue;
    566 }
    567 
    568 /*
    569 ==================
    570 BotChat_Death
    571 ==================
    572 */
    573 int BotChat_Death(bot_state_t *bs) {
    574 	char name[32];
    575 	float rnd;
    576 
    577 	if (bot_nochat.integer) return qfalse;
    578 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    579 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
    580 	// don't chat in tournament mode
    581 	if (gametype == GT_TOURNAMENT) return qfalse;
    582 	//if fast chatting is off
    583 	if (!bot_fastchat.integer) {
    584 		if (random() > rnd) return qfalse;
    585 	}
    586 	if (BotNumActivePlayers() <= 1) return qfalse;
    587 	//
    588 	if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
    589 		EasyClientName(bs->lastkilledby, name, 32);
    590 	else
    591 		strcpy(name, "[world]");
    592 	//
    593 	if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
    594 		if (bs->lastkilledby == bs->client) return qfalse;
    595 		BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
    596 		bs->chatto = CHAT_TEAM;
    597 	}
    598 	else
    599 	{
    600 		//teamplay
    601 		if (TeamPlayIsOn()) {
    602 			trap_EA_Command(bs->client, "vtaunt");
    603 			return qtrue;
    604 		}
    605 		//
    606 		if (bs->botdeathtype == MOD_WATER)
    607 			BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
    608 		else if (bs->botdeathtype == MOD_SLIME)
    609 			BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
    610 		else if (bs->botdeathtype == MOD_LAVA)
    611 			BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
    612 		else if (bs->botdeathtype == MOD_FALLING)
    613 			BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
    614 		else if (bs->botsuicide || //all other suicides by own weapon
    615 				bs->botdeathtype == MOD_CRUSH ||
    616 				bs->botdeathtype == MOD_SUICIDE ||
    617 				bs->botdeathtype == MOD_TARGET_LASER ||
    618 				bs->botdeathtype == MOD_TRIGGER_HURT ||
    619 				bs->botdeathtype == MOD_UNKNOWN)
    620 			BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
    621 		else if (bs->botdeathtype == MOD_TELEFRAG)
    622 			BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
    623 #ifdef MISSIONPACK
    624 		else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze"))
    625 			BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL);
    626 #endif
    627 		else {
    628 			if ((bs->botdeathtype == MOD_GAUNTLET ||
    629 				bs->botdeathtype == MOD_RAILGUN ||
    630 				bs->botdeathtype == MOD_BFG ||
    631 				bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
    632 
    633 				if (bs->botdeathtype == MOD_GAUNTLET)
    634 					BotAI_BotInitialChat(bs, "death_gauntlet",
    635 							name,												// 0
    636 							BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
    637 							NULL);
    638 				else if (bs->botdeathtype == MOD_RAILGUN)
    639 					BotAI_BotInitialChat(bs, "death_rail",
    640 							name,												// 0
    641 							BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
    642 							NULL);
    643 				else
    644 					BotAI_BotInitialChat(bs, "death_bfg",
    645 							name,												// 0
    646 							BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
    647 							NULL);
    648 			}
    649 			//choose between insult and praise
    650 			else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
    651 				BotAI_BotInitialChat(bs, "death_insult",
    652 							name,												// 0
    653 							BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
    654 							NULL);
    655 			}
    656 			else {
    657 				BotAI_BotInitialChat(bs, "death_praise",
    658 							name,												// 0
    659 							BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
    660 							NULL);
    661 			}
    662 		}
    663 		bs->chatto = CHAT_ALL;
    664 	}
    665 	bs->lastchat_time = FloatTime();
    666 	return qtrue;
    667 }
    668 
    669 /*
    670 ==================
    671 BotChat_Kill
    672 ==================
    673 */
    674 int BotChat_Kill(bot_state_t *bs) {
    675 	char name[32];
    676 	float rnd;
    677 
    678 	if (bot_nochat.integer) return qfalse;
    679 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    680 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
    681 	// don't chat in tournament mode
    682 	if (gametype == GT_TOURNAMENT) return qfalse;
    683 	//if fast chat is off
    684 	if (!bot_fastchat.integer) {
    685 		if (random() > rnd) return qfalse;
    686 	}
    687 	if (bs->lastkilledplayer == bs->client) return qfalse;
    688 	if (BotNumActivePlayers() <= 1) return qfalse;
    689 	if (!BotValidChatPosition(bs)) return qfalse;
    690 	//
    691 	if (BotVisibleEnemies(bs)) return qfalse;
    692 	//
    693 	EasyClientName(bs->lastkilledplayer, name, 32);
    694 	//
    695 	bs->chatto = CHAT_ALL;
    696 	if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
    697 		BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
    698 		bs->chatto = CHAT_TEAM;
    699 	}
    700 	else
    701 	{
    702 		//don't chat in teamplay
    703 		if (TeamPlayIsOn()) {
    704 			trap_EA_Command(bs->client, "vtaunt");
    705 			return qfalse;			// don't wait
    706 		}
    707 		//
    708 		if (bs->enemydeathtype == MOD_GAUNTLET) {
    709 			BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
    710 		}
    711 		else if (bs->enemydeathtype == MOD_RAILGUN) {
    712 			BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
    713 		}
    714 		else if (bs->enemydeathtype == MOD_TELEFRAG) {
    715 			BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
    716 		}
    717 #ifdef MISSIONPACK
    718 		else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze"))
    719 			BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL);
    720 #endif
    721 		//choose between insult and praise
    722 		else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
    723 			BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
    724 		}
    725 		else {
    726 			BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
    727 		}
    728 	}
    729 	bs->lastchat_time = FloatTime();
    730 	return qtrue;
    731 }
    732 
    733 /*
    734 ==================
    735 BotChat_EnemySuicide
    736 ==================
    737 */
    738 int BotChat_EnemySuicide(bot_state_t *bs) {
    739 	char name[32];
    740 	float rnd;
    741 
    742 	if (bot_nochat.integer) return qfalse;
    743 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    744 	if (BotNumActivePlayers() <= 1) return qfalse;
    745 	//
    746 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
    747 	//don't chat in teamplay
    748 	if (TeamPlayIsOn()) return qfalse;
    749 	// don't chat in tournament mode
    750 	if (gametype == GT_TOURNAMENT) return qfalse;
    751 	//if fast chat is off
    752 	if (!bot_fastchat.integer) {
    753 		if (random() > rnd) return qfalse;
    754 	}
    755 	if (!BotValidChatPosition(bs)) return qfalse;
    756 	//
    757 	if (BotVisibleEnemies(bs)) return qfalse;
    758 	//
    759 	if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
    760 	else strcpy(name, "");
    761 	BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
    762 	bs->lastchat_time = FloatTime();
    763 	bs->chatto = CHAT_ALL;
    764 	return qtrue;
    765 }
    766 
    767 /*
    768 ==================
    769 BotChat_HitTalking
    770 ==================
    771 */
    772 int BotChat_HitTalking(bot_state_t *bs) {
    773 	char name[32], *weap;
    774 	int lasthurt_client;
    775 	float rnd;
    776 
    777 	if (bot_nochat.integer) return qfalse;
    778 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    779 	if (BotNumActivePlayers() <= 1) return qfalse;
    780 	lasthurt_client = g_entities[bs->client].client->lasthurt_client;
    781 	if (!lasthurt_client) return qfalse;
    782 	if (lasthurt_client == bs->client) return qfalse;
    783 	//
    784 	if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
    785 	//
    786 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
    787 	//don't chat in teamplay
    788 	if (TeamPlayIsOn()) return qfalse;
    789 	// don't chat in tournament mode
    790 	if (gametype == GT_TOURNAMENT) return qfalse;
    791 	//if fast chat is off
    792 	if (!bot_fastchat.integer) {
    793 		if (random() > rnd * 0.5) return qfalse;
    794 	}
    795 	if (!BotValidChatPosition(bs)) return qfalse;
    796 	//
    797 	ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
    798 	weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
    799 	//
    800 	BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
    801 	bs->lastchat_time = FloatTime();
    802 	bs->chatto = CHAT_ALL;
    803 	return qtrue;
    804 }
    805 
    806 /*
    807 ==================
    808 BotChat_HitNoDeath
    809 ==================
    810 */
    811 int BotChat_HitNoDeath(bot_state_t *bs) {
    812 	char name[32], *weap;
    813 	float rnd;
    814 	int lasthurt_client;
    815 	aas_entityinfo_t entinfo;
    816 
    817 	lasthurt_client = g_entities[bs->client].client->lasthurt_client;
    818 	if (!lasthurt_client) return qfalse;
    819 	if (lasthurt_client == bs->client) return qfalse;
    820 	//
    821 	if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
    822 	//
    823 	if (bot_nochat.integer) return qfalse;
    824 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    825 	if (BotNumActivePlayers() <= 1) return qfalse;
    826 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
    827 	//don't chat in teamplay
    828 	if (TeamPlayIsOn()) return qfalse;
    829 	// don't chat in tournament mode
    830 	if (gametype == GT_TOURNAMENT) return qfalse;
    831 	//if fast chat is off
    832 	if (!bot_fastchat.integer) {
    833 		if (random() > rnd * 0.5) return qfalse;
    834 	}
    835 	if (!BotValidChatPosition(bs)) return qfalse;
    836 	//
    837 	if (BotVisibleEnemies(bs)) return qfalse;
    838 	//
    839 	BotEntityInfo(bs->enemy, &entinfo);
    840 	if (EntityIsShooting(&entinfo)) return qfalse;
    841 	//
    842 	ClientName(lasthurt_client, name, sizeof(name));
    843 	weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
    844 	//
    845 	BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
    846 	bs->lastchat_time = FloatTime();
    847 	bs->chatto = CHAT_ALL;
    848 	return qtrue;
    849 }
    850 
    851 /*
    852 ==================
    853 BotChat_HitNoKill
    854 ==================
    855 */
    856 int BotChat_HitNoKill(bot_state_t *bs) {
    857 	char name[32], *weap;
    858 	float rnd;
    859 	aas_entityinfo_t entinfo;
    860 
    861 	if (bot_nochat.integer) return qfalse;
    862 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    863 	if (BotNumActivePlayers() <= 1) return qfalse;
    864 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
    865 	//don't chat in teamplay
    866 	if (TeamPlayIsOn()) return qfalse;
    867 	// don't chat in tournament mode
    868 	if (gametype == GT_TOURNAMENT) return qfalse;
    869 	//if fast chat is off
    870 	if (!bot_fastchat.integer) {
    871 		if (random() > rnd * 0.5) return qfalse;
    872 	}
    873 	if (!BotValidChatPosition(bs)) return qfalse;
    874 	//
    875 	if (BotVisibleEnemies(bs)) return qfalse;
    876 	//
    877 	BotEntityInfo(bs->enemy, &entinfo);
    878 	if (EntityIsShooting(&entinfo)) return qfalse;
    879 	//
    880 	ClientName(bs->enemy, name, sizeof(name));
    881 	weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
    882 	//
    883 	BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
    884 	bs->lastchat_time = FloatTime();
    885 	bs->chatto = CHAT_ALL;
    886 	return qtrue;
    887 }
    888 
    889 /*
    890 ==================
    891 BotChat_Random
    892 ==================
    893 */
    894 int BotChat_Random(bot_state_t *bs) {
    895 	float rnd;
    896 	char name[32];
    897 
    898 	if (bot_nochat.integer) return qfalse;
    899 	if (BotIsObserver(bs)) return qfalse;
    900 	if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
    901 	// don't chat in tournament mode
    902 	if (gametype == GT_TOURNAMENT) return qfalse;
    903 	//don't chat when doing something important :)
    904 	if (bs->ltgtype == LTG_TEAMHELP ||
    905 		bs->ltgtype == LTG_TEAMACCOMPANY ||
    906 		bs->ltgtype == LTG_RUSHBASE) return qfalse;
    907 	//
    908 	rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
    909 	if (random() > bs->thinktime * 0.1) return qfalse;
    910 	if (!bot_fastchat.integer) {
    911 		if (random() > rnd) return qfalse;
    912 		if (random() > 0.25) return qfalse;
    913 	}
    914 	if (BotNumActivePlayers() <= 1) return qfalse;
    915 	//
    916 	if (!BotValidChatPosition(bs)) return qfalse;
    917 	//
    918 	if (BotVisibleEnemies(bs)) return qfalse;
    919 	//
    920 	if (bs->lastkilledplayer == bs->client) {
    921 		strcpy(name, BotRandomOpponentName(bs));
    922 	}
    923 	else {
    924 		EasyClientName(bs->lastkilledplayer, name, sizeof(name));
    925 	}
    926 	if (TeamPlayIsOn()) {
    927 		trap_EA_Command(bs->client, "vtaunt");
    928 		return qfalse;			// don't wait
    929 	}
    930 	//
    931 	if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
    932 		BotAI_BotInitialChat(bs, "random_misc",
    933 					BotRandomOpponentName(bs),	// 0
    934 					name,						// 1
    935 					"[invalid var]",			// 2
    936 					"[invalid var]",			// 3
    937 					BotMapTitle(),				// 4
    938 					BotRandomWeaponName(),		// 5
    939 					NULL);
    940 	}
    941 	else {
    942 		BotAI_BotInitialChat(bs, "random_insult",
    943 					BotRandomOpponentName(bs),	// 0
    944 					name,						// 1
    945 					"[invalid var]",			// 2
    946 					"[invalid var]",			// 3
    947 					BotMapTitle(),				// 4
    948 					BotRandomWeaponName(),		// 5
    949 					NULL);
    950 	}
    951 	bs->lastchat_time = FloatTime();
    952 	bs->chatto = CHAT_ALL;
    953 	return qtrue;
    954 }
    955 
    956 /*
    957 ==================
    958 BotChatTime
    959 ==================
    960 */
    961 float BotChatTime(bot_state_t *bs) {
    962 	int cpm;
    963 
    964 	cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
    965 
    966 	return 2.0;	//(float) trap_BotChatLength(bs->cs) * 30 / cpm;
    967 }
    968 
    969 /*
    970 ==================
    971 BotChatTest
    972 ==================
    973 */
    974 void BotChatTest(bot_state_t *bs) {
    975 
    976 	char name[32];
    977 	char *weap;
    978 	int num, i;
    979 
    980 	num = trap_BotNumInitialChats(bs->cs, "game_enter");
    981 	for (i = 0; i < num; i++)
    982 	{
    983 		BotAI_BotInitialChat(bs, "game_enter",
    984 					EasyClientName(bs->client, name, 32),	// 0
    985 					BotRandomOpponentName(bs),				// 1
    986 					"[invalid var]",						// 2
    987 					"[invalid var]",						// 3
    988 					BotMapTitle(),							// 4
    989 					NULL);
    990 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
    991 	}
    992 	num = trap_BotNumInitialChats(bs->cs, "game_exit");
    993 	for (i = 0; i < num; i++)
    994 	{
    995 		BotAI_BotInitialChat(bs, "game_exit",
    996 					EasyClientName(bs->client, name, 32),	// 0
    997 					BotRandomOpponentName(bs),				// 1
    998 					"[invalid var]",						// 2
    999 					"[invalid var]",						// 3
   1000 					BotMapTitle(),							// 4
   1001 					NULL);
   1002 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1003 	}
   1004 	num = trap_BotNumInitialChats(bs->cs, "level_start");
   1005 	for (i = 0; i < num; i++)
   1006 	{
   1007 		BotAI_BotInitialChat(bs, "level_start",
   1008 					EasyClientName(bs->client, name, 32),	// 0
   1009 					NULL);
   1010 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1011 	}
   1012 	num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
   1013 	for (i = 0; i < num; i++)
   1014 	{
   1015 		BotAI_BotInitialChat(bs, "level_end_victory",
   1016 				EasyClientName(bs->client, name, 32),	// 0
   1017 				BotRandomOpponentName(bs),				// 1
   1018 				BotFirstClientInRankings(),				// 2
   1019 				BotLastClientInRankings(),				// 3
   1020 				BotMapTitle(),							// 4
   1021 				NULL);
   1022 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1023 	}
   1024 	num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
   1025 	for (i = 0; i < num; i++)
   1026 	{
   1027 		BotAI_BotInitialChat(bs, "level_end_lose",
   1028 				EasyClientName(bs->client, name, 32),	// 0
   1029 				BotRandomOpponentName(bs),				// 1
   1030 				BotFirstClientInRankings(),				// 2
   1031 				BotLastClientInRankings(),				// 3
   1032 				BotMapTitle(),							// 4
   1033 				NULL);
   1034 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1035 	}
   1036 	num = trap_BotNumInitialChats(bs->cs, "level_end");
   1037 	for (i = 0; i < num; i++)
   1038 	{
   1039 		BotAI_BotInitialChat(bs, "level_end",
   1040 				EasyClientName(bs->client, name, 32),	// 0
   1041 				BotRandomOpponentName(bs),				// 1
   1042 				BotFirstClientInRankings(),				// 2
   1043 				BotLastClientInRankings(),				// 3
   1044 				BotMapTitle(),							// 4
   1045 				NULL);
   1046 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1047 	}
   1048 	EasyClientName(bs->lastkilledby, name, sizeof(name));
   1049 	num = trap_BotNumInitialChats(bs->cs, "death_drown");
   1050 	for (i = 0; i < num; i++)
   1051 	{
   1052 		//
   1053 		BotAI_BotInitialChat(bs, "death_drown", name, NULL);
   1054 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1055 	}
   1056 	num = trap_BotNumInitialChats(bs->cs, "death_slime");
   1057 	for (i = 0; i < num; i++)
   1058 	{
   1059 		BotAI_BotInitialChat(bs, "death_slime", name, NULL);
   1060 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1061 	}
   1062 	num = trap_BotNumInitialChats(bs->cs, "death_lava");
   1063 	for (i = 0; i < num; i++)
   1064 	{
   1065 		BotAI_BotInitialChat(bs, "death_lava", name, NULL);
   1066 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1067 	}
   1068 	num = trap_BotNumInitialChats(bs->cs, "death_cratered");
   1069 	for (i = 0; i < num; i++)
   1070 	{
   1071 		BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
   1072 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1073 	}
   1074 	num = trap_BotNumInitialChats(bs->cs, "death_suicide");
   1075 	for (i = 0; i < num; i++)
   1076 	{
   1077 		BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
   1078 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1079 	}
   1080 	num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
   1081 	for (i = 0; i < num; i++)
   1082 	{
   1083 		BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
   1084 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1085 	}
   1086 	num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
   1087 	for (i = 0; i < num; i++)
   1088 	{
   1089 		BotAI_BotInitialChat(bs, "death_gauntlet",
   1090 				name,												// 0
   1091 				BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
   1092 				NULL);
   1093 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1094 	}
   1095 	num = trap_BotNumInitialChats(bs->cs, "death_rail");
   1096 	for (i = 0; i < num; i++)
   1097 	{
   1098 		BotAI_BotInitialChat(bs, "death_rail",
   1099 				name,												// 0
   1100 				BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
   1101 				NULL);
   1102 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1103 	}
   1104 	num = trap_BotNumInitialChats(bs->cs, "death_bfg");
   1105 	for (i = 0; i < num; i++)
   1106 	{
   1107 		BotAI_BotInitialChat(bs, "death_bfg",
   1108 				name,												// 0
   1109 				BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
   1110 				NULL);
   1111 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1112 	}
   1113 	num = trap_BotNumInitialChats(bs->cs, "death_insult");
   1114 	for (i = 0; i < num; i++)
   1115 	{
   1116 		BotAI_BotInitialChat(bs, "death_insult",
   1117 					name,												// 0
   1118 					BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
   1119 					NULL);
   1120 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1121 	}
   1122 	num = trap_BotNumInitialChats(bs->cs, "death_praise");
   1123 	for (i = 0; i < num; i++)
   1124 	{
   1125 		BotAI_BotInitialChat(bs, "death_praise",
   1126 					name,												// 0
   1127 					BotWeaponNameForMeansOfDeath(bs->botdeathtype),		// 1
   1128 					NULL);
   1129 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1130 	}
   1131 	//
   1132 	EasyClientName(bs->lastkilledplayer, name, 32);
   1133 	//
   1134 	num = trap_BotNumInitialChats(bs->cs, "kill_gauntlet");
   1135 	for (i = 0; i < num; i++)
   1136 	{
   1137 		//
   1138 		BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
   1139 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1140 	}
   1141 	num = trap_BotNumInitialChats(bs->cs, "kill_rail");
   1142 	for (i = 0; i < num; i++)
   1143 	{
   1144 		BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
   1145 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1146 	}
   1147 	num = trap_BotNumInitialChats(bs->cs, "kill_telefrag");
   1148 	for (i = 0; i < num; i++)
   1149 	{
   1150 		BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
   1151 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1152 	}
   1153 	num = trap_BotNumInitialChats(bs->cs, "kill_insult");
   1154 	for (i = 0; i < num; i++)
   1155 	{
   1156 		BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
   1157 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1158 	}
   1159 	num = trap_BotNumInitialChats(bs->cs, "kill_praise");
   1160 	for (i = 0; i < num; i++)
   1161 	{
   1162 		BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
   1163 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1164 	}
   1165 	num = trap_BotNumInitialChats(bs->cs, "enemy_suicide");
   1166 	for (i = 0; i < num; i++)
   1167 	{
   1168 		BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
   1169 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1170 	}
   1171 	ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
   1172 	weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
   1173 	num = trap_BotNumInitialChats(bs->cs, "hit_talking");
   1174 	for (i = 0; i < num; i++)
   1175 	{
   1176 		BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
   1177 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1178 	}
   1179 	num = trap_BotNumInitialChats(bs->cs, "hit_nodeath");
   1180 	for (i = 0; i < num; i++)
   1181 	{
   1182 		BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
   1183 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1184 	}
   1185 	num = trap_BotNumInitialChats(bs->cs, "hit_nokill");
   1186 	for (i = 0; i < num; i++)
   1187 	{
   1188 		BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
   1189 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1190 	}
   1191 	//
   1192 	if (bs->lastkilledplayer == bs->client) {
   1193 		strcpy(name, BotRandomOpponentName(bs));
   1194 	}
   1195 	else {
   1196 		EasyClientName(bs->lastkilledplayer, name, sizeof(name));
   1197 	}
   1198 	//
   1199 	num = trap_BotNumInitialChats(bs->cs, "random_misc");
   1200 	for (i = 0; i < num; i++)
   1201 	{
   1202 		//
   1203 		BotAI_BotInitialChat(bs, "random_misc",
   1204 					BotRandomOpponentName(bs),	// 0
   1205 					name,						// 1
   1206 					"[invalid var]",			// 2
   1207 					"[invalid var]",			// 3
   1208 					BotMapTitle(),				// 4
   1209 					BotRandomWeaponName(),		// 5
   1210 					NULL);
   1211 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1212 	}
   1213 	num = trap_BotNumInitialChats(bs->cs, "random_insult");
   1214 	for (i = 0; i < num; i++)
   1215 	{
   1216 		BotAI_BotInitialChat(bs, "random_insult",
   1217 					BotRandomOpponentName(bs),	// 0
   1218 					name,						// 1
   1219 					"[invalid var]",			// 2
   1220 					"[invalid var]",			// 3
   1221 					BotMapTitle(),				// 4
   1222 					BotRandomWeaponName(),		// 5
   1223 					NULL);
   1224 		trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
   1225 	}
   1226 }