BotLib: for goals and goalitem route search, use WorldSpaceCenter() and not their origin to deal with brush triggers and non-existant origins properly

This commit is contained in:
Marco Cawthorne 2023-10-13 08:22:31 -07:00
parent 900cf43bd0
commit ab9d66b2e4
Signed by: eukara
GPG key ID: CE2032F0A2882A22
4 changed files with 116 additions and 116 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2023 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -69,11 +69,10 @@ bot::BrainThink(int enemyvisible, int enemydistant)
void
bot::UseButton(void)
{
#if 1
float best;
func_button best_button = __NULL__;
float bestDist;
func_button bestButton = __NULL__;
best = COST_INFINITE;
bestDist = COST_INFINITE;
for (entity e = world; (e = find(e, ::classname, "func_button"));) {
float dist;
vector pos;
@ -82,54 +81,36 @@ bot::UseButton(void)
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
dist = vlen(origin - pos);
if (dist < best) {
best = dist;
best_button = (func_button)e;
if (dist < bestDist) {
bestDist = dist;
bestButton = (func_button)e;
}
}
if (best_button == __NULL__)
if (bestButton == __NULL__) {
return;
best_button.Trigger(this, TRIG_TOGGLE);
sound(this, CHAN_ITEM, "common/wpn_select.wav", 0.25, ATTN_IDLE);
#else
float best;
vector foo;
best = COST_INFINITE;
for (entity e = world; (e = find(e, ::classname, "func_button"));) {
float dist;
vector pos;
pos[0] = e.absmin[0] + (0.5 * (e.absmax[0] - e.absmin[0]));
pos[1] = e.absmin[1] + (0.5 * (e.absmax[1] - e.absmin[1]));
pos[2] = e.absmin[2] + (0.5 * (e.absmax[2] - e.absmin[2]));
dist = vlen(origin - pos);
if (dist < best) {
best = dist;
foo = pos;
}
}
v_angle = vectoangles(origin - foo);
Player_UseDown();
#endif
bestButton.Trigger(this, TRIG_TOGGLE);
sound(this, CHAN_ITEM, "common/wpn_select.wav", 0.25, ATTN_IDLE);
}
void
bot::SeeThink(void)
{
CGameRules rules = (CGameRules)g_grMode;
NSGameRules rules = (NSGameRules)g_grMode;
/*if (m_eTarget)
return; */
if (m_flSeeTime > time)
if (m_flSeeTime > time) {
return;
}
if (autocvar_bot_pacifist)
/* DEVELOPER CVAR: don't attack */
if (autocvar_bot_dont_shoot) {
return;
}
/* reaction time, in a way */
switch (cvar("bot_skill")) {
@ -158,7 +139,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;
@ -274,7 +255,7 @@ bot::CheckRoute(void)
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)
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH || autocvar_bot_crouch)
input_buttons |= INPUT_BUTTON8;
}
}
@ -288,8 +269,8 @@ bot::CreateObjective(void)
void
bot::RunAI(void)
{
vector aimdir, aimpos;
int enemyvisible, enemydistant;
vector aimDir, aimPos;
bool enemyVisible, enemyDistant;
float flLerp;
/* reset input frame */
@ -298,15 +279,15 @@ bot::RunAI(void)
input_angles = [0,0,0];
/* attempt to respawn when dead */
if (health <= 0) {
if (IsDead() == true) {
RouteClear();
WeaponAttack();
SetEnemy(__NULL__);
return;
}
/* freeze the bot */
if (autocvar_bot_wait)
/* DEVELOPER CVAR: freeze the bot */
if (autocvar_bot_stop)
return;
/* create our first route */
@ -335,66 +316,67 @@ bot::RunAI(void)
m_flEnemyDist = -1;
}
enemyvisible = FALSE;
enemydistant = FALSE;
enemyVisible = false;
enemyDistant = false;
if (m_eTarget != __NULL__) {
traceline(origin + view_ofs, m_eTarget.origin, TRUE, this);
traceline(GetEyePos(), m_eTarget.origin, MOVE_NORMAL, this);
/* is it 'visible'? can we 'see' them? */
enemyvisible = (trace_ent == m_eTarget || trace_fraction == 1.0f);
enemyVisible = (trace_ent == m_eTarget || trace_fraction == 1.0f);
/* if they're distant, remember that */
if (m_flEnemyDist > 1024) {
enemydistant = TRUE;
if (m_flEnemyDist > 1024.0f) {
enemyDistant = true;
}
/* attack if visible! */
if (enemyvisible) {
if (enemyVisible == true) {
WeaponAttack();
}
} else if (m_flForceWeaponAttack > time)
} else if (m_flForceWeaponAttack > time) {
WeaponAttack();
}
BrainThink(enemyvisible, enemydistant);
BrainThink(enemyVisible, enemyDistant);
CheckRoute();
aimpos = [0,0,0];
aimPos = [0,0,0];
/* if we've got a path (we always should) move the bot */
if (m_iNodes) {
float goroute = 0;
bool goRoute = false;
vector vecNewAngles;
vector vecDirection;
/* no enemy, or it isn't visible... then stare at nodes! */
if (!m_eTarget || !enemyvisible) {
if (!m_eTarget || enemyVisible == false) {
/* aim at the next node */
if (m_iCurNode == BOTROUTE_DESTINATION)
aimpos = m_vecLastNode;
aimPos = m_vecLastNode;
else {
if (m_iCurNode > 0 && !(Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_AIM))
aimpos = m_pRoute[m_iCurNode - 1].dest;
aimPos = m_pRoute[m_iCurNode - 1].dest;
else
aimpos = m_pRoute[m_iCurNode].dest;
aimPos = m_pRoute[m_iCurNode].dest;
}
} else {
/* aim towards the enemy */
aimpos = m_eTarget.origin;
aimPos = m_eTarget.origin;
}
/* force bot to fire at a position if desired */
if (m_flForceWeaponAttack > time)
aimpos = m_vecForceWeaponAttackPos;
aimPos = m_vecForceWeaponAttackPos;
/* aim ahead if aimpos is somehow invalid */
if (aimpos == [0,0,0]) {
/* aim ahead if aimPos is somehow invalid */
if (aimPos == [0,0,0]) {
makevectors(angles);
aimpos = origin + v_forward * 128;
aimPos = origin + v_forward * 128;
}
/* lerping speed, faster when we've got a target */
if (m_eTarget && enemyvisible)
if (m_eTarget && enemyVisible == true)
flLerp = bound(0.0f, frametime * 45, 1.0f);
else
flLerp = bound(0.0f, frametime * 30, 1.0f);
@ -403,9 +385,9 @@ bot::RunAI(void)
makevectors(v_angle);
vecNewAngles = v_forward;
/* aimdir = new final angle */
aimdir = vectoangles(aimpos - origin);
makevectors(aimdir);
/* aimDir = new final angle */
aimDir = vectoangles(aimPos - origin);
makevectors(aimDir);
/* slowly lerp towards the final angle */
vecNewAngles[0] = Math_Lerp(vecNewAngles[0], v_forward[0], flLerp);
@ -422,53 +404,53 @@ bot::RunAI(void)
angles[2] = Math_FixDelta(v_angle[2]);
input_angles = v_angle;
float shouldwalk = 0;
bool shouldWalk = autocvar_bot_walk;
if (m_wtWeaponType == WPNTYPE_RANGED) {
other = world;
if (m_eTarget) {
other = world;
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;
if (trace_fraction >= 1.0 && m_eTarget && enemyVisible && m_eTarget.health < 50 && m_flEnemyDist < 512) {
aimPos = m_eTarget.origin;
goRoute = true;
} else {
goroute = 1;
goRoute = true;
}
} else {
goroute = 1;
goRoute = true;
}
/* we should probably walk we're distant enough to be more accurate */
if ((m_eTarget && enemyvisible && m_flEnemyDist < 512))
shouldwalk = 1;
if ((m_eTarget && enemyVisible && m_flEnemyDist < 512))
shouldWalk = true;
} else if (m_wtWeaponType == WPNTYPE_CLOSE) {
/* move directly towards the enemy if we're 256 units away */
if (m_eTarget && enemyvisible && m_flEnemyDist < 256) {
if (m_eTarget && enemyVisible && m_flEnemyDist < 256) {
/* we are far away, inch closer */
aimpos = m_eTarget.origin;
aimPos = m_eTarget.origin;
//printf("going to target\n");
} else {
goroute = 1;
goRoute = true;
}
} else if (m_wtWeaponType == WPNTYPE_THROW) {
if ((m_eTarget && enemyvisible && !enemydistant) && m_flEnemyDist < 512) {
aimpos = m_eTarget.origin;
if ((m_eTarget && enemyVisible && !enemyDistant) && m_flEnemyDist < 512) {
aimPos = m_eTarget.origin;
//printf("going to target\n");
} else {
goroute = 1;
goRoute = true;
}
} else {
goroute = 1;
goRoute = true;
}
if (goroute) {
if (goRoute) {
if (m_iCurNode <= BOTROUTE_DESTINATION) {
aimpos = m_vecLastNode;
aimPos = m_vecLastNode;
//printf("going to last node\n");
} else {
aimpos = m_pRoute[m_iCurNode].dest;
aimPos = m_pRoute[m_iCurNode].dest;
//printf("going to next node\n");
}
} else {
@ -476,7 +458,7 @@ bot::RunAI(void)
}
/* if there's a breakable in the way... */
traceline(origin, aimpos, MOVE_NORMAL, this);
traceline(origin, aimPos, MOVE_NORMAL, this);
/* Hackish: If there's a func_breakable in the way... */
if (trace_ent.classname == "func_breakable") {
@ -485,10 +467,10 @@ bot::RunAI(void)
}
/* now we'll set the movevalues relative to the input_angle */
if ((m_iCurNode >= 0 && Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_WALK) || shouldwalk)
vecDirection = normalize(aimpos - origin) * GetWalkSpeed();
if ((m_iCurNode >= 0 && Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_WALK) || shouldWalk)
vecDirection = normalize(aimPos - origin) * GetWalkSpeed();
else
vecDirection = normalize(aimpos - origin) * GetRunSpeed();
vecDirection = normalize(aimPos - origin) * GetRunSpeed();
makevectors(input_angles);
input_movevalues = [v_forward * vecDirection, v_right * vecDirection, v_up * vecDirection];
@ -496,7 +478,7 @@ bot::RunAI(void)
#if 1
/* duck and stand still when our enemy seems strong */
if (m_eTarget && enemyvisible && m_eTarget.health >= 75) {
if (m_eTarget && enemyVisible && m_eTarget.health >= 75) {
if (m_wtWeaponType == WPNTYPE_RANGED) {
input_buttons |= INPUT_BUTTON8;
input_movevalues = [0,0,0];

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2023 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -17,7 +17,7 @@
void
bot::Pain(void)
{
CGameRules rules = g_grMode;
NSGameRules rules = g_grMode;
super::Pain();
@ -33,11 +33,13 @@ bot::Pain(void)
float enemydist = vlen(origin - m_eTarget.origin);
float newdist = vlen(origin - g_dmg_eAttacker.origin);
if (m_eTarget)
if (newdist < enemydist)
if (m_eTarget) {
if (newdist < enemydist) {
SetEnemy(g_dmg_eAttacker);
else
}
} else {
SetEnemy(g_dmg_eAttacker);
}
}
}
@ -46,10 +48,11 @@ bot::SetEnemy(entity en)
{
m_eTarget = en;
if (m_eTarget)
if (m_eTarget) {
m_flEnemyDist = vlen(origin - m_eTarget.origin);
else
} else {
m_flEnemyDist = -1;
}
}
void
@ -59,9 +62,11 @@ bot::WeaponThink(void)
/* clip empty, but the whole weapon isn't */
if (r == 0 && a_ammo1 <= 0) {
/* stop fire, tap reload */
input_buttons &= ~INPUT_BUTTON0;
input_buttons |= INPUT_BUTTON4;
} else if (r == 1) {
/* if empty, switch to the next best weapon */
Weapons_SwitchBest(this, activeweapon);
}
@ -71,27 +76,27 @@ bot::WeaponThink(void)
void
bot::WeaponAttack(void)
{
int should_attack = 0;
bool shouldAttack = false;
/* only attack when the type's suggested distance makes sense to */
if (m_wtWeaponType == WPNTYPE_RANGED) {
if (m_flEnemyDist <= 1024)
should_attack = 1;
shouldAttack = true;
} else if (m_wtWeaponType == WPNTYPE_THROW) {
if (m_flEnemyDist <= 512)
should_attack = 1;
shouldAttack = true;
} else if (m_wtWeaponType == WPNTYPE_CLOSE) {
if (m_flEnemyDist <= 128)
should_attack = 1;
shouldAttack = true;
} else {
if (m_flEnemyDist <= 1024)
should_attack = 1;
shouldAttack = true;
}
if (m_flForceWeaponAttack > time)
should_attack = 1;
shouldAttack = true;
if (should_attack && m_flAttackTime < time) {
if (shouldAttack && m_flAttackTime < time) {
if (!m_iAttackMode) {
input_buttons |= INPUT_BUTTON0;
}
@ -136,7 +141,7 @@ var float g_botalert_timer;
void
BotLib_Alert(vector pos, float radius, float t)
{
CGameRules rules = g_grMode;
NSGameRules rules = g_grMode;
/* sometimes many alert-sounds happen at once... we don't really want
* that */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2022 Vera Visions LLC.
* Copyright (c) 2016-2023 Vera Visions LLC.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -14,13 +14,22 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
var int autocvar_bot_pacifist = FALSE;
var int autocvar_bot_wait = FALSE;
var int autocvar_bot_aimless = FALSE;
var int autocvar_nav_linksize = 256;
var int autocvar_nav_radius = 8;
var bool autocvar_bot_crouch = false;
var bool autocvar_bot_walk = false;
var bool autocvar_bot_stop = false;
var bool autocvar_bot_dont_shoot = false;
var bool autocvar_bot_join_after_player = false;
var float autocvar_bot_join_delay = 0.0f;
var int autocvar_bot_quota = 0i;
var string autocvar_bot_quota_mode = "normal";
var string autocvar_bot_chatter = "normal";
typedef enum
{
BOTSKILL_EASY = 1,
@ -28,6 +37,6 @@ typedef enum
BOTSKILL_HARD
} botskill_t;
var botskill_t autocvar_bot_skill = 2;
var botskill_t autocvar_bot_skill = BOTSKILL_MEDIUM;
var string autocvar_bot_prefix = "";

View file

@ -94,10 +94,11 @@ Route_SelectNearestTeam(float type, vector org, float tt)
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
NSEntity tempEnt = (NSEntity)temp;
if (temp.team != tt)
continue;
range = vlen(temp.origin - org);
range = vlen(tempEnt.WorldSpaceCenter() - org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
@ -118,10 +119,11 @@ Route_SelectNearestEnemyTeam(float type, vector org, float tt)
entity dest = __NULL__;
for (temp = world; (temp = findfloat(temp, ::botinfo, type));) {
NSEntity tempEnt = (NSEntity)temp;
if (temp.team == tt)
continue;
range = vlen(temp.origin - org);
range = vlen(tempEnt.WorldSpaceCenter() - org);
if ((range < bestrange) && (temp.solid != SOLID_NOT)) {
bestrange = range;
@ -169,7 +171,7 @@ Route_SelectDestination(bot target)
CGameRules rules;
rules = (CGameRules)g_grMode;
entity dest = world;
NSEntity dest = __NULL__;
if (rules.IsTeamplay()) {
/* we have the goal item, so capture it */
@ -187,10 +189,12 @@ Route_SelectDestination(bot target)
}
if (dest != __NULL__) {
target.m_vecLastPOI = dest.origin;
return dest.origin + [0,0,32];
target.m_vecLastPOI = dest.WorldSpaceCenter();
return dest.WorldSpaceCenter() + [0,0,32];
}
/* by now, they need something else to do involving goal items probably */
print(sprintf("%s can't figure out where to go for the goal\n", target.netname));
}
@ -200,7 +204,7 @@ Route_SelectDestination(bot target)
dest = Route_SelectNearest(BOTINFO_HEALTH, target.origin, target.m_vecLastPOI);
if (dest != __NULL__) {
target.m_vecLastPOI = dest.origin;
target.m_vecLastPOI = dest.WorldSpaceCenter();
return dest.origin + [0,0,32];
}