BotLib: Add support for goalitems. These may include objectives for things

like CTF - flag your game-mode entities as either .botinfo BOTINFO_TEAM_GOALITEM
or BOTINFO_TEAM_GOALCAPTURE and BotLib will try to figure out what to do.
This commit is contained in:
Marco Cawthorne 2022-03-02 09:17:57 -08:00
parent 390f127898
commit 6db98c88aa
Signed by: eukara
GPG Key ID: C196CD8BA993248A
5 changed files with 163 additions and 30 deletions

View File

@ -39,10 +39,14 @@ bot::ChatSayTeam(string msg)
void
bot::Pain(void)
{
CGameRules rules = g_grMode;
player::Pain();
/* might as well target our attacker */
m_eTarget = g_dmg_eAttacker;
if (rules.IsTeamPlay()) {
if (g_dmg_eAttacker.flags & FL_CLIENT && g_dmg_eAttacker.team == team)
ChatSayTeam("Stop shooting me!");
}
}
void
@ -151,6 +155,8 @@ bot::UseButton(void)
void
bot::SeeThink(void)
{
CGameRules rules = (CGameRules)g_grMode;
if (m_eTarget)
return;
@ -171,7 +177,7 @@ bot::SeeThink(void)
continue;
/* ain't go hurt our brothers and sisters */
if (Rules_IsTeamPlay() == TRUE)
if (rules.IsTeamPlay() == TRUE)
if (team == w.team)
continue;
@ -221,15 +227,15 @@ bot::CheckRoute(void)
m_iCurNode--;
if (m_iCurNode >= 0) {
if (m_pRoute[m_iCurNode].m_iFlags)
print(sprintf("NODE FLAGS: %i\n", m_pRoute[m_iCurNode].m_iFlags));
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]))
dprint(sprintf("NODE FLAGS: %i\n", Route_GetNodeFlags(&m_pRoute[m_iCurNode])));
/* if a node is flagged as jumpy, jump! */
if (m_pRoute[m_iCurNode].m_iFlags & LF_JUMP)
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_JUMP)
input_buttons |= INPUT_BUTTON2;
/* find the nearest usable item (func_button) and use them */
if (m_pRoute[m_iCurNode].m_iFlags & LF_USER)
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_USER)
UseButton();
}
@ -274,7 +280,7 @@ bot::CheckRoute(void)
input_buttons |= INPUT_BUTTON2;
} else {
/* entire way-link needs to be crouched. that's the law of the land */
if (m_pRoute[m_iCurNode].m_iFlags & LF_CROUCH)
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH)
input_buttons |= INPUT_BUTTON8;
}
}
@ -344,6 +350,8 @@ bot::RunAI(void)
BrainThink(enemyvisible, enemydistant);
CheckRoute();
aimpos = [0,0,0];
if (m_iNodes) {
vector vecNewAngles;
vector vecDirection;
@ -353,7 +361,7 @@ bot::RunAI(void)
if (m_iCurNode == BOTROUTE_DESTINATION)
aimpos = m_vecLastNode;
else {
if (m_iCurNode > 0 && !(m_pRoute[m_iCurNode].m_iFlags & LF_AIM))
if (m_iCurNode > 0 && !(Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_AIM))
aimpos = m_pRoute[m_iCurNode - 1].m_vecDest;
else
aimpos = m_pRoute[m_iCurNode].m_vecDest;
@ -363,6 +371,12 @@ bot::RunAI(void)
aimpos = m_eTarget.origin;
}
/* aim ahead */
if (aimpos == [0,0,0]) {
makevectors(angles);
aimpos = origin + v_forward * 128;
}
/* lerping speed, faster when we've got a target */
if (m_eTarget && enemyvisible)
flLerp = bound(0.0f, frametime * 45, 1.0f);
@ -407,7 +421,7 @@ bot::RunAI(void)
}
/* now we'll set the movevalues relative to the input_angle */
if ((m_iCurNode >= 0 && m_pRoute[m_iCurNode].m_iFlags & LF_WALK) || m_eTarget && enemyvisible && vlen(aimpos-origin) < 512)
if ((m_iCurNode >= 0 && Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_WALK) || m_eTarget && enemyvisible && vlen(aimpos-origin) < 512)
vecDirection = normalize(aimpos - origin) * 120;
else
vecDirection = normalize(aimpos - origin) * 240;

View File

@ -14,11 +14,14 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* we need to keep this an enum so find() does its work faster */
enum
{
BOTINFO_NONE,
BOTINFO_HEALTH,
BOTINFO_ARMOR,
BOTINFO_SPAWNPOINT,
BOTINFO_END
BOTINFO_NONE, /* no info */
BOTINFO_HEALTH, /* health item */
BOTINFO_ARMOR, /* armor item */
BOTINFO_SPAWNPOINT, /* place where to find new players */
BOTINFO_TEAM_GOALITEM, /* team-mode goal item (flag, intel) */
BOTINFO_TEAM_GOALCAPTURE, /* where to go when goal-item present */
BOTINFO_END /* end destination */
};

View File

@ -17,3 +17,5 @@
int Route_RoundDistance( float flDist );
vector Route_SelectDestination( bot target );
void Bot_RouteCB( entity ent, vector dest, int numnodes, nodeslist_t *nodelist );
int Route_GetNodeFlags(nodeslist_t *node);

View File

@ -36,6 +36,76 @@ Route_RoundDistance(float flDist)
}
/* returns a botinfo point that's nearest to us */
entity
Route_SelectNearest(float type, vector org)
{
entity temp;
int bestrange = COST_INFINITE;
int range;
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
range = vlen(temp.origin - org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
dest = temp;
}
}
return dest;
}
/* returns a botinfo point belonging to our team */
entity
Route_SelectNearestTeam(float type, vector org, float tt)
{
entity temp;
int bestrange = COST_INFINITE;
int range;
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
if (temp.team != tt)
continue;
range = vlen(temp.origin - org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
dest = temp;
}
}
return dest;
}
/* returns a botinfo point belonging to the enemy team */
entity
Route_SelectNearestEnemyTeam(float type, vector org, float tt)
{
entity temp;
int bestrange = COST_INFINITE;
int range;
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
if (temp.team == tt)
continue;
range = vlen(temp.origin - org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
dest = temp;
}
}
return dest;
}
/*
================
Spawn_SelectRandom
@ -80,28 +150,72 @@ Bot_RouteCB(entity ent, vector dest, int numnodes, nodeslist_t *nodelist)
vector
Route_SelectDestination(bot target)
{
CGameRules rules;
rules = (CGameRules)g_grMode;
entity dest = world;
if (target.health < 50) {
entity temp;
int bestrange = COST_INFINITE;
int range;
for (temp = world; (temp = findfloat(temp, ::botinfo, BOTINFO_HEALTH));) {
range = vlen(temp.origin - target.origin);
if ((range < bestrange) && (temp.solid == SOLID_TRIGGER)) {
bestrange = range;
dest = temp;
if (rules.IsTeamPlay()) {
/* we have the goal item, so capture it */
if (target.flags & FL_GOALITEM) {
print(sprintf("%s going for capture\n", target.netname));
dest = Route_SelectNearestTeam(BOTINFO_TEAM_GOALCAPTURE, target.origin, target.team);
/* we may have to go to our teams' goal item then */
if (!dest) {
dest = Route_SelectNearestTeam(BOTINFO_TEAM_GOALITEM, target.origin, target.team);
}
} else {
print(sprintf("%s hunting for goal item\n", target.netname));
dest = Route_SelectNearestEnemyTeam(BOTINFO_TEAM_GOALITEM, target.origin, target.team);
}
if (dest) {
//dprint("Route: Going for health!");
return (dest.origin + [0,0,32]);
}
if (dest)
return dest.origin + [0,0,32];
print(sprintf("%s can't figure out where to go for the goal\n", target.netname));
}
/* if we're low on health, look for health items */
if (target.health < 50) {
print(sprintf("%s going for health\n", target.netname));
dest = Route_SelectNearest(BOTINFO_HEALTH, target.origin);
if (dest)
return dest.origin + [0,0,32];
print(sprintf("%s can't figure out where to go for health\n", target.netname));
}
/* armor is always a good idea to have */
if (target.armor < 50) {
print(sprintf("%s going for armor\n", target.netname));
dest = Route_SelectNearest(BOTINFO_ARMOR, target.origin);
if (dest)
return dest.origin + [0,0,32];
print(sprintf("%s can't figure out where to go for armor\n", target.netname));
}
/* if all else fails... select a random spot */
print(sprintf("%s found nothing, going for random PoI\n", target.netname));
dest = Route_SelectRandomSpot();
target.m_eDestination = dest;
return (dest.origin);
}
int
Route_GetNodeFlags(nodeslist_t *node)
{
int fl = node.m_iFlags;
/* to avoid random buttons being pressed */
if (fl == LF_DESTINATION)
return 0;
else if (fl == -1i)
return 0;
else
return fl;
}

View File

@ -40,4 +40,4 @@
#define FL_NOATTACK (1<<21)
#define FL_ONUSABLE (1<<22)
#define FL_ONFIRE (1<<23)
#define FL_RESERVED3 (1<<15)
#define FL_GOALITEM (1<<15)