BotLib: Add support for the AIM linkflag, to control when a bot is forced

to look ahead to the current waypoint node.
This commit is contained in:
Marco Cawthorne 2021-01-16 17:34:04 +01:00
parent 4bb854f16b
commit 6a48c18171
10 changed files with 83 additions and 38 deletions

View File

@ -273,7 +273,7 @@ bot::RunAI(void)
if (m_iCurNode == BOTROUTE_DESTINATION)
aimpos = m_vecLastNode;
else {
if (m_iCurNode > 0)
if (m_iCurNode > 0 && !(m_pRoute[m_iCurNode].m_iFlags & LF_AIM))
aimpos = m_pRoute[m_iCurNode - 1].m_vecDest;
else
aimpos = m_pRoute[m_iCurNode].m_vecDest;

View File

@ -16,6 +16,7 @@
enum
{
BOTINFO_NONE,
BOTINFO_HEALTH,
BOTINFO_ARMOR,
BOTINFO_SPAWNPOINT,

View File

@ -21,16 +21,16 @@
* The route must be followed in reverse order (ie: the first node that must be reached
* is at index numnodes-1). If no route is available then the callback will be called with no nodes.
*/
int Route_RoundDistance( float flDist )
int
Route_RoundDistance(float flDist)
{
float r = fabs( flDist ) % 2;
if ( r == 0 ) {
float r = fabs(flDist) % 2;
if (r == 0) {
return flDist;
}
if ( flDist < 0 ) {
return -( fabs( flDist ) - r );
if (flDist < 0) {
return -(fabs(flDist) - r);
} else {
return flDist + 2 - r;
}
@ -42,10 +42,11 @@ int Route_RoundDistance( float flDist )
Spawn_SelectRandom
================
*/
entity Route_SelectRandom ( string sEntname )
entity
Route_SelectRandom(string sEntname)
{
static entity eLastSpot;
eLastSpot = find( eLastSpot, classname, sEntname );
eLastSpot = find(eLastSpot, classname, sEntname);
return eLastSpot;
}
@ -54,14 +55,16 @@ entity Route_SelectRandom ( string sEntname )
Route_SelectRandomSpot
================
*/
entity Route_SelectRandomSpot(void)
entity
Route_SelectRandomSpot(void)
{
static entity eLastSpot;
eLastSpot = findfloat( eLastSpot, ::botinfo, BOTINFO_SPAWNPOINT );
eLastSpot = findfloat(eLastSpot, ::botinfo, BOTINFO_SPAWNPOINT);
return eLastSpot;
}
void Bot_RouteCB( entity ent, vector dest, int numnodes, nodeslist_t *nodelist )
void
Bot_RouteCB(entity ent, vector dest, int numnodes, nodeslist_t *nodelist)
{
bot b = (bot)ent;
b.m_iNodes = numnodes;
@ -69,31 +72,32 @@ void Bot_RouteCB( entity ent, vector dest, int numnodes, nodeslist_t *nodelist )
b.m_pRoute = nodelist;
b.m_vecLastNode = dest;
//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 ) );
//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));
}
vector Route_SelectDestination( bot target )
vector
Route_SelectDestination(bot target)
{
entity dest = world;
// Need health!
if ( target.health < 50 ) {
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 ) ) {
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 ( dest ) {
//dprint( "Route: Going for health!" );
if (dest) {
//dprint("Route: Going for health!");
return dest.origin + '0 0 32';
}
}
@ -102,14 +106,3 @@ vector Route_SelectDestination( bot target )
target.m_eDestination = dest;
return dest.origin;
}
int Route_CanCrouch(bot target, vector endpos)
{
traceline(target.origin + [0,0,-18], endpos, FALSE, target);
if ( trace_fraction != 1.0f ) {
return FALSE;
} else {
return TRUE;
}
}

View File

@ -16,5 +16,4 @@
int Route_RoundDistance( float flDist );
vector Route_SelectDestination( bot target );
int Route_CanCrouch(bot target, vector endpos);
void Bot_RouteCB( entity ent, vector dest, int numnodes, nodeslist_t *nodelist );

View File

@ -265,6 +265,31 @@ Way_FlagWalk(void)
}
}
void
Way_FlagAim(void)
{
if (g_waylink_status == 0) {
g_way1 = Way_FindClosestNode(self.origin);
g_waylink_status = 1;
env_message_single(self, "^2Selected first waypoint!\n");
} else if (g_waylink_status == 1) {
g_way2 = Way_FindClosestNode(self.origin);
g_waylink_status = 0;
if (g_way1 != g_way2) {
for (int b = 0i; b < g_pWaypoints[g_way1].m_numNeighbours; b++) {
if (g_pWaypoints[g_way1].m_pNeighbour[b].m_iNode == g_way2) {
g_pWaypoints[g_way1].m_pNeighbour[b].m_iFlags |= LF_AIM;
env_message_single(self, "^2Walk-linked the two points!\n");
}
}
} else {
env_message_single(self, "^1Failed to link, the two points are the same!\n");
}
g_way1 = g_way2 = -1;
}
}
void
Way_HelperSpawns()
{
@ -461,6 +486,9 @@ Way_Cmd(void)
case "linkwalk":
Way_FlagWalk();
break;
case "linkaim":
Way_FlagAim();
break;
case "move":
vector p;
int n = Way_FindClosestNode(self.origin);
@ -551,6 +579,12 @@ Way_DrawDebugInfo(void)
R_EndPolygon();
}
if (fl & LF_AIM) {
R_PolygonVertex(org + [0,0,4], [0,1], [0.25,0.25,1], 1);
R_PolygonVertex(w2->m_vecOrigin + [0,0,4], [1,1], [0,0,0], 1);
R_EndPolygon();
}
R_PolygonVertex(org, [0,1], [1,0,1], 1);
R_PolygonVertex(w2->m_vecOrigin, [1,1], [0,1,0], 1);
R_EndPolygon();

View File

@ -21,5 +21,6 @@
#define LF_CROUCH 0x00000004i
#define LF_TELEPORT 0x00000008i
#define LF_WALK 0x00000010i
#define LF_AIM 0x00000020i
#define LF_USER 0x7fffff00i
#define LF_DESTINATION 0x80000000i

View File

@ -279,6 +279,9 @@ WAY_FLAGS(int n)
case 3:
localcmd("sv way linkwalk\n");
break;
case 4:
localcmd("sv way linkaim\n");
break;
case 9:
Textmenu_Call("WAY_MENU");
break;

View File

@ -26,6 +26,7 @@ void info_player_start(void)
if (autocvar_fcs_swapteams == TRUE) {
self.classname = "info_player_deathmatch";
}
self.botinfo = BOTINFO_SPAWNPOINT;
}
/*
@ -40,6 +41,7 @@ void info_player_deathmatch(void)
if (autocvar_fcs_swapteams == TRUE) {
self.classname = "info_player_start";
}
self.botinfo = BOTINFO_SPAWNPOINT;
}
/* Counter-Strike: Source compat */

View File

@ -174,11 +174,16 @@ times the amount of players in a given game.
*/
void PlayerPreThink(void)
{
if (self.classname != "player") {
return;
}
#ifdef BOT_INCLUDED
if (clienttype(self) == CLIENTTYPE_BOT) {
((bot)self).PreFrame();
}
#endif
g_grMode.PlayerPreFrame((base_player)self);
}
@ -193,6 +198,10 @@ times the amount of players in a given game.
*/
void PlayerPostThink(void)
{
if (self.classname != "player") {
return;
}
#ifdef BOT_INCLUDED
if (clienttype(self) == CLIENTTYPE_BOT) {
((bot)self).PostFrame();
@ -247,9 +256,12 @@ with the input_X globals being set to the appropriate data.
*/
void SV_RunClientCommand(void)
{
if (self.classname != "player") {
return;
}
#ifdef BOT_INCLUDED
/* wait a few seconds, as we may not have been spawned yet */
if (time > 5.0)
if (clienttype(self) == CLIENTTYPE_BOT) {
((bot)self).RunAI();
}

View File

@ -3,6 +3,7 @@ GAME tfc
NAME "Team Fortress"
BASEGAME platform
BASEGAME logos
BASEGAME valve
BASEGAME tfc
// custom game menu variables
@ -24,9 +25,8 @@ BASEGAME tfc
-set gameinfo_url_dl "http://www.frag-net.com/mods/tfc.fmf"
-set gameinfo_menutrack ""
DOWNLOADSURL http://www.frag-net.com/dl/tfc_packages
DOWNLOADSURL http://www.frag-net.com/dl/valve_packages
UPDATEURL http://www.frag-net.com/mods/tfc.fmf
INSTALL "tfc_essential;valve_essential;free_essential"
// you don't really want to change these
RTCBROKER master.frag-net.com:27950