diff --git a/src/botlib/bot.qc b/src/botlib/bot.qc index 9080c2a1..c874bccd 100644 --- a/src/botlib/bot.qc +++ b/src/botlib/bot.qc @@ -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; diff --git a/src/botlib/botinfo.h b/src/botlib/botinfo.h index a84ec61c..deb12ea1 100644 --- a/src/botlib/botinfo.h +++ b/src/botlib/botinfo.h @@ -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 */ }; diff --git a/src/botlib/route.h b/src/botlib/route.h index b2b6cc4f..8be15194 100644 --- a/src/botlib/route.h +++ b/src/botlib/route.h @@ -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); diff --git a/src/botlib/route.qc b/src/botlib/route.qc index a17a43b7..d9a754f5 100644 --- a/src/botlib/route.qc +++ b/src/botlib/route.qc @@ -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; +} diff --git a/src/shared/flags.h b/src/shared/flags.h index c3f3e191..fe37a0b6 100644 --- a/src/shared/flags.h +++ b/src/shared/flags.h @@ -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)