BotLib: Prematurely commit all this new nav-stuff because some people like
to compile their games.
This commit is contained in:
parent
e437550c73
commit
bbfc8c945c
5 changed files with 191 additions and 46 deletions
|
@ -47,12 +47,6 @@ class player:base_player
|
|||
PREDICTED_INT(mode_tempstate);
|
||||
|
||||
#ifdef CLIENT
|
||||
/* External model */
|
||||
entity p_model;
|
||||
int p_hand_bone;
|
||||
int p_model_bone;
|
||||
float lastweapon;
|
||||
|
||||
virtual void(void) draw;
|
||||
virtual float() predraw;
|
||||
virtual void(void) postdraw;
|
||||
|
|
|
@ -63,6 +63,7 @@ class bot:player
|
|||
/* cache, these are just here so we won't have to calc them often */
|
||||
float m_flEnemyDist;
|
||||
weapontype_t m_wtWeaponType;
|
||||
vector m_vecLastPOI;
|
||||
|
||||
void(void) bot;
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
void SV_SendChat(entity sender, string msg, entity eEnt, float fType);
|
||||
|
||||
|
||||
botstate_t
|
||||
bot::GetState(void)
|
||||
{
|
||||
|
@ -57,6 +56,7 @@ bot::RouteClear(void)
|
|||
m_iNodes = 0;
|
||||
m_flNodeGiveup = 0.0f;
|
||||
memfree(m_pRoute);
|
||||
print(sprintf("%s cleared his route.\n", netname));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -180,8 +180,8 @@ void
|
|||
bot::CheckRoute(void)
|
||||
{
|
||||
float flDist;
|
||||
vector evenpos;
|
||||
float rad;
|
||||
vector vecEndPos;
|
||||
float flRadius;
|
||||
|
||||
if (!m_iNodes) {
|
||||
return;
|
||||
|
@ -189,17 +189,24 @@ bot::CheckRoute(void)
|
|||
|
||||
/* level out position/node stuff */
|
||||
if (m_iCurNode < 0) {
|
||||
evenpos = m_vecLastNode - origin;
|
||||
rad = 128; /* destination is not a node, therefore has a virtual radius */
|
||||
vecEndPos = m_vecLastNode;
|
||||
flRadius = 128; /* destination is not a node, therefore has a virtual radius */
|
||||
} else {
|
||||
evenpos = m_pRoute[m_iCurNode].m_vecDest - origin;
|
||||
rad = m_pRoute[m_iCurNode].m_flRadius;
|
||||
vecEndPos = m_pRoute[m_iCurNode].m_vecDest;
|
||||
flRadius = m_pRoute[m_iCurNode].m_flRadius;
|
||||
}
|
||||
|
||||
flDist = floor(vlen(evenpos));
|
||||
/* we need to have a sensible radius */
|
||||
if (flRadius <= 16)
|
||||
flRadius = 16.0f;
|
||||
|
||||
/* we only check if we've moved anywhere on the X/Y axis */
|
||||
flDist = floor(vlen([vecEndPos[0],vecEndPos[1],origin[2]] - origin));
|
||||
|
||||
// print(sprintf("%s node dist: %d; radius: %d\n", netname, flDist, rad));
|
||||
|
||||
/* we're inside the radius */
|
||||
if (flDist <= rad) {
|
||||
if (flDist <= flRadius) {
|
||||
dprint(sprintf("^2bot::^3CheckRoute^7: " \
|
||||
"%s reached node\n", this.targetname));
|
||||
m_iCurNode--;
|
||||
|
@ -207,28 +214,32 @@ bot::CheckRoute(void)
|
|||
/* if we're inside an actual node (not a virtual one */
|
||||
if (m_iCurNode >= 0) {
|
||||
/* if a node is flagged as jumpy, jump! */
|
||||
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_JUMP)
|
||||
input_buttons |= INPUT_BUTTON2;
|
||||
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_JUMP) {
|
||||
//input_buttons |= INPUT_BUTTON2;
|
||||
velocity = Route_GetJumpVelocity(origin, m_pRoute[m_iCurNode].m_vecDest, gravity);
|
||||
}
|
||||
|
||||
/* find the nearest usable item (func_button) and use them */
|
||||
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_USER)
|
||||
UseButton();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* we've still traveling and from this node we may be able to walk
|
||||
* directly to our end-destination */
|
||||
if (m_iCurNode > -1) {
|
||||
tracebox(origin, mins, maxs, m_vecLastNode, MOVE_NORMAL, this);
|
||||
tracebox(origin, mins, maxs, vecEndPos, MOVE_NORMAL, this);
|
||||
|
||||
/* can we walk directly to our target destination? */
|
||||
if (trace_fraction == 1.0) {
|
||||
dprint("^2bot::^3CheckRoute^7: " \
|
||||
print("^2bot::^3CheckRoute^7: " \
|
||||
"Walking directly to last node\n");
|
||||
m_iCurNode = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else { /* we're not near the node quite yet */
|
||||
traceline(origin, m_pRoute[m_iCurNode].m_vecDest, MOVE_NORMAL, this);
|
||||
traceline(origin, vecEndPos, MOVE_NORMAL, this);
|
||||
|
||||
/* we can't trace against our next node... that should never happen */
|
||||
if (trace_fraction != 1.0f) {
|
||||
|
@ -248,10 +259,14 @@ bot::CheckRoute(void)
|
|||
|
||||
/* after one second, also give up the route */
|
||||
if (m_flNodeGiveup >= 1.0f || m_iCurNode <= BOTROUTE_END) {
|
||||
print("taking too long! giving up!\n");
|
||||
RouteClear();
|
||||
} else if (m_flNodeGiveup >= 0.5f) {
|
||||
/* attempt a jump after half a second */
|
||||
input_buttons |= INPUT_BUTTON2;
|
||||
|
||||
/* don't bother if it's too high (we're aiming at air... */
|
||||
if ((vecEndPos[2] - 32) < origin[2])
|
||||
input_buttons |= INPUT_BUTTON2;
|
||||
} else {
|
||||
/* entire way-link needs to be crouched. that's the law of the land */
|
||||
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH)
|
||||
|
@ -406,37 +421,54 @@ bot::RunAI(void)
|
|||
float shouldwalk = 0;
|
||||
|
||||
if (m_wtWeaponType == WPNTYPE_RANGED) {
|
||||
/* walk _directly_ towards the enemy if we're less than 512 units away */
|
||||
if (m_eTarget && enemyvisible && m_flEnemyDist < 1024) {
|
||||
aimpos = m_eTarget.origin;
|
||||
other = world;
|
||||
|
||||
if (m_eTarget) {
|
||||
tracebox(origin, m_eTarget.origin, mins, maxs, MOVE_OTHERONLY, this);
|
||||
/* walk _directly_ towards the enemy if we're less than 512 units away */
|
||||
if (trace_fraction >= 1.0 && m_eTarget && enemyvisible && m_eTarget.health < 50 && m_flEnemyDist < 512) {
|
||||
aimpos = m_eTarget.origin;
|
||||
goroute = 1;
|
||||
} else {
|
||||
goroute = 1;
|
||||
}
|
||||
} else {
|
||||
goroute = 1;
|
||||
}
|
||||
|
||||
/* we should probably walk we're distant enough to be more accurate */
|
||||
if ((m_eTarget && enemyvisible && m_flEnemyDist > 512))
|
||||
if ((m_eTarget && enemyvisible && m_flEnemyDist < 512))
|
||||
shouldwalk = 1;
|
||||
} else if (m_wtWeaponType == WPNTYPE_CLOSE) {
|
||||
/* move directly towards the enemy if we're 256 units away */
|
||||
if (m_eTarget && enemyvisible && m_flEnemyDist < 256) {
|
||||
/* we are far away, inch closer */
|
||||
aimpos = m_eTarget.origin;
|
||||
printf("going to target\n");
|
||||
} else {
|
||||
goroute = 1;
|
||||
}
|
||||
} else if (m_wtWeaponType == WPNTYPE_THROW) {
|
||||
if ((m_eTarget && enemyvisible && !enemydistant) && m_flEnemyDist < 512) {
|
||||
aimpos = m_eTarget.origin;
|
||||
printf("going to target\n");
|
||||
} else {
|
||||
goroute = 1;
|
||||
}
|
||||
} else {
|
||||
goroute = 1;
|
||||
}
|
||||
|
||||
if (goroute) {
|
||||
if (m_iCurNode <= BOTROUTE_DESTINATION)
|
||||
if (m_iCurNode <= BOTROUTE_DESTINATION) {
|
||||
aimpos = m_vecLastNode;
|
||||
else
|
||||
printf("going to last node\n");
|
||||
} else {
|
||||
aimpos = m_pRoute[m_iCurNode].m_vecDest;
|
||||
printf("going to next node\n");
|
||||
}
|
||||
} else {
|
||||
RouteClear();
|
||||
}
|
||||
|
||||
/* now we'll set the movevalues relative to the input_angle */
|
||||
|
@ -449,11 +481,13 @@ bot::RunAI(void)
|
|||
input_movevalues = [v_forward * vecDirection, v_right * vecDirection, v_up * vecDirection];
|
||||
input_movevalues[2] = 0;
|
||||
|
||||
#if 0
|
||||
/* duck and stand still when our enemy is far away */
|
||||
if (m_eTarget && enemyvisible && vlen(aimpos-origin) > 512) {
|
||||
input_buttons |= INPUT_BUTTON8;
|
||||
input_movevalues = [0,0,0];
|
||||
#if 1
|
||||
/* duck and stand still when our enemy seems strong */
|
||||
if (m_eTarget && enemyvisible && m_eTarget.health >= 75) {
|
||||
if (m_wtWeaponType == WPNTYPE_RANGED) {
|
||||
input_buttons |= INPUT_BUTTON8;
|
||||
input_movevalues = [0,0,0];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
|
||||
* Copyright (c) 2016-2022 Marco Cawthorne <marco@icculus.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -19,3 +19,4 @@ vector Route_SelectDestination( bot target );
|
|||
void Bot_RouteCB( entity ent, vector dest, int numnodes, nodeslist_t *nodelist );
|
||||
|
||||
int Route_GetNodeFlags(nodeslist_t *node);
|
||||
vector Route_GetJumpVelocity(vector frompos, vector topos, float gravitymod);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020 Marco Cawthorne <marco@icculus.org>
|
||||
* Copyright (c) 2016-2022 Marco Cawthorne <marco@icculus.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -38,7 +38,31 @@ Route_RoundDistance(float flDist)
|
|||
|
||||
/* returns a botinfo point that's nearest to us */
|
||||
entity
|
||||
Route_SelectNearest(float type, vector org)
|
||||
Route_SelectFarthest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||
{
|
||||
entity temp;
|
||||
int bestrange = 0;
|
||||
int range;
|
||||
entity dest = __NULL__;
|
||||
|
||||
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
|
||||
range = vlen(temp.origin - org);
|
||||
|
||||
if (lastpoi == temp.origin)
|
||||
continue;
|
||||
|
||||
if ((range > bestrange) && (temp.solid != SOLID_NOT)) {
|
||||
bestrange = range;
|
||||
dest = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* returns a botinfo point that's nearest to us */
|
||||
entity
|
||||
Route_SelectNearest(float type, vector org, optional vector lastpoi = [0,0,0])
|
||||
{
|
||||
entity temp;
|
||||
int bestrange = COST_INFINITE;
|
||||
|
@ -48,6 +72,9 @@ Route_SelectNearest(float type, vector org)
|
|||
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
|
||||
range = vlen(temp.origin - org);
|
||||
|
||||
if (lastpoi == temp.origin)
|
||||
continue;
|
||||
|
||||
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
|
||||
bestrange = range;
|
||||
dest = temp;
|
||||
|
@ -129,6 +156,10 @@ Route_SelectRandomSpot(void)
|
|||
{
|
||||
static entity eLastSpot;
|
||||
eLastSpot = findfloat(eLastSpot, ::botinfo, BOTINFO_SPAWNPOINT);
|
||||
|
||||
if (!eLastSpot)
|
||||
return (Route_SelectRandomSpot());
|
||||
|
||||
return (eLastSpot);
|
||||
}
|
||||
|
||||
|
@ -140,11 +171,12 @@ Bot_RouteCB(entity ent, vector dest, int numnodes, nodeslist_t *nodelist)
|
|||
b.m_iCurNode = numnodes - 1;
|
||||
b.m_pRoute = nodelist;
|
||||
b.m_vecLastNode = dest;
|
||||
b.m_flNodeGiveup = 0.0f;
|
||||
|
||||
//dprint("Bot: Route calculated.\n");
|
||||
//dprint(sprintf("Bot: # of nodes: %i\n", bot.m_iNodes) );
|
||||
//dprint(sprintf("Bot: # current node: %i\n", bot.m_iCurNode) );
|
||||
//dprint(sprintf("Bot: # endpos: %v\n", dest));
|
||||
print("Bot: Route calculated.\n");
|
||||
print(sprintf("Bot: # of nodes: %i\n", b.m_iNodes) );
|
||||
print(sprintf("Bot: # current node: %i\n", b.m_iCurNode) );
|
||||
print(sprintf("Bot: # endpos: %v\n", dest));
|
||||
}
|
||||
|
||||
vector
|
||||
|
@ -154,7 +186,6 @@ Route_SelectDestination(bot target)
|
|||
rules = (CGameRules)g_grMode;
|
||||
|
||||
entity dest = world;
|
||||
|
||||
|
||||
if (rules.IsTeamPlay()) {
|
||||
/* we have the goal item, so capture it */
|
||||
|
@ -171,8 +202,10 @@ Route_SelectDestination(bot target)
|
|||
dest = Route_SelectNearestEnemyTeam(BOTINFO_TEAM_GOALITEM, target.origin, target.team);
|
||||
}
|
||||
|
||||
if (dest)
|
||||
if (dest) {
|
||||
target.m_vecLastPOI = dest.origin;
|
||||
return dest.origin + [0,0,32];
|
||||
}
|
||||
|
||||
print(sprintf("%s can't figure out where to go for the goal\n", target.netname));
|
||||
}
|
||||
|
@ -180,25 +213,66 @@ Route_SelectDestination(bot target)
|
|||
/* 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)
|
||||
dest = Route_SelectNearest(BOTINFO_HEALTH, target.origin, target.m_vecLastPOI);
|
||||
|
||||
if (dest) {
|
||||
target.m_vecLastPOI = dest.origin;
|
||||
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 (random() < 0.25)
|
||||
if (target.armor < 50) {
|
||||
print(sprintf("%s going for armor\n", target.netname));
|
||||
dest = Route_SelectNearest(BOTINFO_ARMOR, target.origin);
|
||||
dest = Route_SelectNearest(BOTINFO_ARMOR, target.origin, target.m_vecLastPOI);
|
||||
|
||||
if (dest)
|
||||
if (dest) {
|
||||
target.m_vecLastPOI = dest.origin;
|
||||
return dest.origin + [0,0,32];
|
||||
}
|
||||
|
||||
print(sprintf("%s can't figure out where to go for armor\n", target.netname));
|
||||
}
|
||||
|
||||
/* go for ammo, or weapon */
|
||||
if (random() < 0.25)
|
||||
if (!dest) {
|
||||
print(sprintf("%s going for ammo/weapon\n", target.netname));
|
||||
|
||||
if (random() < 0.5)
|
||||
dest = Route_SelectFarthest(BOTINFO_WEAPON, target.origin, target.m_vecLastPOI);
|
||||
else
|
||||
dest = Route_SelectFarthest(BOTINFO_AMMO, target.origin, target.m_vecLastPOI);
|
||||
|
||||
if (dest) {
|
||||
target.m_vecLastPOI = dest.origin;
|
||||
return dest.origin + [0,0,32];
|
||||
}
|
||||
|
||||
print(sprintf("%s can't figure out where to go for ammo/weapon\n", target.netname));
|
||||
}
|
||||
|
||||
if (random() < 0.25)
|
||||
if (!dest) {
|
||||
static entity but;
|
||||
but = find(but, ::classname, "func_button");
|
||||
|
||||
if (but)
|
||||
return but.absmin + (0.5 * (but.absmax - but.absmin));
|
||||
}
|
||||
|
||||
if (random() < 0.25)
|
||||
if (!dest) {
|
||||
static entity trig;
|
||||
trig = find(trig, ::classname, "trigger_multiple");
|
||||
|
||||
if (trig)
|
||||
return trig.absmin + (0.5 * (trig.absmax - trig.absmin));
|
||||
}
|
||||
|
||||
/* if all else fails... select a random spot */
|
||||
print(sprintf("%s found nothing, going for random PoI\n", target.netname));
|
||||
dest = Route_SelectRandomSpot();
|
||||
|
@ -217,3 +291,44 @@ Route_GetNodeFlags(nodeslist_t *node)
|
|||
else
|
||||
return fl;
|
||||
}
|
||||
|
||||
/* Get's a velocity vector with which we can successfully jump from one place to another */
|
||||
vector
|
||||
Route_GetJumpVelocity(vector vecFrom, vector vecTo, float flGravMod)
|
||||
{
|
||||
#if 0
|
||||
float flHeight, flGravity, flTime, flDistance, flDir;
|
||||
vector vecJump = [0,0,0];
|
||||
|
||||
if (flGravMod <= 0.0)
|
||||
flGravMod = 1.0f;
|
||||
|
||||
flGravity = serverkeyfloat("phy_gravity") * flGravMod;
|
||||
flHeight = vecTo[2] - vecFrom[2];
|
||||
|
||||
if (flHeight <= 0)
|
||||
flHeight = vlen(vecTo - vecFrom) / 2;
|
||||
|
||||
flTime = sqrt(flHeight / (flGravity * 0.5f));
|
||||
if (flTime <= 0) {
|
||||
return [0,0,0];
|
||||
}
|
||||
|
||||
vecJump = vecTo - vecFrom;
|
||||
vecJump[2] = 0;
|
||||
flDistance = vlen(normalize(vecJump));
|
||||
|
||||
flDir = flDistance / flTime;
|
||||
vecJump *= flDir;
|
||||
vecJump[2] = bound(240, flTime * flGravity, 512);
|
||||
|
||||
print(sprintf("jumping from %v to %v at %v\n", vecFrom, vecTo, vecJump));
|
||||
#else
|
||||
vector vecJump = [0,0,0];
|
||||
float flDist = vlen(vecTo - vecFrom);
|
||||
makevectors(vectoangles(vecTo - vecFrom));
|
||||
vecJump = v_forward * flDist;
|
||||
vecJump[2] = 280;
|
||||
#endif
|
||||
return vecJump;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue