📄 ai_dmq3.c
字号:
ClientSkin
==================
*/
char *ClientSkin(int client, char *skin, int size) {
char buf[MAX_INFO_STRING];
if (client < 0 || client >= MAX_CLIENTS) {
BotAI_Print(PRT_ERROR, "ClientSkin: client out of range\n");
return "[client out of range]";
}
trap_GetConfigstring(CS_PLAYERS+client, buf, sizeof(buf));
strncpy(skin, Info_ValueForKey(buf, "model"), size-1);
skin[size-1] = '\0';
return skin;
}
/*
==================
ClientFromName
==================
*/
int ClientFromName(char *name) {
int i;
char buf[MAX_INFO_STRING];
static int maxclients;
if (!maxclients)
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
Q_CleanStr( buf );
if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
}
return -1;
}
/*
==================
ClientOnSameTeamFromName
==================
*/
int ClientOnSameTeamFromName(bot_state_t *bs, char *name) {
int i;
char buf[MAX_INFO_STRING];
static int maxclients;
if (!maxclients)
maxclients = trap_Cvar_VariableIntegerValue("sv_maxclients");
for (i = 0; i < maxclients && i < MAX_CLIENTS; i++) {
if (!BotSameTeam(bs, i))
continue;
trap_GetConfigstring(CS_PLAYERS+i, buf, sizeof(buf));
Q_CleanStr( buf );
if (!Q_stricmp(Info_ValueForKey(buf, "n"), name)) return i;
}
return -1;
}
/*
==================
stristr
==================
*/
char *stristr(char *str, char *charset) {
int i;
while(*str) {
for (i = 0; charset[i] && str[i]; i++) {
if (toupper(charset[i]) != toupper(str[i])) break;
}
if (!charset[i]) return str;
str++;
}
return NULL;
}
/*
==================
EasyClientName
==================
*/
char *EasyClientName(int client, char *buf, int size) {
int i;
char *str1, *str2, *ptr, c;
char name[128];
strcpy(name, ClientName(client, name, sizeof(name)));
for (i = 0; name[i]; i++) name[i] &= 127;
//remove all spaces
for (ptr = strstr(name, " "); ptr; ptr = strstr(name, " ")) {
memmove(ptr, ptr+1, strlen(ptr+1)+1);
}
//check for [x] and ]x[ clan names
str1 = strstr(name, "[");
str2 = strstr(name, "]");
if (str1 && str2) {
if (str2 > str1) memmove(str1, str2+1, strlen(str2+1)+1);
else memmove(str2, str1+1, strlen(str1+1)+1);
}
//remove Mr prefix
if ((name[0] == 'm' || name[0] == 'M') &&
(name[1] == 'r' || name[1] == 'R')) {
memmove(name, name+2, strlen(name+2)+1);
}
//only allow lower case alphabet characters
ptr = name;
while(*ptr) {
c = *ptr;
if ((c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') || c == '_') {
ptr++;
}
else if (c >= 'A' && c <= 'Z') {
*ptr += 'a' - 'A';
ptr++;
}
else {
memmove(ptr, ptr+1, strlen(ptr + 1)+1);
}
}
strncpy(buf, name, size-1);
buf[size-1] = '\0';
return buf;
}
/*
==================
BotSynonymContext
==================
*/
int BotSynonymContext(bot_state_t *bs) {
int context;
context = CONTEXT_NORMAL|CONTEXT_NEARBYITEM|CONTEXT_NAMES;
//
if (gametype == GT_CTF
#ifdef MISSIONPACK
|| gametype == GT_1FCTF
#endif
) {
if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_CTFREDTEAM;
else context |= CONTEXT_CTFBLUETEAM;
}
#ifdef MISSIONPACK
else if (gametype == GT_OBELISK) {
if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_OBELISKREDTEAM;
else context |= CONTEXT_OBELISKBLUETEAM;
}
else if (gametype == GT_HARVESTER) {
if (BotTeam(bs) == TEAM_RED) context |= CONTEXT_HARVESTERREDTEAM;
else context |= CONTEXT_HARVESTERBLUETEAM;
}
#endif
return context;
}
/*
==================
BotChooseWeapon
==================
*/
void BotChooseWeapon(bot_state_t *bs) {
int newweaponnum;
if (bs->cur_ps.weaponstate == WEAPON_RAISING ||
bs->cur_ps.weaponstate == WEAPON_DROPPING) {
trap_EA_SelectWeapon(bs->client, bs->weaponnum);
}
else {
newweaponnum = trap_BotChooseBestFightWeapon(bs->ws, bs->inventory);
if (bs->weaponnum != newweaponnum) bs->weaponchange_time = FloatTime();
bs->weaponnum = newweaponnum;
//BotAI_Print(PRT_MESSAGE, "bs->weaponnum = %d\n", bs->weaponnum);
trap_EA_SelectWeapon(bs->client, bs->weaponnum);
}
}
/*
==================
BotSetupForMovement
==================
*/
void BotSetupForMovement(bot_state_t *bs) {
bot_initmove_t initmove;
memset(&initmove, 0, sizeof(bot_initmove_t));
VectorCopy(bs->cur_ps.origin, initmove.origin);
VectorCopy(bs->cur_ps.velocity, initmove.velocity);
VectorClear(initmove.viewoffset);
initmove.viewoffset[2] += bs->cur_ps.viewheight;
initmove.entitynum = bs->entitynum;
initmove.client = bs->client;
initmove.thinktime = bs->thinktime;
//set the onground flag
if (bs->cur_ps.groundEntityNum != ENTITYNUM_NONE) initmove.or_moveflags |= MFL_ONGROUND;
//set the teleported flag
if ((bs->cur_ps.pm_flags & PMF_TIME_KNOCKBACK) && (bs->cur_ps.pm_time > 0)) {
initmove.or_moveflags |= MFL_TELEPORTED;
}
//set the waterjump flag
if ((bs->cur_ps.pm_flags & PMF_TIME_WATERJUMP) && (bs->cur_ps.pm_time > 0)) {
initmove.or_moveflags |= MFL_WATERJUMP;
}
//set presence type
if (bs->cur_ps.pm_flags & PMF_DUCKED) initmove.presencetype = PRESENCE_CROUCH;
else initmove.presencetype = PRESENCE_NORMAL;
//
if (bs->walker > 0.5) initmove.or_moveflags |= MFL_WALK;
//
VectorCopy(bs->viewangles, initmove.viewangles);
//
trap_BotInitMoveState(bs->ms, &initmove);
}
/*
==================
BotCheckItemPickup
==================
*/
void BotCheckItemPickup(bot_state_t *bs, int *oldinventory) {
#ifdef MISSIONPACK
int offence, leader;
if (gametype <= GT_TEAM)
return;
offence = -1;
// go into offence if picked up the kamikaze or invulnerability
if (!oldinventory[INVENTORY_KAMIKAZE] && bs->inventory[INVENTORY_KAMIKAZE] >= 1) {
offence = qtrue;
}
if (!oldinventory[INVENTORY_INVULNERABILITY] && bs->inventory[INVENTORY_INVULNERABILITY] >= 1) {
offence = qtrue;
}
// if not already wearing the kamikaze or invulnerability
if (!bs->inventory[INVENTORY_KAMIKAZE] && !bs->inventory[INVENTORY_INVULNERABILITY]) {
if (!oldinventory[INVENTORY_SCOUT] && bs->inventory[INVENTORY_SCOUT] >= 1) {
offence = qtrue;
}
if (!oldinventory[INVENTORY_GUARD] && bs->inventory[INVENTORY_GUARD] >= 1) {
offence = qtrue;
}
if (!oldinventory[INVENTORY_DOUBLER] && bs->inventory[INVENTORY_DOUBLER] >= 1) {
offence = qfalse;
}
if (!oldinventory[INVENTORY_AMMOREGEN] && bs->inventory[INVENTORY_AMMOREGEN] >= 1) {
offence = qfalse;
}
}
if (offence >= 0) {
leader = ClientFromName(bs->teamleader);
if (offence) {
if (!(bs->teamtaskpreference & TEAMTP_ATTACKER)) {
// if we have a bot team leader
if (BotTeamLeader(bs)) {
// tell the leader we want to be on offence
BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
//BotAI_BotInitialChat(bs, "wantoffence", NULL);
//trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
}
else if (g_spSkill.integer <= 3) {
if ( bs->ltgtype != LTG_GETFLAG &&
bs->ltgtype != LTG_ATTACKENEMYBASE &&
bs->ltgtype != LTG_HARVEST ) {
//
if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) &&
(gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) {
// tell the leader we want to be on offence
BotVoiceChat(bs, leader, VOICECHAT_WANTONOFFENSE);
//BotAI_BotInitialChat(bs, "wantoffence", NULL);
//trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
}
}
bs->teamtaskpreference |= TEAMTP_ATTACKER;
}
}
bs->teamtaskpreference &= ~TEAMTP_DEFENDER;
}
else {
if (!(bs->teamtaskpreference & TEAMTP_DEFENDER)) {
// if we have a bot team leader
if (BotTeamLeader(bs)) {
// tell the leader we want to be on defense
BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
//BotAI_BotInitialChat(bs, "wantdefence", NULL);
//trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
}
else if (g_spSkill.integer <= 3) {
if ( bs->ltgtype != LTG_DEFENDKEYAREA ) {
//
if ((gametype != GT_CTF || (bs->redflagstatus == 0 && bs->blueflagstatus == 0)) &&
(gametype != GT_1FCTF || bs->neutralflagstatus == 0) ) {
// tell the leader we want to be on defense
BotVoiceChat(bs, -1, VOICECHAT_WANTONDEFENSE);
//BotAI_BotInitialChat(bs, "wantdefence", NULL);
//trap_BotEnterChat(bs->cs, leader, CHAT_TELL);
}
}
}
bs->teamtaskpreference |= TEAMTP_DEFENDER;
}
bs->teamtaskpreference &= ~TEAMTP_ATTACKER;
}
}
#endif
}
/*
==================
BotUpdateInventory
==================
*/
void BotUpdateInventory(bot_state_t *bs) {
int oldinventory[MAX_ITEMS];
memcpy(oldinventory, bs->inventory, sizeof(oldinventory));
//armor
bs->inventory[INVENTORY_ARMOR] = bs->cur_ps.stats[STAT_ARMOR];
//weapons
bs->inventory[INVENTORY_GAUNTLET] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GAUNTLET)) != 0;
bs->inventory[INVENTORY_SHOTGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_SHOTGUN)) != 0;
bs->inventory[INVENTORY_MACHINEGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_MACHINEGUN)) != 0;
bs->inventory[INVENTORY_GRENADELAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRENADE_LAUNCHER)) != 0;
bs->inventory[INVENTORY_ROCKETLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_ROCKET_LAUNCHER)) != 0;
bs->inventory[INVENTORY_LIGHTNING] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_LIGHTNING)) != 0;
bs->inventory[INVENTORY_RAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_RAILGUN)) != 0;
bs->inventory[INVENTORY_PLASMAGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PLASMAGUN)) != 0;
bs->inventory[INVENTORY_BFG10K] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_BFG)) != 0;
bs->inventory[INVENTORY_GRAPPLINGHOOK] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_GRAPPLING_HOOK)) != 0;
#ifdef MISSIONPACK
bs->inventory[INVENTORY_NAILGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_NAILGUN)) != 0;;
bs->inventory[INVENTORY_PROXLAUNCHER] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_PROX_LAUNCHER)) != 0;;
bs->inventory[INVENTORY_CHAINGUN] = (bs->cur_ps.stats[STAT_WEAPONS] & (1 << WP_CHAINGUN)) != 0;;
#endif
//ammo
bs->inventory[INVENTORY_SHELLS] = bs->cur_ps.ammo[WP_SHOTGUN];
bs->inventory[INVENTORY_BULLETS] = bs->cur_ps.ammo[WP_MACHINEGUN];
bs->inventory[INVENTORY_GRENADES] = bs->cur_ps.ammo[WP_GRENADE_LAUNCHER];
bs->inventory[INVENTORY_CELLS] = bs->cur_ps.ammo[WP_PLASMAGUN];
bs->inventory[INVENTORY_LIGHTNINGAMMO] = bs->cur_ps.ammo[WP_LIGHTNING];
bs->inventory[INVENTORY_ROCKETS] = bs->cur_ps.ammo[WP_ROCKET_LAUNCHER];
bs->inventory[INVENTORY_SLUGS] = bs->cur_ps.ammo[WP_RAILGUN];
bs->inventory[INVENTORY_BFGAMMO] = bs->cur_ps.ammo[WP_BFG];
#ifdef MISSIONPACK
bs->inventory[INVENTORY_NAILS] = bs->cur_ps.ammo[WP_NAILGUN];
bs->inventory[INVENTORY_MINES] = bs->cur_ps.ammo[WP_PROX_LAUNCHER];
bs->inventory[INVENTORY_BELT] = bs->cur_ps.ammo[WP_CHAINGUN];
#endif
//powerups
bs->inventory[INVENTORY_HEALTH] = bs->cur_ps.stats[STAT_HEALTH];
bs->inventory[INVENTORY_TELEPORTER] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_TELEPORTER;
bs->inventory[INVENTORY_MEDKIT] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_MEDKIT;
#ifdef MISSIONPACK
bs->inventory[INVENTORY_KAMIKAZE] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_KAMIKAZE;
bs->inventory[INVENTORY_PORTAL] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_PORTAL;
bs->inventory[INVENTORY_INVULNERABILITY] = bs->cur_ps.stats[STAT_HOLDABLE_ITEM] == MODELINDEX_INVULNERABILITY;
#endif
bs->inventory[INVENTORY_QUAD] = bs->cur_ps.powerups[PW_QUAD] != 0;
bs->inventory[INVENTORY_ENVIRONMENTSUIT] = bs->cur_ps.powerups[PW_BATTLESUIT] != 0;
bs->inventory[INVENTORY_HASTE] = bs->cur_ps.powerups[PW_HASTE] != 0;
bs->inventory[INVENTORY_INVISIBILITY] = bs->cur_ps.powerups[PW_INVIS] != 0;
bs->inventory[INVENTORY_REGEN] = bs->cur_ps.powerups[PW_REGEN] != 0;
bs->inventory[INVENTORY_FLIGHT] = bs->cur_ps.powerups[PW_FLIGHT] != 0;
#ifdef MISSIONPACK
bs->inventory[INVENTORY_SCOUT] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_SCOUT;
bs->inventory[INVENTORY_GUARD] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_GUARD;
bs->inventory[INVENTORY_DOUBLER] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_DOUBLER;
bs->inventory[INVENTORY_AMMOREGEN] = bs->cur_ps.stats[STAT_PERSISTANT_POWERUP] == MODELINDEX_AMMOREGEN;
#endif
bs->inventory[INVENTORY_REDFLAG] = bs->cur_ps.powerups[PW_REDFLAG] != 0;
bs->inventory[INVENTORY_BLUEFLAG] = bs->cur_ps.powerups[PW_BLUEFLAG] != 0;
#ifdef MISSIONPACK
bs->inventory[INVENTORY_NEUTRALFLAG] = bs->cur_ps.powerups[PW_NEUTRALFLAG] != 0;
if (BotTeam(bs) == TEAM_RED) {
bs->inventory[INVENTORY_REDCUBE] = bs->cur_ps.generic1;
bs->inventory[INVENTORY_BLUECUBE] = 0;
}
else {
bs->inventory[INVENTORY_REDCUBE] = 0;
bs->inventory[INVENTORY_BLUECUBE] = bs->cur_ps.generic1;
}
#endif
BotCheckItemPickup(bs, oldinventory);
}
/*
==================
BotUpdateBattleInventory
==================
*/
void BotUpdateBattleInventory(bot_state_t *bs, int enemy) {
vec3_t dir;
aas_entityinfo_t entinfo;
BotEntityInfo(enemy, &entinfo);
VectorSubtract(entinfo.origin, bs->origin, dir);
bs->inventory[ENEMY_HEIGHT] = (int) dir[2];
dir[2] = 0;
bs->inventory[ENEMY_HORIZONTAL_DIST] = (int) VectorLength(dir);
//FIXME: add num visible enemies and num visible team mates to the inventory
}
#ifdef MISSIONPACK
/*
==================
BotUseKamikaze
==================
*/
#define KAMIKAZE_DIST 1024
void BotUseKamikaze(bot_state_t *bs) {
int c, teammates, enemies;
aas_entityinfo_t entinfo;
vec3_t dir, target;
bot_goal_t *goal;
bsp_trace_t trace;
//if the bot has no kamikaze
if (bs->inventory[INVENTORY_KAMIKAZE] <= 0)
return;
if (bs->kamikaze_time > FloatTime())
return;
bs->kamikaze_time = FloatTime() + 0.2;
if (gametype == GT_CTF) {
//never use kamikaze if the team flag carrier is visible
if (BotCTFCarryingFlag(bs))
return;
c = BotTeamFlagCarrierVisible(bs);
if (c >= 0) {
BotEntityInfo(c, &entinfo);
VectorSubtract(entinfo.origin, bs->origin, dir);
if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
return;
}
c = BotEnemyFlagCarrierVisible(bs);
if (c >= 0) {
BotEntityInfo(c, &entinfo);
VectorSubtract(entinfo.origin, bs->origin, dir);
if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
trap_EA_Use(bs->client);
return;
}
}
}
else if (gametype == GT_1FCTF) {
//never use kamikaze if the team flag carrier is visible
if (Bot1FCTFCarryingFlag(bs))
return;
c = BotTeamFlagCarrierVisible(bs);
if (c >= 0) {
BotEntityInfo(c, &entinfo);
VectorSubtract(entinfo.origin, bs->origin, dir);
if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST))
return;
}
c = BotEnemyFlagCarrierVisible(bs);
if (c >= 0) {
BotEntityInfo(c, &entinfo);
VectorSubtract(entinfo.origin, bs->origin, dir);
if (VectorLengthSquared(dir) < Square(KAMIKAZE_DIST)) {
trap_EA_Use(bs->client);
return;
}
}
}
else if (gametype == GT_OBELISK) {
switch(BotTeam(bs)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -