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 Quake III Arena source code; 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/botlib.h"
35 #include "../botlib/be_aas.h"
36 #include "../botlib/be_ea.h"
37 #include "../botlib/be_ai_char.h"
38 #include "../botlib/be_ai_chat.h"
39 #include "../botlib/be_ai_gen.h"
40 #include "../botlib/be_ai_goal.h"
41 #include "../botlib/be_ai_move.h"
42 #include "../botlib/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
57 #include "../../ui/menudef.h"
58 #endif
59 
60 #define TIME_BETWEENCHATTING	25
61 
62 
63 /*
64 ==================
65 BotNumActivePlayers
66 ==================
67 */
BotNumActivePlayers(void)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 */
BotIsFirstInRankings(bot_state_t * bs)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 */
BotIsLastInRankings(bot_state_t * bs)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 */
BotFirstClientInRankings(void)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 */
BotLastClientInRankings(void)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 */
BotRandomOpponentName(bot_state_t * bs)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 
BotMapTitle(void)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 
BotWeaponNameForMeansOfDeath(int mod)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 */
BotRandomWeaponName(void)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 */
BotVisibleEnemies(bot_state_t * bs)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 */
BotValidChatPosition(bot_state_t * bs)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 */
BotChat_EnterGame(bot_state_t * bs)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 */
BotChat_ExitGame(bot_state_t * bs)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 */
BotChat_StartLevel(bot_state_t * bs)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 */
BotChat_EndLevel(bot_state_t * bs)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 */
BotChat_Death(bot_state_t * bs)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 */
BotChat_Kill(bot_state_t * bs)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 */
BotChat_EnemySuicide(bot_state_t * bs)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 */
BotChat_HitTalking(bot_state_t * bs)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 */
BotChat_HitNoDeath(bot_state_t * bs)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 */
BotChat_HitNoKill(bot_state_t * bs)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 */
BotChat_Random(bot_state_t * bs)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 */
BotChatTime(bot_state_t * bs)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 */
BotChatTest(bot_state_t * bs)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 }
1227