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:
parent
390f127898
commit
6db98c88aa
5 changed files with 163 additions and 30 deletions
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue