2020-04-22 10:31:28 +00:00
|
|
|
/*
|
2022-07-07 16:10:14 +00:00
|
|
|
* Copyright (c) 2016-2022 Vera Visions LLC.
|
2020-04-22 10:31:28 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2022-07-07 16:10:14 +00:00
|
|
|
*/
|
2020-04-22 10:31:28 +00:00
|
|
|
|
2021-05-12 13:42:20 +00:00
|
|
|
void SV_SendChat(entity sender, string msg, entity eEnt, float fType);
|
|
|
|
|
2022-03-11 19:40:43 +00:00
|
|
|
botstate_t
|
|
|
|
bot::GetState(void)
|
2022-03-09 05:50:30 +00:00
|
|
|
{
|
2022-03-11 19:40:43 +00:00
|
|
|
return m_bsState;
|
2022-03-09 05:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-03-11 19:40:43 +00:00
|
|
|
bot::SetState(botstate_t state)
|
2022-03-09 05:50:30 +00:00
|
|
|
{
|
2022-03-11 19:40:43 +00:00
|
|
|
m_bsState = state;
|
2022-03-09 05:50:30 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 19:40:43 +00:00
|
|
|
botpersonality_t
|
|
|
|
bot::GetPersonality(void)
|
2021-05-12 13:42:20 +00:00
|
|
|
{
|
2022-03-11 19:40:43 +00:00
|
|
|
return m_bpPersonality;
|
2021-05-12 13:42:20 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 19:40:43 +00:00
|
|
|
float
|
|
|
|
bot::GetWalkSpeed(void)
|
2021-05-12 13:42:20 +00:00
|
|
|
{
|
2022-03-11 19:40:43 +00:00
|
|
|
return 120;
|
2021-05-12 13:42:20 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 19:40:43 +00:00
|
|
|
float
|
|
|
|
bot::GetRunSpeed(void)
|
2020-12-26 06:27:34 +00:00
|
|
|
{
|
2022-03-11 19:40:43 +00:00
|
|
|
return 240;
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bot::RouteClear(void)
|
|
|
|
{
|
|
|
|
if (!m_iNodes)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_iCurNode = BOTROUTE_END;
|
|
|
|
m_iNodes = 0;
|
|
|
|
m_flNodeGiveup = 0.0f;
|
|
|
|
memfree(m_pRoute);
|
2022-03-14 00:10:12 +00:00
|
|
|
print(sprintf("%s cleared his route.\n", netname));
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bot::BrainThink(int enemyvisible, int enemydistant)
|
|
|
|
{
|
|
|
|
/* we had a target and it's now dead. now what? */
|
2022-03-09 05:50:30 +00:00
|
|
|
if (m_eTarget) {
|
|
|
|
if (m_eTarget.health <= 0) {
|
|
|
|
SetEnemy(__NULL__);
|
|
|
|
RouteClear();
|
|
|
|
}
|
2020-12-26 06:27:34 +00:00
|
|
|
} else if (m_eTarget && enemyvisible && enemydistant) {
|
|
|
|
/* we can see the player, but are too far away, plot a route */
|
|
|
|
route_calculate(this, m_eTarget.origin, 0, Bot_RouteCB);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-27 06:48:46 +00:00
|
|
|
void
|
|
|
|
bot::UseButton(void)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
float best;
|
|
|
|
func_button best_button = __NULL__;
|
|
|
|
|
|
|
|
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;
|
|
|
|
best_button = (func_button)e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (best_button == __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
|
|
|
|
}
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
void
|
|
|
|
bot::SeeThink(void)
|
|
|
|
{
|
2022-03-02 17:17:57 +00:00
|
|
|
CGameRules rules = (CGameRules)g_grMode;
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/*if (m_eTarget)
|
|
|
|
return; */
|
2020-12-26 06:27:34 +00:00
|
|
|
|
|
|
|
if (m_flSeeTime > time)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (autocvar_bot_pacifist)
|
|
|
|
return;
|
|
|
|
|
2022-06-22 22:25:08 +00:00
|
|
|
/* reaction time, in a way */
|
|
|
|
switch (cvar("bot_skill")) {
|
|
|
|
case 1:
|
|
|
|
m_flSeeTime = time + 0.5f;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_flSeeTime = time + 0.25f;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
m_flSeeTime = time + 0.15f;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
m_flSeeTime = time + 1.0f;
|
|
|
|
}
|
2020-12-26 06:27:34 +00:00
|
|
|
|
|
|
|
for (entity w = world; (w = findfloat(w, ::takedamage, DAMAGE_YES));) {
|
|
|
|
float flDot;
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* is w a client? */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (!(w.flags & FL_CLIENT))
|
|
|
|
continue;
|
2022-03-09 05:50:30 +00:00
|
|
|
|
|
|
|
/* is w alive? */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (w.health <= 0)
|
|
|
|
continue;
|
|
|
|
|
2020-12-28 18:59:37 +00:00
|
|
|
/* ain't go hurt our brothers and sisters */
|
2022-03-02 17:17:57 +00:00
|
|
|
if (rules.IsTeamPlay() == TRUE)
|
2020-12-28 18:59:37 +00:00
|
|
|
if (team == w.team)
|
|
|
|
continue;
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
/* first, is the potential enemy in our field of view? */
|
|
|
|
makevectors(v_angle);
|
|
|
|
vector v = normalize(w.origin - origin);
|
|
|
|
flDot = v * v_forward;
|
|
|
|
|
|
|
|
if (flDot < 90/180)
|
|
|
|
continue;
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* is it even physically able to be seen? */
|
|
|
|
traceline(origin, w.origin, MOVE_NORMAL, this);
|
2020-12-26 06:27:34 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* break out if at all a valid trace */
|
|
|
|
if (trace_ent == w) {
|
|
|
|
SetEnemy(w);
|
2020-12-26 06:27:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:31:28 +00:00
|
|
|
void
|
2020-12-23 06:53:43 +00:00
|
|
|
bot::CheckRoute(void)
|
2020-04-22 10:31:28 +00:00
|
|
|
{
|
2020-12-23 06:53:43 +00:00
|
|
|
float flDist;
|
2022-03-14 00:10:12 +00:00
|
|
|
vector vecEndPos;
|
|
|
|
float flRadius;
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
if (!m_iNodes) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* level out position/node stuff */
|
|
|
|
if (m_iCurNode < 0) {
|
2022-03-14 00:10:12 +00:00
|
|
|
vecEndPos = m_vecLastNode;
|
|
|
|
flRadius = 128; /* destination is not a node, therefore has a virtual radius */
|
2020-12-23 06:53:43 +00:00
|
|
|
} else {
|
2022-06-07 02:58:29 +00:00
|
|
|
vecEndPos = m_pRoute[m_iCurNode].dest;
|
|
|
|
flRadius = m_pRoute[m_iCurNode].radius;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 00:10:12 +00:00
|
|
|
/* 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));
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* we're inside the radius */
|
2022-03-14 00:10:12 +00:00
|
|
|
if (flDist <= flRadius) {
|
2022-05-11 19:49:04 +00:00
|
|
|
NSLog("^2bot::^3CheckRoute^7: " \
|
|
|
|
"%s reached node\n", this.targetname);
|
2020-12-23 06:53:43 +00:00
|
|
|
m_iCurNode--;
|
2020-12-26 06:27:34 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* if we're inside an actual node (not a virtual one */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (m_iCurNode >= 0) {
|
|
|
|
/* if a node is flagged as jumpy, jump! */
|
2022-03-14 00:10:12 +00:00
|
|
|
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_JUMP) {
|
|
|
|
//input_buttons |= INPUT_BUTTON2;
|
2022-06-07 02:58:29 +00:00
|
|
|
velocity = Route_GetJumpVelocity(origin, m_pRoute[m_iCurNode].dest, gravity);
|
2022-03-14 00:10:12 +00:00
|
|
|
}
|
2021-03-27 06:48:46 +00:00
|
|
|
|
|
|
|
/* find the nearest usable item (func_button) and use them */
|
2022-03-02 17:17:57 +00:00
|
|
|
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_USER)
|
2021-03-27 06:48:46 +00:00
|
|
|
UseButton();
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
|
|
|
|
2022-03-14 00:10:12 +00:00
|
|
|
#if 0
|
2020-12-23 06:53:43 +00:00
|
|
|
/* we've still traveling and from this node we may be able to walk
|
|
|
|
* directly to our end-destination */
|
|
|
|
if (m_iCurNode > -1) {
|
2022-03-14 00:10:12 +00:00
|
|
|
tracebox(origin, mins, maxs, vecEndPos, MOVE_NORMAL, this);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
/* can we walk directly to our target destination? */
|
|
|
|
if (trace_fraction == 1.0) {
|
2022-03-14 00:10:12 +00:00
|
|
|
print("^2bot::^3CheckRoute^7: " \
|
2020-12-23 06:53:43 +00:00
|
|
|
"Walking directly to last node\n");
|
|
|
|
m_iCurNode = -1;
|
|
|
|
}
|
|
|
|
}
|
2022-03-14 00:10:12 +00:00
|
|
|
#endif
|
2022-03-09 05:50:30 +00:00
|
|
|
} else { /* we're not near the node quite yet */
|
2022-03-14 00:10:12 +00:00
|
|
|
traceline(origin, vecEndPos, MOVE_NORMAL, this);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* we can't trace against our next node... that should never happen */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (trace_fraction != 1.0f) {
|
2020-12-23 06:53:43 +00:00
|
|
|
m_flNodeGiveup += frametime;
|
|
|
|
} else {
|
|
|
|
/* if we're literally stuck in a corner aiming at something we should
|
|
|
|
* not, also give up */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (flDist == m_flLastDist) {
|
2020-12-23 06:53:43 +00:00
|
|
|
m_flNodeGiveup += frametime;
|
|
|
|
} else {
|
2020-12-26 06:27:34 +00:00
|
|
|
m_flNodeGiveup = bound(0, m_flNodeGiveup - frametime, 1.0);
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
2020-04-22 10:31:28 +00:00
|
|
|
}
|
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
m_flLastDist = flDist;
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
/* after one second, also give up the route */
|
|
|
|
if (m_flNodeGiveup >= 1.0f || m_iCurNode <= BOTROUTE_END) {
|
2022-03-14 00:10:12 +00:00
|
|
|
print("taking too long! giving up!\n");
|
2020-12-26 06:27:34 +00:00
|
|
|
RouteClear();
|
|
|
|
} else if (m_flNodeGiveup >= 0.5f) {
|
|
|
|
/* attempt a jump after half a second */
|
2022-03-14 00:10:12 +00:00
|
|
|
|
|
|
|
/* don't bother if it's too high (we're aiming at air... */
|
|
|
|
if ((vecEndPos[2] - 32) < origin[2])
|
|
|
|
input_buttons |= INPUT_BUTTON2;
|
2020-12-26 06:27:34 +00:00
|
|
|
} else {
|
|
|
|
/* entire way-link needs to be crouched. that's the law of the land */
|
2022-03-02 17:17:57 +00:00
|
|
|
if (Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_CROUCH)
|
2020-12-26 06:27:34 +00:00
|
|
|
input_buttons |= INPUT_BUTTON8;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
2020-04-22 10:31:28 +00:00
|
|
|
}
|
|
|
|
|
2022-03-11 22:00:44 +00:00
|
|
|
void
|
|
|
|
bot::NewRoute(vector pos)
|
|
|
|
{
|
|
|
|
route_calculate(this, pos, 0, Bot_RouteCB);
|
|
|
|
}
|
|
|
|
|
2021-05-12 13:42:20 +00:00
|
|
|
void
|
|
|
|
bot::CreateObjective(void)
|
|
|
|
{
|
|
|
|
route_calculate(this, Route_SelectDestination(this), 0, Bot_RouteCB);
|
|
|
|
}
|
|
|
|
|
2020-04-22 10:31:28 +00:00
|
|
|
void
|
2020-12-23 06:53:43 +00:00
|
|
|
bot::RunAI(void)
|
2020-04-22 10:31:28 +00:00
|
|
|
{
|
2020-12-23 06:53:43 +00:00
|
|
|
vector aimdir, aimpos;
|
|
|
|
int enemyvisible, enemydistant;
|
|
|
|
float flLerp;
|
2020-04-22 10:31:28 +00:00
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
/* reset input frame */
|
|
|
|
input_buttons = 0;
|
|
|
|
input_movevalues = [0,0,0];
|
|
|
|
input_angles = [0,0,0];
|
|
|
|
|
|
|
|
/* attempt to respawn when dead */
|
|
|
|
if (health <= 0) {
|
2020-12-26 06:27:34 +00:00
|
|
|
RouteClear();
|
|
|
|
WeaponAttack();
|
2022-03-09 05:50:30 +00:00
|
|
|
SetEnemy(__NULL__);
|
2020-12-26 06:27:34 +00:00
|
|
|
return;
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
2020-12-28 18:59:37 +00:00
|
|
|
/* freeze the bot */
|
|
|
|
if (autocvar_bot_wait)
|
|
|
|
return;
|
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
/* create our first route */
|
2021-01-02 17:52:09 +00:00
|
|
|
if (!m_iNodes && autocvar_bot_aimless == 0) {
|
2021-05-12 13:42:20 +00:00
|
|
|
CreateObjective();
|
2020-04-22 10:31:28 +00:00
|
|
|
|
2022-05-11 19:49:04 +00:00
|
|
|
NSLog("bot::RunAI: %s is calculating first bot route",
|
|
|
|
this.netname);
|
2020-04-22 10:31:28 +00:00
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
/* our route probably has not been processed yet */
|
|
|
|
if (!m_iNodes) {
|
|
|
|
return;
|
|
|
|
}
|
2020-04-22 10:31:28 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* prepare our weapons for firing */
|
2020-12-26 06:27:34 +00:00
|
|
|
WeaponThink();
|
2022-03-09 05:50:30 +00:00
|
|
|
|
|
|
|
/* see if enemies are nearby */
|
2020-12-26 06:27:34 +00:00
|
|
|
SeeThink();
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* calculate enemy distance _once_ */
|
|
|
|
if (m_eTarget) {
|
|
|
|
m_flEnemyDist = vlen(origin - m_eTarget.origin);
|
|
|
|
} else {
|
|
|
|
m_flEnemyDist = -1;
|
|
|
|
}
|
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
enemyvisible = FALSE;
|
|
|
|
enemydistant = FALSE;
|
|
|
|
|
|
|
|
if (m_eTarget != __NULL__) {
|
|
|
|
traceline(origin + view_ofs, m_eTarget.origin, TRUE, this);
|
2022-03-09 05:50:30 +00:00
|
|
|
|
|
|
|
/* is it 'visible'? can we 'see' them? */
|
2020-12-23 06:53:43 +00:00
|
|
|
enemyvisible = (trace_ent == m_eTarget || trace_fraction == 1.0f);
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* if they're distant, remember that */
|
|
|
|
if (m_flEnemyDist > 1024) {
|
2020-12-23 06:53:43 +00:00
|
|
|
enemydistant = TRUE;
|
|
|
|
}
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* attack if visible! */
|
2020-12-23 06:53:43 +00:00
|
|
|
if (enemyvisible) {
|
2020-12-26 06:27:34 +00:00
|
|
|
WeaponAttack();
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
}
|
2022-03-09 05:50:30 +00:00
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
BrainThink(enemyvisible, enemydistant);
|
2020-12-23 06:53:43 +00:00
|
|
|
CheckRoute();
|
|
|
|
|
2022-03-02 17:17:57 +00:00
|
|
|
aimpos = [0,0,0];
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* if we've got a path (we always should) move the bot */
|
2020-12-23 06:53:43 +00:00
|
|
|
if (m_iNodes) {
|
2022-03-14 18:18:59 +00:00
|
|
|
float goroute = 0;
|
2020-12-26 06:27:34 +00:00
|
|
|
vector vecNewAngles;
|
|
|
|
vector vecDirection;
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* no enemy, or it isn't visible... then stare at nodes! */
|
2020-12-23 06:53:43 +00:00
|
|
|
if (!m_eTarget || !enemyvisible) {
|
|
|
|
/* aim at the next node */
|
2020-12-26 06:27:34 +00:00
|
|
|
if (m_iCurNode == BOTROUTE_DESTINATION)
|
2020-12-23 06:53:43 +00:00
|
|
|
aimpos = m_vecLastNode;
|
2020-12-26 06:27:34 +00:00
|
|
|
else {
|
2022-03-02 17:17:57 +00:00
|
|
|
if (m_iCurNode > 0 && !(Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_AIM))
|
2022-06-07 02:58:29 +00:00
|
|
|
aimpos = m_pRoute[m_iCurNode - 1].dest;
|
2020-12-26 06:27:34 +00:00
|
|
|
else
|
2022-06-07 02:58:29 +00:00
|
|
|
aimpos = m_pRoute[m_iCurNode].dest;
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
} else {
|
|
|
|
/* aim towards the enemy */
|
|
|
|
aimpos = m_eTarget.origin;
|
|
|
|
}
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
/* aim ahead if aimpos is somehow invalid */
|
2022-03-02 17:17:57 +00:00
|
|
|
if (aimpos == [0,0,0]) {
|
|
|
|
makevectors(angles);
|
|
|
|
aimpos = origin + v_forward * 128;
|
|
|
|
}
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
/* lerping speed, faster when we've got a target */
|
|
|
|
if (m_eTarget && enemyvisible)
|
|
|
|
flLerp = bound(0.0f, frametime * 45, 1.0f);
|
|
|
|
else
|
|
|
|
flLerp = bound(0.0f, frametime * 30, 1.0f);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
/* that's the old angle */
|
|
|
|
makevectors(v_angle);
|
2020-12-26 06:27:34 +00:00
|
|
|
vecNewAngles = v_forward;
|
2020-12-23 06:53:43 +00:00
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
/* aimdir = new final angle */
|
2020-12-23 06:53:43 +00:00
|
|
|
aimdir = vectoangles(aimpos - origin);
|
|
|
|
makevectors(aimdir);
|
|
|
|
|
|
|
|
/* slowly lerp towards the final angle */
|
2020-12-26 06:27:34 +00:00
|
|
|
vecNewAngles[0] = Math_Lerp(vecNewAngles[0], v_forward[0], flLerp);
|
|
|
|
vecNewAngles[1] = Math_Lerp(vecNewAngles[1], v_forward[1], flLerp);
|
|
|
|
vecNewAngles[2] = Math_Lerp(vecNewAngles[2], v_forward[2], flLerp);
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
/* make sure we're aiming tight */
|
2020-12-26 06:27:34 +00:00
|
|
|
v_angle = vectoangles(vecNewAngles);
|
2020-12-23 06:53:43 +00:00
|
|
|
v_angle[0] = Math_FixDelta(v_angle[0]);
|
|
|
|
v_angle[1] = Math_FixDelta(v_angle[1]);
|
|
|
|
v_angle[2] = Math_FixDelta(v_angle[2]);
|
|
|
|
angles[0] = Math_FixDelta(v_angle[0]);
|
|
|
|
angles[1] = Math_FixDelta(v_angle[1]);
|
|
|
|
angles[2] = Math_FixDelta(v_angle[2]);
|
2020-12-26 06:27:34 +00:00
|
|
|
input_angles = v_angle;
|
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
float shouldwalk = 0;
|
2022-02-10 21:31:57 +00:00
|
|
|
|
2022-03-09 05:50:30 +00:00
|
|
|
if (m_wtWeaponType == WPNTYPE_RANGED) {
|
2022-03-14 00:10:12 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-03-09 05:50:30 +00:00
|
|
|
} else {
|
|
|
|
goroute = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we should probably walk we're distant enough to be more accurate */
|
2022-03-14 00:10:12 +00:00
|
|
|
if ((m_eTarget && enemyvisible && m_flEnemyDist < 512))
|
2022-03-09 05:50:30 +00:00
|
|
|
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;
|
2022-03-14 18:18:59 +00:00
|
|
|
//printf("going to target\n");
|
2022-03-09 05:50:30 +00:00
|
|
|
} else {
|
|
|
|
goroute = 1;
|
|
|
|
}
|
|
|
|
} else if (m_wtWeaponType == WPNTYPE_THROW) {
|
|
|
|
if ((m_eTarget && enemyvisible && !enemydistant) && m_flEnemyDist < 512) {
|
|
|
|
aimpos = m_eTarget.origin;
|
2022-03-14 18:18:59 +00:00
|
|
|
//printf("going to target\n");
|
2022-03-09 05:50:30 +00:00
|
|
|
} else {
|
|
|
|
goroute = 1;
|
|
|
|
}
|
2022-03-14 00:10:12 +00:00
|
|
|
} else {
|
|
|
|
goroute = 1;
|
2022-03-09 05:50:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (goroute) {
|
2022-03-14 00:10:12 +00:00
|
|
|
if (m_iCurNode <= BOTROUTE_DESTINATION) {
|
2020-12-26 06:27:34 +00:00
|
|
|
aimpos = m_vecLastNode;
|
2022-03-14 18:18:59 +00:00
|
|
|
//printf("going to last node\n");
|
2022-03-14 00:10:12 +00:00
|
|
|
} else {
|
2022-06-07 02:58:29 +00:00
|
|
|
aimpos = m_pRoute[m_iCurNode].dest;
|
2022-03-14 18:18:59 +00:00
|
|
|
//printf("going to next node\n");
|
2022-03-14 00:10:12 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RouteClear();
|
2020-12-26 06:27:34 +00:00
|
|
|
}
|
2020-12-23 06:53:43 +00:00
|
|
|
|
|
|
|
/* now we'll set the movevalues relative to the input_angle */
|
2022-03-09 05:50:30 +00:00
|
|
|
if ((m_iCurNode >= 0 && Route_GetNodeFlags(&m_pRoute[m_iCurNode]) & LF_WALK) || shouldwalk)
|
|
|
|
vecDirection = normalize(aimpos - origin) * GetWalkSpeed();
|
2020-12-29 08:10:21 +00:00
|
|
|
else
|
2022-03-09 05:50:30 +00:00
|
|
|
vecDirection = normalize(aimpos - origin) * GetRunSpeed();
|
2020-12-29 08:10:21 +00:00
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
makevectors(input_angles);
|
2020-12-26 06:27:34 +00:00
|
|
|
input_movevalues = [v_forward * vecDirection, v_right * vecDirection, v_up * vecDirection];
|
2022-02-04 23:24:43 +00:00
|
|
|
input_movevalues[2] = 0;
|
2021-05-16 21:08:41 +00:00
|
|
|
|
2022-03-14 00:10:12 +00:00
|
|
|
#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];
|
|
|
|
}
|
2021-05-16 21:08:41 +00:00
|
|
|
}
|
2022-03-09 05:50:30 +00:00
|
|
|
#endif
|
2020-12-23 06:53:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* press any buttons needed */
|
2020-12-26 06:27:34 +00:00
|
|
|
button0 = input_buttons & INPUT_BUTTON0; // attack
|
|
|
|
button2 = input_buttons & INPUT_BUTTON2; // jump
|
|
|
|
button3 = input_buttons & INPUT_BUTTON3; // tertiary
|
|
|
|
button4 = input_buttons & INPUT_BUTTON4; // reload
|
|
|
|
button5 = input_buttons & INPUT_BUTTON5; // secondary
|
|
|
|
button6 = input_buttons & INPUT_BUTTON6; // use
|
|
|
|
button7 = input_buttons & INPUT_BUTTON7; // unused
|
|
|
|
button8 = input_buttons & INPUT_BUTTON8; // duck
|
2020-12-23 06:53:43 +00:00
|
|
|
movement = input_movevalues;
|
|
|
|
}
|
|
|
|
|
2020-12-26 06:27:34 +00:00
|
|
|
void
|
|
|
|
bot::PreFrame(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bot::PostFrame(void)
|
|
|
|
{
|
|
|
|
/* we've picked something new up */
|
|
|
|
if (m_iOldItems != g_items) {
|
2020-12-28 18:59:37 +00:00
|
|
|
Weapons_SwitchBest(this);
|
|
|
|
print(sprintf("%s is now using %s (%d)\n", netname, g_weapons[activeweapon].name, activeweapon));
|
2020-12-26 06:27:34 +00:00
|
|
|
m_iOldItems = g_items;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-24 22:32:37 +00:00
|
|
|
void
|
|
|
|
bot::SetName(string nickname)
|
|
|
|
{
|
|
|
|
if (autocvar_bot_prefix)
|
|
|
|
forceinfokey(this, "name", sprintf("%s %s", autocvar_bot_prefix, nickname));
|
|
|
|
else
|
|
|
|
forceinfokey(this, "name", nickname);
|
|
|
|
}
|
|
|
|
|
2020-12-23 06:53:43 +00:00
|
|
|
void
|
|
|
|
bot::bot(void)
|
|
|
|
{
|
2020-12-26 06:27:34 +00:00
|
|
|
classname = "player";
|
2021-01-05 14:51:49 +00:00
|
|
|
targetname = "_nuclide_bot_";
|
2022-04-29 22:20:04 +00:00
|
|
|
forceinfokey(this, "*bot", "1");
|
2020-04-22 10:31:28 +00:00
|
|
|
}
|