00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "g_local.h"
00034 #include "botlib.h"
00035 #include "be_aas.h"
00036 #include "be_ea.h"
00037 #include "be_ai_char.h"
00038 #include "be_ai_chat.h"
00039 #include "be_ai_gen.h"
00040 #include "be_ai_goal.h"
00041 #include "be_ai_move.h"
00042 #include "be_ai_weap.h"
00043
00044 #include "ai_main.h"
00045 #include "ai_dmq3.h"
00046 #include "ai_chat.h"
00047 #include "ai_cmd.h"
00048 #include "ai_dmnet.h"
00049
00050 #include "chars.h"
00051 #include "inv.h"
00052 #include "syn.h"
00053 #include "match.h"
00054
00055
00056 #ifdef MISSIONPACK // bk001205
00057 #include "../../ui/menudef.h"
00058 #endif
00059
00060 #define TIME_BETWEENCHATTING 25
00061
00062
00063
00064
00065
00066
00067
00068 int BotNumActivePlayers(void) {
00069 int i, num;
00070 char buf[MAX_INFO_STRING];
00071 static int maxclients;
00072
00073 if (!maxclients)
00074 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00075
00076 num = 0;
00077 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00078 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00079
00080 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00081
00082 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00083
00084 num++;
00085 }
00086 return num;
00087 }
00088
00089
00090
00091
00092
00093
00094 int BotIsFirstInRankings(bot_state_t *bs) {
00095 int i, score;
00096 char buf[MAX_INFO_STRING];
00097 static int maxclients;
00098 playerState_t ps;
00099
00100 if (!maxclients)
00101 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00102
00103 score = bs->cur_ps.persistant[PERS_SCORE];
00104 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00105 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00106
00107 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00108
00109 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00110
00111 BotAI_GetClientState(i, &ps);
00112 if (score < ps.persistant[PERS_SCORE]) return qfalse;
00113 }
00114 return qtrue;
00115 }
00116
00117
00118
00119
00120
00121
00122 int BotIsLastInRankings(bot_state_t *bs) {
00123 int i, score;
00124 char buf[MAX_INFO_STRING];
00125 static int maxclients;
00126 playerState_t ps;
00127
00128 if (!maxclients)
00129 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00130
00131 score = bs->cur_ps.persistant[PERS_SCORE];
00132 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00133 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00134
00135 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00136
00137 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00138
00139 BotAI_GetClientState(i, &ps);
00140 if (score > ps.persistant[PERS_SCORE]) return qfalse;
00141 }
00142 return qtrue;
00143 }
00144
00145
00146
00147
00148
00149
00150 char *BotFirstClientInRankings(void) {
00151 int i, bestscore, bestclient;
00152 char buf[MAX_INFO_STRING];
00153 static char name[32];
00154 static int maxclients;
00155 playerState_t ps;
00156
00157 if (!maxclients)
00158 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00159
00160 bestscore = -999999;
00161 bestclient = 0;
00162 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00163 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00164
00165 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00166
00167 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00168
00169 BotAI_GetClientState(i, &ps);
00170 if (ps.persistant[PERS_SCORE] > bestscore) {
00171 bestscore = ps.persistant[PERS_SCORE];
00172 bestclient = i;
00173 }
00174 }
00175 EasyClientName(bestclient, name, 32);
00176 return name;
00177 }
00178
00179
00180
00181
00182
00183
00184 char *BotLastClientInRankings(void) {
00185 int i, worstscore, bestclient;
00186 char buf[MAX_INFO_STRING];
00187 static char name[32];
00188 static int maxclients;
00189 playerState_t ps;
00190
00191 if (!maxclients)
00192 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00193
00194 worstscore = 999999;
00195 bestclient = 0;
00196 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00197 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00198
00199 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00200
00201 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00202
00203 BotAI_GetClientState(i, &ps);
00204 if (ps.persistant[PERS_SCORE] < worstscore) {
00205 worstscore = ps.persistant[PERS_SCORE];
00206 bestclient = i;
00207 }
00208 }
00209 EasyClientName(bestclient, name, 32);
00210 return name;
00211 }
00212
00213
00214
00215
00216
00217
00218 char *BotRandomOpponentName(bot_state_t *bs) {
00219 int i, count;
00220 char buf[MAX_INFO_STRING];
00221 int opponents[MAX_CLIENTS], numopponents;
00222 static int maxclients;
00223 static char name[32];
00224
00225 if (!maxclients)
00226 maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
00227
00228 numopponents = 0;
00229 opponents[0] = 0;
00230 for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
00231 if (i == bs->client) continue;
00232
00233 trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
00234
00235 if (!strlen(buf) || !strlen(Info_ValueForKey(buf, "n"))) continue;
00236
00237 if (atoi(Info_ValueForKey(buf, "t")) == TEAM_SPECTATOR) continue;
00238
00239 if (BotSameTeam(bs, i)) continue;
00240
00241 opponents[numopponents] = i;
00242 numopponents++;
00243 }
00244 count = random() * numopponents;
00245 for (i = 0; i < numopponents; i++) {
00246 count--;
00247 if (count <= 0) {
00248 EasyClientName(opponents[i], name, sizeof(name));
00249 return name;
00250 }
00251 }
00252 EasyClientName(opponents[0], name, sizeof(name));
00253 return name;
00254 }
00255
00256
00257
00258
00259
00260
00261
00262 char *BotMapTitle(void) {
00263 char info[1024];
00264 static char mapname[128];
00265
00266 trap_GetServerinfo(info, sizeof(info));
00267
00268 strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
00269 mapname[sizeof(mapname)-1] = '\0';
00270
00271 return mapname;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281 char *BotWeaponNameForMeansOfDeath(int mod) {
00282 switch(mod) {
00283 case MOD_SHOTGUN: return "Shotgun";
00284 case MOD_GAUNTLET: return "Gauntlet";
00285 case MOD_MACHINEGUN: return "Machinegun";
00286 case MOD_GRENADE:
00287 case MOD_GRENADE_SPLASH: return "Grenade Launcher";
00288 case MOD_ROCKET:
00289 case MOD_ROCKET_SPLASH: return "Rocket Launcher";
00290 case MOD_PLASMA:
00291 case MOD_PLASMA_SPLASH: return "Plasmagun";
00292 case MOD_RAILGUN: return "Railgun";
00293 case MOD_LIGHTNING: return "Lightning Gun";
00294 case MOD_BFG:
00295 case MOD_BFG_SPLASH: return "BFG10K";
00296 #ifdef MISSIONPACK
00297 case MOD_NAIL: return "Nailgun";
00298 case MOD_CHAINGUN: return "Chaingun";
00299 case MOD_PROXIMITY_MINE: return "Proximity Launcher";
00300 case MOD_KAMIKAZE: return "Kamikaze";
00301 case MOD_JUICED: return "Prox mine";
00302 #endif
00303 case MOD_GRAPPLE: return "Grapple";
00304 default: return "[unknown weapon]";
00305 }
00306 }
00307
00308
00309
00310
00311
00312
00313 char *BotRandomWeaponName(void) {
00314 int rnd;
00315
00316 #ifdef MISSIONPACK
00317 rnd = random() * 11.9;
00318 #else
00319 rnd = random() * 8.9;
00320 #endif
00321 switch(rnd) {
00322 case 0: return "Gauntlet";
00323 case 1: return "Shotgun";
00324 case 2: return "Machinegun";
00325 case 3: return "Grenade Launcher";
00326 case 4: return "Rocket Launcher";
00327 case 5: return "Plasmagun";
00328 case 6: return "Railgun";
00329 case 7: return "Lightning Gun";
00330 #ifdef MISSIONPACK
00331 case 8: return "Nailgun";
00332 case 9: return "Chaingun";
00333 case 10: return "Proximity Launcher";
00334 #endif
00335 default: return "BFG10K";
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344 int BotVisibleEnemies(bot_state_t *bs) {
00345 float vis;
00346 int i;
00347 aas_entityinfo_t entinfo;
00348
00349 for (i = 0; i < MAX_CLIENTS; i++) {
00350
00351 if (i == bs->client) continue;
00352
00353 BotEntityInfo(i, &entinfo);
00354
00355 if (!entinfo.valid) continue;
00356
00357 if (EntityIsDead(&entinfo) || entinfo.number == bs->entitynum) continue;
00358
00359 if (EntityIsInvisible(&entinfo) && !EntityIsShooting(&entinfo)) {
00360 continue;
00361 }
00362
00363 if (BotSameTeam(bs, i)) continue;
00364
00365 vis = BotEntityVisible(bs->entitynum, bs->eye, bs->viewangles, 360, i);
00366 if (vis > 0) return qtrue;
00367 }
00368 return qfalse;
00369 }
00370
00371
00372
00373
00374
00375
00376 int BotValidChatPosition(bot_state_t *bs) {
00377 vec3_t point, start, end, mins, maxs;
00378 bsp_trace_t trace;
00379
00380
00381 if (BotIsDead(bs)) return qtrue;
00382
00383 if (bs->inventory[INVENTORY_QUAD] ||
00384 bs->inventory[INVENTORY_HASTE] ||
00385 bs->inventory[INVENTORY_INVISIBILITY] ||
00386 bs->inventory[INVENTORY_REGEN] ||
00387 bs->inventory[INVENTORY_FLIGHT]) return qfalse;
00388
00389
00390
00391 VectorCopy(bs->origin, point);
00392 point[2] -= 24;
00393 if (trap_PointContents(point,bs->entitynum) & (CONTENTS_LAVA|CONTENTS_SLIME)) return qfalse;
00394
00395 VectorCopy(bs->origin, point);
00396 point[2] += 32;
00397 if (trap_PointContents(point,bs->entitynum) & MASK_WATER) return qfalse;
00398
00399 VectorCopy(bs->origin, start);
00400 VectorCopy(bs->origin, end);
00401 start[2] += 1;
00402 end[2] -= 10;
00403 trap_AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, mins, maxs);
00404 BotAI_Trace(&trace, start, mins, maxs, end, bs->client, MASK_SOLID);
00405 if (trace.ent != ENTITYNUM_WORLD) return qfalse;
00406
00407 return qtrue;
00408 }
00409
00410
00411
00412
00413
00414
00415 int BotChat_EnterGame(bot_state_t *bs) {
00416 char name[32];
00417 float rnd;
00418
00419 if (bot_nochat.integer) return qfalse;
00420 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00421
00422 if (TeamPlayIsOn()) return qfalse;
00423
00424 if (gametype == GT_TOURNAMENT) return qfalse;
00425 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
00426 if (!bot_fastchat.integer) {
00427 if (random() > rnd) return qfalse;
00428 }
00429 if (BotNumActivePlayers() <= 1) return qfalse;
00430 if (!BotValidChatPosition(bs)) return qfalse;
00431 BotAI_BotInitialChat(bs, "game_enter",
00432 EasyClientName(bs->client, name, 32),
00433 BotRandomOpponentName(bs),
00434 "[invalid var]",
00435 "[invalid var]",
00436 BotMapTitle(),
00437 NULL);
00438 bs->lastchat_time = FloatTime();
00439 bs->chatto = CHAT_ALL;
00440 return qtrue;
00441 }
00442
00443
00444
00445
00446
00447
00448 int BotChat_ExitGame(bot_state_t *bs) {
00449 char name[32];
00450 float rnd;
00451
00452 if (bot_nochat.integer) return qfalse;
00453 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00454
00455 if (TeamPlayIsOn()) return qfalse;
00456
00457 if (gametype == GT_TOURNAMENT) return qfalse;
00458 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_ENTEREXITGAME, 0, 1);
00459 if (!bot_fastchat.integer) {
00460 if (random() > rnd) return qfalse;
00461 }
00462 if (BotNumActivePlayers() <= 1) return qfalse;
00463
00464 BotAI_BotInitialChat(bs, "game_exit",
00465 EasyClientName(bs->client, name, 32),
00466 BotRandomOpponentName(bs),
00467 "[invalid var]",
00468 "[invalid var]",
00469 BotMapTitle(),
00470 NULL);
00471 bs->lastchat_time = FloatTime();
00472 bs->chatto = CHAT_ALL;
00473 return qtrue;
00474 }
00475
00476
00477
00478
00479
00480
00481 int BotChat_StartLevel(bot_state_t *bs) {
00482 char name[32];
00483 float rnd;
00484
00485 if (bot_nochat.integer) return qfalse;
00486 if (BotIsObserver(bs)) return qfalse;
00487 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00488
00489 if (TeamPlayIsOn()) {
00490 trap_EA_Command(bs->client, "vtaunt");
00491 return qfalse;
00492 }
00493
00494 if (gametype == GT_TOURNAMENT) return qfalse;
00495 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
00496 if (!bot_fastchat.integer) {
00497 if (random() > rnd) return qfalse;
00498 }
00499 if (BotNumActivePlayers() <= 1) return qfalse;
00500 BotAI_BotInitialChat(bs, "level_start",
00501 EasyClientName(bs->client, name, 32),
00502 NULL);
00503 bs->lastchat_time = FloatTime();
00504 bs->chatto = CHAT_ALL;
00505 return qtrue;
00506 }
00507
00508
00509
00510
00511
00512
00513 int BotChat_EndLevel(bot_state_t *bs) {
00514 char name[32];
00515 float rnd;
00516
00517 if (bot_nochat.integer) return qfalse;
00518 if (BotIsObserver(bs)) return qfalse;
00519 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00520
00521 if (TeamPlayIsOn())
00522 {
00523 if (BotIsFirstInRankings(bs)) {
00524 trap_EA_Command(bs->client, "vtaunt");
00525 }
00526 return qtrue;
00527 }
00528
00529 if (gametype == GT_TOURNAMENT) return qfalse;
00530 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_STARTENDLEVEL, 0, 1);
00531 if (!bot_fastchat.integer) {
00532 if (random() > rnd) return qfalse;
00533 }
00534 if (BotNumActivePlayers() <= 1) return qfalse;
00535
00536 if (BotIsFirstInRankings(bs)) {
00537 BotAI_BotInitialChat(bs, "level_end_victory",
00538 EasyClientName(bs->client, name, 32),
00539 BotRandomOpponentName(bs),
00540 "[invalid var]",
00541 BotLastClientInRankings(),
00542 BotMapTitle(),
00543 NULL);
00544 }
00545 else if (BotIsLastInRankings(bs)) {
00546 BotAI_BotInitialChat(bs, "level_end_lose",
00547 EasyClientName(bs->client, name, 32),
00548 BotRandomOpponentName(bs),
00549 BotFirstClientInRankings(),
00550 "[invalid var]",
00551 BotMapTitle(),
00552 NULL);
00553 }
00554 else {
00555 BotAI_BotInitialChat(bs, "level_end",
00556 EasyClientName(bs->client, name, 32),
00557 BotRandomOpponentName(bs),
00558 BotFirstClientInRankings(),
00559 BotLastClientInRankings(),
00560 BotMapTitle(),
00561 NULL);
00562 }
00563 bs->lastchat_time = FloatTime();
00564 bs->chatto = CHAT_ALL;
00565 return qtrue;
00566 }
00567
00568
00569
00570
00571
00572
00573 int BotChat_Death(bot_state_t *bs) {
00574 char name[32];
00575 float rnd;
00576
00577 if (bot_nochat.integer) return qfalse;
00578 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00579 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_DEATH, 0, 1);
00580
00581 if (gametype == GT_TOURNAMENT) return qfalse;
00582
00583 if (!bot_fastchat.integer) {
00584 if (random() > rnd) return qfalse;
00585 }
00586 if (BotNumActivePlayers() <= 1) return qfalse;
00587
00588 if (bs->lastkilledby >= 0 && bs->lastkilledby < MAX_CLIENTS)
00589 EasyClientName(bs->lastkilledby, name, 32);
00590 else
00591 strcpy(name, "[world]");
00592
00593 if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledby)) {
00594 if (bs->lastkilledby == bs->client) return qfalse;
00595 BotAI_BotInitialChat(bs, "death_teammate", name, NULL);
00596 bs->chatto = CHAT_TEAM;
00597 }
00598 else
00599 {
00600
00601 if (TeamPlayIsOn()) {
00602 trap_EA_Command(bs->client, "vtaunt");
00603 return qtrue;
00604 }
00605
00606 if (bs->botdeathtype == MOD_WATER)
00607 BotAI_BotInitialChat(bs, "death_drown", BotRandomOpponentName(bs), NULL);
00608 else if (bs->botdeathtype == MOD_SLIME)
00609 BotAI_BotInitialChat(bs, "death_slime", BotRandomOpponentName(bs), NULL);
00610 else if (bs->botdeathtype == MOD_LAVA)
00611 BotAI_BotInitialChat(bs, "death_lava", BotRandomOpponentName(bs), NULL);
00612 else if (bs->botdeathtype == MOD_FALLING)
00613 BotAI_BotInitialChat(bs, "death_cratered", BotRandomOpponentName(bs), NULL);
00614 else if (bs->botsuicide ||
00615 bs->botdeathtype == MOD_CRUSH ||
00616 bs->botdeathtype == MOD_SUICIDE ||
00617 bs->botdeathtype == MOD_TARGET_LASER ||
00618 bs->botdeathtype == MOD_TRIGGER_HURT ||
00619 bs->botdeathtype == MOD_UNKNOWN)
00620 BotAI_BotInitialChat(bs, "death_suicide", BotRandomOpponentName(bs), NULL);
00621 else if (bs->botdeathtype == MOD_TELEFRAG)
00622 BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
00623 #ifdef MISSIONPACK
00624 else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "death_kamikaze"))
00625 BotAI_BotInitialChat(bs, "death_kamikaze", name, NULL);
00626 #endif
00627 else {
00628 if ((bs->botdeathtype == MOD_GAUNTLET ||
00629 bs->botdeathtype == MOD_RAILGUN ||
00630 bs->botdeathtype == MOD_BFG ||
00631 bs->botdeathtype == MOD_BFG_SPLASH) && random() < 0.5) {
00632
00633 if (bs->botdeathtype == MOD_GAUNTLET)
00634 BotAI_BotInitialChat(bs, "death_gauntlet",
00635 name,
00636 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
00637 NULL);
00638 else if (bs->botdeathtype == MOD_RAILGUN)
00639 BotAI_BotInitialChat(bs, "death_rail",
00640 name,
00641 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
00642 NULL);
00643 else
00644 BotAI_BotInitialChat(bs, "death_bfg",
00645 name,
00646 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
00647 NULL);
00648 }
00649
00650 else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
00651 BotAI_BotInitialChat(bs, "death_insult",
00652 name,
00653 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
00654 NULL);
00655 }
00656 else {
00657 BotAI_BotInitialChat(bs, "death_praise",
00658 name,
00659 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
00660 NULL);
00661 }
00662 }
00663 bs->chatto = CHAT_ALL;
00664 }
00665 bs->lastchat_time = FloatTime();
00666 return qtrue;
00667 }
00668
00669
00670
00671
00672
00673
00674 int BotChat_Kill(bot_state_t *bs) {
00675 char name[32];
00676 float rnd;
00677
00678 if (bot_nochat.integer) return qfalse;
00679 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00680 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
00681
00682 if (gametype == GT_TOURNAMENT) return qfalse;
00683
00684 if (!bot_fastchat.integer) {
00685 if (random() > rnd) return qfalse;
00686 }
00687 if (bs->lastkilledplayer == bs->client) return qfalse;
00688 if (BotNumActivePlayers() <= 1) return qfalse;
00689 if (!BotValidChatPosition(bs)) return qfalse;
00690
00691 if (BotVisibleEnemies(bs)) return qfalse;
00692
00693 EasyClientName(bs->lastkilledplayer, name, 32);
00694
00695 bs->chatto = CHAT_ALL;
00696 if (TeamPlayIsOn() && BotSameTeam(bs, bs->lastkilledplayer)) {
00697 BotAI_BotInitialChat(bs, "kill_teammate", name, NULL);
00698 bs->chatto = CHAT_TEAM;
00699 }
00700 else
00701 {
00702
00703 if (TeamPlayIsOn()) {
00704 trap_EA_Command(bs->client, "vtaunt");
00705 return qfalse;
00706 }
00707
00708 if (bs->enemydeathtype == MOD_GAUNTLET) {
00709 BotAI_BotInitialChat(bs, "kill_gauntlet", name, NULL);
00710 }
00711 else if (bs->enemydeathtype == MOD_RAILGUN) {
00712 BotAI_BotInitialChat(bs, "kill_rail", name, NULL);
00713 }
00714 else if (bs->enemydeathtype == MOD_TELEFRAG) {
00715 BotAI_BotInitialChat(bs, "kill_telefrag", name, NULL);
00716 }
00717 #ifdef MISSIONPACK
00718 else if (bs->botdeathtype == MOD_KAMIKAZE && trap_BotNumInitialChats(bs->cs, "kill_kamikaze"))
00719 BotAI_BotInitialChat(bs, "kill_kamikaze", name, NULL);
00720 #endif
00721
00722 else if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_INSULT, 0, 1)) {
00723 BotAI_BotInitialChat(bs, "kill_insult", name, NULL);
00724 }
00725 else {
00726 BotAI_BotInitialChat(bs, "kill_praise", name, NULL);
00727 }
00728 }
00729 bs->lastchat_time = FloatTime();
00730 return qtrue;
00731 }
00732
00733
00734
00735
00736
00737
00738 int BotChat_EnemySuicide(bot_state_t *bs) {
00739 char name[32];
00740 float rnd;
00741
00742 if (bot_nochat.integer) return qfalse;
00743 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00744 if (BotNumActivePlayers() <= 1) return qfalse;
00745
00746 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_KILL, 0, 1);
00747
00748 if (TeamPlayIsOn()) return qfalse;
00749
00750 if (gametype == GT_TOURNAMENT) return qfalse;
00751
00752 if (!bot_fastchat.integer) {
00753 if (random() > rnd) return qfalse;
00754 }
00755 if (!BotValidChatPosition(bs)) return qfalse;
00756
00757 if (BotVisibleEnemies(bs)) return qfalse;
00758
00759 if (bs->enemy >= 0) EasyClientName(bs->enemy, name, 32);
00760 else strcpy(name, "");
00761 BotAI_BotInitialChat(bs, "enemy_suicide", name, NULL);
00762 bs->lastchat_time = FloatTime();
00763 bs->chatto = CHAT_ALL;
00764 return qtrue;
00765 }
00766
00767
00768
00769
00770
00771
00772 int BotChat_HitTalking(bot_state_t *bs) {
00773 char name[32], *weap;
00774 int lasthurt_client;
00775 float rnd;
00776
00777 if (bot_nochat.integer) return qfalse;
00778 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00779 if (BotNumActivePlayers() <= 1) return qfalse;
00780 lasthurt_client = g_entities[bs->client].client->lasthurt_client;
00781 if (!lasthurt_client) return qfalse;
00782 if (lasthurt_client == bs->client) return qfalse;
00783
00784 if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
00785
00786 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITTALKING, 0, 1);
00787
00788 if (TeamPlayIsOn()) return qfalse;
00789
00790 if (gametype == GT_TOURNAMENT) return qfalse;
00791
00792 if (!bot_fastchat.integer) {
00793 if (random() > rnd * 0.5) return qfalse;
00794 }
00795 if (!BotValidChatPosition(bs)) return qfalse;
00796
00797 ClientName(g_entities[bs->client].client->lasthurt_client, name, sizeof(name));
00798 weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_client);
00799
00800 BotAI_BotInitialChat(bs, "hit_talking", name, weap, NULL);
00801 bs->lastchat_time = FloatTime();
00802 bs->chatto = CHAT_ALL;
00803 return qtrue;
00804 }
00805
00806
00807
00808
00809
00810
00811 int BotChat_HitNoDeath(bot_state_t *bs) {
00812 char name[32], *weap;
00813 float rnd;
00814 int lasthurt_client;
00815 aas_entityinfo_t entinfo;
00816
00817 lasthurt_client = g_entities[bs->client].client->lasthurt_client;
00818 if (!lasthurt_client) return qfalse;
00819 if (lasthurt_client == bs->client) return qfalse;
00820
00821 if (lasthurt_client < 0 || lasthurt_client >= MAX_CLIENTS) return qfalse;
00822
00823 if (bot_nochat.integer) return qfalse;
00824 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00825 if (BotNumActivePlayers() <= 1) return qfalse;
00826 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNODEATH, 0, 1);
00827
00828 if (TeamPlayIsOn()) return qfalse;
00829
00830 if (gametype == GT_TOURNAMENT) return qfalse;
00831
00832 if (!bot_fastchat.integer) {
00833 if (random() > rnd * 0.5) return qfalse;
00834 }
00835 if (!BotValidChatPosition(bs)) return qfalse;
00836
00837 if (BotVisibleEnemies(bs)) return qfalse;
00838
00839 BotEntityInfo(bs->enemy, &entinfo);
00840 if (EntityIsShooting(&entinfo)) return qfalse;
00841
00842 ClientName(lasthurt_client, name, sizeof(name));
00843 weap = BotWeaponNameForMeansOfDeath(g_entities[bs->client].client->lasthurt_mod);
00844
00845 BotAI_BotInitialChat(bs, "hit_nodeath", name, weap, NULL);
00846 bs->lastchat_time = FloatTime();
00847 bs->chatto = CHAT_ALL;
00848 return qtrue;
00849 }
00850
00851
00852
00853
00854
00855
00856 int BotChat_HitNoKill(bot_state_t *bs) {
00857 char name[32], *weap;
00858 float rnd;
00859 aas_entityinfo_t entinfo;
00860
00861 if (bot_nochat.integer) return qfalse;
00862 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00863 if (BotNumActivePlayers() <= 1) return qfalse;
00864 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_HITNOKILL, 0, 1);
00865
00866 if (TeamPlayIsOn()) return qfalse;
00867
00868 if (gametype == GT_TOURNAMENT) return qfalse;
00869
00870 if (!bot_fastchat.integer) {
00871 if (random() > rnd * 0.5) return qfalse;
00872 }
00873 if (!BotValidChatPosition(bs)) return qfalse;
00874
00875 if (BotVisibleEnemies(bs)) return qfalse;
00876
00877 BotEntityInfo(bs->enemy, &entinfo);
00878 if (EntityIsShooting(&entinfo)) return qfalse;
00879
00880 ClientName(bs->enemy, name, sizeof(name));
00881 weap = BotWeaponNameForMeansOfDeath(g_entities[bs->enemy].client->lasthurt_mod);
00882
00883 BotAI_BotInitialChat(bs, "hit_nokill", name, weap, NULL);
00884 bs->lastchat_time = FloatTime();
00885 bs->chatto = CHAT_ALL;
00886 return qtrue;
00887 }
00888
00889
00890
00891
00892
00893
00894 int BotChat_Random(bot_state_t *bs) {
00895 float rnd;
00896 char name[32];
00897
00898 if (bot_nochat.integer) return qfalse;
00899 if (BotIsObserver(bs)) return qfalse;
00900 if (bs->lastchat_time > FloatTime() - TIME_BETWEENCHATTING) return qfalse;
00901
00902 if (gametype == GT_TOURNAMENT) return qfalse;
00903
00904 if (bs->ltgtype == LTG_TEAMHELP ||
00905 bs->ltgtype == LTG_TEAMACCOMPANY ||
00906 bs->ltgtype == LTG_RUSHBASE) return qfalse;
00907
00908 rnd = trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_RANDOM, 0, 1);
00909 if (random() > bs->thinktime * 0.1) return qfalse;
00910 if (!bot_fastchat.integer) {
00911 if (random() > rnd) return qfalse;
00912 if (random() > 0.25) return qfalse;
00913 }
00914 if (BotNumActivePlayers() <= 1) return qfalse;
00915
00916 if (!BotValidChatPosition(bs)) return qfalse;
00917
00918 if (BotVisibleEnemies(bs)) return qfalse;
00919
00920 if (bs->lastkilledplayer == bs->client) {
00921 strcpy(name, BotRandomOpponentName(bs));
00922 }
00923 else {
00924 EasyClientName(bs->lastkilledplayer, name, sizeof(name));
00925 }
00926 if (TeamPlayIsOn()) {
00927 trap_EA_Command(bs->client, "vtaunt");
00928 return qfalse;
00929 }
00930
00931 if (random() < trap_Characteristic_BFloat(bs->character, CHARACTERISTIC_CHAT_MISC, 0, 1)) {
00932 BotAI_BotInitialChat(bs, "random_misc",
00933 BotRandomOpponentName(bs),
00934 name,
00935 "[invalid var]",
00936 "[invalid var]",
00937 BotMapTitle(),
00938 BotRandomWeaponName(),
00939 NULL);
00940 }
00941 else {
00942 BotAI_BotInitialChat(bs, "random_insult",
00943 BotRandomOpponentName(bs),
00944 name,
00945 "[invalid var]",
00946 "[invalid var]",
00947 BotMapTitle(),
00948 BotRandomWeaponName(),
00949 NULL);
00950 }
00951 bs->lastchat_time = FloatTime();
00952 bs->chatto = CHAT_ALL;
00953 return qtrue;
00954 }
00955
00956
00957
00958
00959
00960
00961 float BotChatTime(bot_state_t *bs) {
00962 int cpm;
00963
00964 cpm = trap_Characteristic_BInteger(bs->character, CHARACTERISTIC_CHAT_CPM, 1, 4000);
00965
00966 return 2.0;
00967 }
00968
00969
00970
00971
00972
00973
00974 void BotChatTest(bot_state_t *bs) {
00975
00976 char name[32];
00977 char *weap;
00978 int num, i;
00979
00980 num = trap_BotNumInitialChats(bs->cs, "game_enter");
00981 for (i = 0; i < num; i++)
00982 {
00983 BotAI_BotInitialChat(bs, "game_enter",
00984 EasyClientName(bs->client, name, 32),
00985 BotRandomOpponentName(bs),
00986 "[invalid var]",
00987 "[invalid var]",
00988 BotMapTitle(),
00989 NULL);
00990 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
00991 }
00992 num = trap_BotNumInitialChats(bs->cs, "game_exit");
00993 for (i = 0; i < num; i++)
00994 {
00995 BotAI_BotInitialChat(bs, "game_exit",
00996 EasyClientName(bs->client, name, 32),
00997 BotRandomOpponentName(bs),
00998 "[invalid var]",
00999 "[invalid var]",
01000 BotMapTitle(),
01001 NULL);
01002 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01003 }
01004 num = trap_BotNumInitialChats(bs->cs, "level_start");
01005 for (i = 0; i < num; i++)
01006 {
01007 BotAI_BotInitialChat(bs, "level_start",
01008 EasyClientName(bs->client, name, 32),
01009 NULL);
01010 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01011 }
01012 num = trap_BotNumInitialChats(bs->cs, "level_end_victory");
01013 for (i = 0; i < num; i++)
01014 {
01015 BotAI_BotInitialChat(bs, "level_end_victory",
01016 EasyClientName(bs->client, name, 32),
01017 BotRandomOpponentName(bs),
01018 BotFirstClientInRankings(),
01019 BotLastClientInRankings(),
01020 BotMapTitle(),
01021 NULL);
01022 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01023 }
01024 num = trap_BotNumInitialChats(bs->cs, "level_end_lose");
01025 for (i = 0; i < num; i++)
01026 {
01027 BotAI_BotInitialChat(bs, "level_end_lose",
01028 EasyClientName(bs->client, name, 32),
01029 BotRandomOpponentName(bs),
01030 BotFirstClientInRankings(),
01031 BotLastClientInRankings(),
01032 BotMapTitle(),
01033 NULL);
01034 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01035 }
01036 num = trap_BotNumInitialChats(bs->cs, "level_end");
01037 for (i = 0; i < num; i++)
01038 {
01039 BotAI_BotInitialChat(bs, "level_end",
01040 EasyClientName(bs->client, name, 32),
01041 BotRandomOpponentName(bs),
01042 BotFirstClientInRankings(),
01043 BotLastClientInRankings(),
01044 BotMapTitle(),
01045 NULL);
01046 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01047 }
01048 EasyClientName(bs->lastkilledby, name, sizeof(name));
01049 num = trap_BotNumInitialChats(bs->cs, "death_drown");
01050 for (i = 0; i < num; i++)
01051 {
01052
01053 BotAI_BotInitialChat(bs, "death_drown", name, NULL);
01054 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01055 }
01056 num = trap_BotNumInitialChats(bs->cs, "death_slime");
01057 for (i = 0; i < num; i++)
01058 {
01059 BotAI_BotInitialChat(bs, "death_slime", name, NULL);
01060 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01061 }
01062 num = trap_BotNumInitialChats(bs->cs, "death_lava");
01063 for (i = 0; i < num; i++)
01064 {
01065 BotAI_BotInitialChat(bs, "death_lava", name, NULL);
01066 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01067 }
01068 num = trap_BotNumInitialChats(bs->cs, "death_cratered");
01069 for (i = 0; i < num; i++)
01070 {
01071 BotAI_BotInitialChat(bs, "death_cratered", name, NULL);
01072 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01073 }
01074 num = trap_BotNumInitialChats(bs->cs, "death_suicide");
01075 for (i = 0; i < num; i++)
01076 {
01077 BotAI_BotInitialChat(bs, "death_suicide", name, NULL);
01078 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01079 }
01080 num = trap_BotNumInitialChats(bs->cs, "death_telefrag");
01081 for (i = 0; i < num; i++)
01082 {
01083 BotAI_BotInitialChat(bs, "death_telefrag", name, NULL);
01084 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01085 }
01086 num = trap_BotNumInitialChats(bs->cs, "death_gauntlet");
01087 for (i = 0; i < num; i++)
01088 {
01089 BotAI_BotInitialChat(bs, "death_gauntlet",
01090 name,
01091 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
01092 NULL);
01093 trap_BotEnterChat(bs->cs, 0, CHAT_ALL);
01094 }
01095 num = trap_BotNumInitialChats(bs->cs, "death_rail");
01096 for (i = 0; i < num; i++)
01097 {
01098 BotAI_BotInitialChat(bs, "death_rail",
01099 name,
01100 BotWeaponNameForMeansOfDeath(bs->botdeathtype),
01101 NULL);
01102 trap_BotEnterChat(bs->