📄 ai_dmq3.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
/*****************************************************************************
* name: ai_dmq3.c
*
* desc: Quake3 bot AI
*
* $Archive: /MissionPack/code/game/ai_dmq3.c $
*
*****************************************************************************/
#include "g_local.h"
#include "botlib.h"
#include "be_aas.h"
#include "be_ea.h"
#include "be_ai_char.h"
#include "be_ai_chat.h"
#include "be_ai_gen.h"
#include "be_ai_goal.h"
#include "be_ai_move.h"
#include "be_ai_weap.h"
//
#include "ai_main.h"
#include "ai_dmq3.h"
#include "ai_chat.h"
#include "ai_cmd.h"
#include "ai_dmnet.h"
#include "ai_team.h"
//
#include "chars.h" //characteristics
#include "inv.h" //indexes into the inventory
#include "syn.h" //synonyms
#include "match.h" //string matching types and vars
// for the voice chats
#include "../../ui/menudef.h" // sos001205 - for q3_ui also
// from aasfile.h
#define AREACONTENTS_MOVER 1024
#define AREACONTENTS_MODELNUMSHIFT 24
#define AREACONTENTS_MAXMODELNUM 0xFF
#define AREACONTENTS_MODELNUM (AREACONTENTS_MAXMODELNUM << AREACONTENTS_MODELNUMSHIFT)
#define IDEAL_ATTACKDIST 140
#define MAX_WAYPOINTS 128
//
bot_waypoint_t botai_waypoints[MAX_WAYPOINTS];
bot_waypoint_t *botai_freewaypoints;
//NOTE: not using a cvars which can be updated because the game should be reloaded anyway
int gametype; //game type
int maxclients; //maximum number of clients
vmCvar_t bot_grapple;
vmCvar_t bot_rocketjump;
vmCvar_t bot_fastchat;
vmCvar_t bot_nochat;
vmCvar_t bot_testrchat;
vmCvar_t bot_challenge;
vmCvar_t bot_predictobstacles;
vmCvar_t g_spSkill;
extern vmCvar_t bot_developer;
vec3_t lastteleport_origin; //last teleport event origin
float lastteleport_time; //last teleport event time
int max_bspmodelindex; //maximum BSP model index
//CTF flag goals
bot_goal_t ctf_redflag;
bot_goal_t ctf_blueflag;
#ifdef MISSIONPACK
bot_goal_t ctf_neutralflag;
bot_goal_t redobelisk;
bot_goal_t blueobelisk;
bot_goal_t neutralobelisk;
#endif
#define MAX_ALTROUTEGOALS 32
int altroutegoals_setup;
aas_altroutegoal_t red_altroutegoals[MAX_ALTROUTEGOALS];
int red_numaltroutegoals;
aas_altroutegoal_t blue_altroutegoals[MAX_ALTROUTEGOALS];
int blue_numaltroutegoals;
/*
==================
BotSetUserInfo
==================
*/
void BotSetUserInfo(bot_state_t *bs, char *key, char *value) {
char userinfo[MAX_INFO_STRING];
trap_GetUserinfo(bs->client, userinfo, sizeof(userinfo));
Info_SetValueForKey(userinfo, key, value);
trap_SetUserinfo(bs->client, userinfo);
ClientUserinfoChanged( bs->client );
}
/*
==================
BotCTFCarryingFlag
==================
*/
int BotCTFCarryingFlag(bot_state_t *bs) {
if (gametype != GT_CTF) return CTF_FLAG_NONE;
if (bs->inventory[INVENTORY_REDFLAG] > 0) return CTF_FLAG_RED;
else if (bs->inventory[INVENTORY_BLUEFLAG] > 0) return CTF_FLAG_BLUE;
return CTF_FLAG_NONE;
}
/*
==================
BotTeam
==================
*/
int BotTeam(bot_state_t *bs) {
char info[1024];
if (bs->client < 0 || bs->client >= MAX_CLIENTS) {
//BotAI_Print(PRT_ERROR, "BotCTFTeam: client out of range\n");
return qfalse;
}
trap_GetConfigstring(CS_PLAYERS+bs->client, info, sizeof(info));
//
if (atoi(Info_ValueForKey(info, "t")) == TEAM_RED) return TEAM_RED;
else if (atoi(Info_ValueForKey(info, "t")) == TEAM_BLUE) return TEAM_BLUE;
return TEAM_FREE;
}
/*
==================
BotOppositeTeam
==================
*/
int BotOppositeTeam(bot_state_t *bs) {
switch(BotTeam(bs)) {
case TEAM_RED: return TEAM_BLUE;
case TEAM_BLUE: return TEAM_RED;
default: return TEAM_FREE;
}
}
/*
==================
BotEnemyFlag
==================
*/
bot_goal_t *BotEnemyFlag(bot_state_t *bs) {
if (BotTeam(bs) == TEAM_RED) {
return &ctf_blueflag;
}
else {
return &ctf_redflag;
}
}
/*
==================
BotTeamFlag
==================
*/
bot_goal_t *BotTeamFlag(bot_state_t *bs) {
if (BotTeam(bs) == TEAM_RED) {
return &ctf_redflag;
}
else {
return &ctf_blueflag;
}
}
/*
==================
EntityIsDead
==================
*/
qboolean EntityIsDead(aas_entityinfo_t *entinfo) {
playerState_t ps;
if (entinfo->number >= 0 && entinfo->number < MAX_CLIENTS) {
//retrieve the current client state
BotAI_GetClientState( entinfo->number, &ps );
if (ps.pm_type != PM_NORMAL) return qtrue;
}
return qfalse;
}
/*
==================
EntityCarriesFlag
==================
*/
qboolean EntityCarriesFlag(aas_entityinfo_t *entinfo) {
if ( entinfo->powerups & ( 1 << PW_REDFLAG ) )
return qtrue;
if ( entinfo->powerups & ( 1 << PW_BLUEFLAG ) )
return qtrue;
#ifdef MISSIONPACK
if ( entinfo->powerups & ( 1 << PW_NEUTRALFLAG ) )
return qtrue;
#endif
return qfalse;
}
/*
==================
EntityIsInvisible
==================
*/
qboolean EntityIsInvisible(aas_entityinfo_t *entinfo) {
// the flag is always visible
if (EntityCarriesFlag(entinfo)) {
return qfalse;
}
if (entinfo->powerups & (1 << PW_INVIS)) {
return qtrue;
}
return qfalse;
}
/*
==================
EntityIsShooting
==================
*/
qboolean EntityIsShooting(aas_entityinfo_t *entinfo) {
if (entinfo->flags & EF_FIRING) {
return qtrue;
}
return qfalse;
}
/*
==================
EntityIsChatting
==================
*/
qboolean EntityIsChatting(aas_entityinfo_t *entinfo) {
if (entinfo->flags & EF_TALK) {
return qtrue;
}
return qfalse;
}
/*
==================
EntityHasQuad
==================
*/
qboolean EntityHasQuad(aas_entityinfo_t *entinfo) {
if (entinfo->powerups & (1 << PW_QUAD)) {
return qtrue;
}
return qfalse;
}
#ifdef MISSIONPACK
/*
==================
EntityHasKamikze
==================
*/
qboolean EntityHasKamikaze(aas_entityinfo_t *entinfo) {
if (entinfo->flags & EF_KAMIKAZE) {
return qtrue;
}
return qfalse;
}
/*
==================
EntityCarriesCubes
==================
*/
qboolean EntityCarriesCubes(aas_entityinfo_t *entinfo) {
entityState_t state;
if (gametype != GT_HARVESTER)
return qfalse;
//FIXME: get this info from the aas_entityinfo_t ?
BotAI_GetEntityState(entinfo->number, &state);
if (state.generic1 > 0)
return qtrue;
return qfalse;
}
/*
==================
Bot1FCTFCarryingFlag
==================
*/
int Bot1FCTFCarryingFlag(bot_state_t *bs) {
if (gametype != GT_1FCTF) return qfalse;
if (bs->inventory[INVENTORY_NEUTRALFLAG] > 0) return qtrue;
return qfalse;
}
/*
==================
BotHarvesterCarryingCubes
==================
*/
int BotHarvesterCarryingCubes(bot_state_t *bs) {
if (gametype != GT_HARVESTER) return qfalse;
if (bs->inventory[INVENTORY_REDCUBE] > 0) return qtrue;
if (bs->inventory[INVENTORY_BLUECUBE] > 0) return qtrue;
return qfalse;
}
#endif
/*
==================
BotRememberLastOrderedTask
==================
*/
void BotRememberLastOrderedTask(bot_state_t *bs) {
if (!bs->ordered) {
return;
}
bs->lastgoal_decisionmaker = bs->decisionmaker;
bs->lastgoal_ltgtype = bs->ltgtype;
memcpy(&bs->lastgoal_teamgoal, &bs->teamgoal, sizeof(bot_goal_t));
bs->lastgoal_teammate = bs->teammate;
}
/*
==================
BotSetTeamStatus
==================
*/
void BotSetTeamStatus(bot_state_t *bs) {
#ifdef MISSIONPACK
int teamtask;
aas_entityinfo_t entinfo;
teamtask = TEAMTASK_PATROL;
switch(bs->ltgtype) {
case LTG_TEAMHELP:
break;
case LTG_TEAMACCOMPANY:
BotEntityInfo(bs->teammate, &entinfo);
if ( ( (gametype == GT_CTF || gametype == GT_1FCTF) && EntityCarriesFlag(&entinfo))
|| ( gametype == GT_HARVESTER && EntityCarriesCubes(&entinfo)) ) {
teamtask = TEAMTASK_ESCORT;
}
else {
teamtask = TEAMTASK_FOLLOW;
}
break;
case LTG_DEFENDKEYAREA:
teamtask = TEAMTASK_DEFENSE;
break;
case LTG_GETFLAG:
teamtask = TEAMTASK_OFFENSE;
break;
case LTG_RUSHBASE:
teamtask = TEAMTASK_DEFENSE;
break;
case LTG_RETURNFLAG:
teamtask = TEAMTASK_RETRIEVE;
break;
case LTG_CAMP:
case LTG_CAMPORDER:
teamtask = TEAMTASK_CAMP;
break;
case LTG_PATROL:
teamtask = TEAMTASK_PATROL;
break;
case LTG_GETITEM:
teamtask = TEAMTASK_PATROL;
break;
case LTG_KILL:
teamtask = TEAMTASK_PATROL;
break;
case LTG_HARVEST:
teamtask = TEAMTASK_OFFENSE;
break;
case LTG_ATTACKENEMYBASE:
teamtask = TEAMTASK_OFFENSE;
break;
default:
teamtask = TEAMTASK_PATROL;
break;
}
BotSetUserInfo(bs, "teamtask", va("%d", teamtask));
#endif
}
/*
==================
BotSetLastOrderedTask
==================
*/
int BotSetLastOrderedTask(bot_state_t *bs) {
if (gametype == GT_CTF) {
// don't go back to returning the flag if it's at the base
if ( bs->lastgoal_ltgtype == LTG_RETURNFLAG ) {
if ( BotTeam(bs) == TEAM_RED ) {
if ( bs->redflagstatus == 0 ) {
bs->lastgoal_ltgtype = 0;
}
}
else {
if ( bs->blueflagstatus == 0 ) {
bs->lastgoal_ltgtype = 0;
}
}
}
}
if ( bs->lastgoal_ltgtype ) {
bs->decisionmaker = bs->lastgoal_decisionmaker;
bs->ordered = qtrue;
bs->ltgtype = bs->lastgoal_ltgtype;
memcpy(&bs->teamgoal, &bs->lastgoal_teamgoal, sizeof(bot_goal_t));
bs->teammate = bs->lastgoal_teammate;
bs->teamgoal_time = FloatTime() + 300;
BotSetTeamStatus(bs);
//
if ( gametype == GT_CTF ) {
if ( bs->ltgtype == LTG_GETFLAG ) {
bot_goal_t *tb, *eb;
int tt, et;
tb = BotTeamFlag(bs);
eb = BotEnemyFlag(bs);
tt = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, tb->areanum, TFL_DEFAULT);
et = trap_AAS_AreaTravelTimeToGoalArea(bs->areanum, bs->origin, eb->areanum, TFL_DEFAULT);
// if the travel time towards the enemy base is larger than towards our base
if (et > tt) {
//get an alternative route goal towards the enemy base
BotGetAlternateRouteGoal(bs, BotOppositeTeam(bs));
}
}
}
return qtrue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -