jabot: Improve navigation save logic

This commit is contained in:
Denis Pauk 2025-03-10 01:01:11 +02:00
parent 5d4a2facbd
commit 0fbcbbcdff
22 changed files with 160 additions and 236 deletions

View file

@ -528,7 +528,8 @@ SCR_ReadNextAVFrame(void)
static qboolean
SCR_LoadAVcodec(const char *arg, const char *dot)
{
char name[MAX_OSPATH], *path = NULL;
const char *path = NULL;
char name[MAX_OSPATH];
while (1)
{

View file

@ -245,7 +245,7 @@ typedef struct
// gamedir will be the current directory that generated
// files should be stored to, ie: "f:\quake\id1"
char *(IMPORT *FS_Gamedir) (void);
const char *(IMPORT *FS_Gamedir) (void);
cvar_t *(IMPORT *Cvar_Get) (const char *name, const char *value, int flags);
cvar_t *(IMPORT *Cvar_Set) (const char *name, const char *value);

View file

@ -231,27 +231,30 @@ FS_FileLength(FILE *f)
* Creates any directories needed to store the given filename.
*/
void
FS_CreatePath(char *path)
FS_CreatePath(const char *path)
{
char *cur; /* Current '/'. */
char *old; /* Old '/'. */
char dir_path[MAX_OSPATH];
FS_DPrintf("FS_CreatePath(%s)\n", path);
FS_DPrintf("%s(%s)\n", __func__, path);
if (strstr(path, "..") != NULL)
if (strstr(dir_path, "..") != NULL)
{
Com_Printf("WARNING: refusing to create relative path '%s'.\n", path);
return;
}
cur = old = path;
strncpy(dir_path, path, sizeof(dir_path) - 1);
cur = old = dir_path;
while (cur != NULL)
{
if ((cur - old) > 1)
{
*cur = '\0';
Sys_Mkdir(path);
Sys_Mkdir(dir_path);
*cur = '/';
}
@ -278,7 +281,7 @@ FS_DPrintf(const char *format, ...)
Com_Printf("%s", msg);
}
char *
const char *
FS_Gamedir(void)
{
return fs_gamedir;
@ -1460,7 +1463,7 @@ FS_LoadPK3(const char *packPath)
/*
* Allows enumerating all of the directories in the search path.
*/
char *
const char *
FS_NextPath(const char *prevPath)
{
char *prev;
@ -2013,7 +2016,7 @@ FS_Dir_f(void)
{
char **dirnames; /* File list. */
char findname[1024]; /* File search path and pattern. */
char *path = NULL; /* Search path. */
const char *path = NULL; /* Search path. */
char *lastsep;
char wildcard[1024] = "*.*"; /* File pattern. */
int i; /* Loop counter. */

View file

@ -743,8 +743,8 @@ void FS_FreeList(char **list, int nfiles);
void FS_InitFilesystem(void);
void FS_ShutdownFilesystem(void);
void FS_BuildGameSpecificSearchPath(const char *dir);
char *FS_Gamedir(void);
char *FS_NextPath(const char *prevpath);
const char *FS_Gamedir(void);
const char *FS_NextPath(const char *prevpath);
int FS_LoadFile(const char *path, void **buffer);
qboolean FS_FileInGamedir(const char *file);
qboolean FS_AddPAKFromGamedir(const char *pak);
@ -757,7 +757,7 @@ char **FS_ListMods(int *nummods);
/* properly handles partial reads */
void FS_FreeFile(void *buffer);
void FS_CreatePath(char *path);
void FS_CreatePath(const char *path);
/* MISC */

View file

@ -403,7 +403,7 @@ qboolean BOT_DMclass_FindEnemy(edict_t *self)
if(bestenemy)
{
// if (AIDevel.debugChased && bot_showcombat->value && bestenemy->ai.is_bot)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: selected %s as enemy.\n",
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected %s as enemy.\n",
// self->ai.pers.netname,
// bestenemy->ai.pers.netname);
@ -587,7 +587,7 @@ void BOT_DMclass_FireWeapon (edict_t *self, usercmd_t *ucmd)
ucmd->buttons = BUTTON_ATTACK;
//if(AIDevel.debugChased && bot_showcombat->integer)
// G_PrintMsg (AIDevel.devguy, PRINT_HIGH, "%s: attacking %s\n",self->bot.pers.netname ,self->enemy->r.client->pers.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: attacking %s\n",self->bot.pers.netname ,self->enemy->r.client->pers.netname);
}

View file

@ -255,7 +255,7 @@ void M_default_FireWeapon (edict_t *self)
}
//if(AIDevel.debugMode && bot_debugmonster->integer)
// G_PrintMsg (NULL, PRINT_HIGH, "monster: attacking\n");
// gi.cprintf(NULL, PRINT_HIGH, "monster: attacking\n");
}

View file

@ -42,7 +42,7 @@ typedef struct
qboolean was_falling;
int last_node;
}player_dropping_nodes_t;
} player_dropping_nodes_t;
player_dropping_nodes_t player;
@ -100,24 +100,25 @@ int AI_AddNode( vec3_t origin, int flagsmask )
// AI_UpdateNodeEdge
// Add/Update node connections (paths)
//==========================================
void AI_UpdateNodeEdge( int from, int to )
void AI_UpdateNodeEdge(int from, int to)
{
int link;
if(from == -1 || to == -1 || from == to)
{
return; // safety
}
if(AI_PlinkExists(from, to))
{
link = AI_PlinkMoveType(from, to);
} else
}
else
{
link = AI_FindLinkType( from, to );
}
Com_Printf("Link: %d -> %d. ", from, to);
Com_Printf("%s\n", AI_LinkString(link) );
Com_Printf("Link: %d -> %d. %s\n", from, to, AI_LinkString(link) );
}
@ -161,7 +162,9 @@ void AI_DropLadderNodes( edict_t *self )
{
VectorCopy( trace.endpos, borigin );
} else { //it wasn't so easy
}
else
{ //it wasn't so easy
trace = gi.trace( borigin, tv(-15,-15,-25), tv(15,15,0), borigin, self, MASK_NODESOLID );
while( AI_IsLadder( borigin, self->client->ps.viewangles, self->mins, self->maxs, self)
@ -506,28 +509,38 @@ void AITools_InitMakenodes( void )
// save nodes and plinks to file.
// Only navigation nodes are saved. Item nodes aren't
//==========================================
qboolean AI_SavePLKFile( char *mapname )
static qboolean
AI_SavePLKFile(const char *mapname)
{
FILE *pOut;
char filename[MAX_OSPATH];
int i;
int version = NAV_FILE_VERSION;
Com_sprintf (filename, sizeof(filename), "%s/%s/%s.%s", AI_MOD_FOLDER, AI_NODES_FOLDER, mapname, NAV_FILE_EXTENSION );
pOut = fopen (filename, "wb");
Com_sprintf(filename, sizeof(filename), "%s/%s/%s.%s",
gi.FS_Gamedir(), AI_NODES_FOLDER, mapname, NAV_FILE_EXTENSION);
gi.FS_CreatePath(filename);
pOut = fopen(filename, "wb");
if (!pOut)
{
Com_Printf("Failed to store: %s\n", filename);
return false;
}
fwrite(&version,sizeof(int),1,pOut);
fwrite(&nav.num_nodes,sizeof(int),1,pOut);
fwrite(&version, sizeof(int), 1, pOut);
fwrite(&nav.num_nodes, sizeof(int), 1, pOut);
// write out nodes
for(i=0; i<nav.num_nodes;i++)
fwrite(&nodes[i],sizeof(nav_node_t),1,pOut);
{
fwrite(&nodes[i], sizeof(nav_node_t), 1, pOut);
}
// write out plinks array
for(i=0; i<nav.num_nodes;i++)
fwrite(&pLinks[i],sizeof(nav_plink_t),1,pOut);
{
fwrite(&pLinks[i], sizeof(nav_plink_t), 1, pOut);
}
fclose(pOut);
@ -550,23 +563,28 @@ void AITools_SaveNodes( void )
int newlinks;
int jumplinks;
if( !nav.num_nodes ) {
if( !nav.num_nodes )
{
Com_Printf("CGame AITools: No nodes to save\n");
return;
}
//find links
newlinks = AI_LinkCloseNodes();
Com_Printf (" : Added %i new links\n", newlinks);
Com_Printf ("Added %i new links\n", newlinks);
//find jump links
jumplinks = AI_LinkCloseNodes_JumpPass(0);
Com_Printf (" : Added %i new jump links\n", jumplinks);
Com_Printf ("Added %i new jump links\n", jumplinks);
if( !AI_SavePLKFile( level.mapname ) )
Com_Printf (" : Failed: Couldn't create the nodes file\n");
if(!AI_SavePLKFile(level.mapname))
{
Com_Printf ("Failed: Couldn't create the nodes file\n");
}
else
Com_Printf (" : Nodes files saved\n");
{
Com_Printf ("Nodes files saved\n");
}
//restart navigation
AITools_EraseNodes();

View file

@ -274,7 +274,7 @@ float AI_ItemWeight(edict_t *self, edict_t *it)
//item didn't have a recognizable item flag
// if (AIDevel.debugMode)
// G_PrintMsg (NULL, PRINT_HIGH, "(AI_ItemWeight) WARNING: Item with unhandled item flag:%s\n", it->classname);
// gi.cprintf(NULL, PRINT_HIGH, "(AI_ItemWeight) WARNING: Item with unhandled item flag:%s\n", it->classname);
return 0;
}

View file

@ -179,7 +179,7 @@ qboolean AI_AddLink( int n1, int n2, int linkType )
//add the link
if (pLinks[n1].numLinks > NODES_MAX_PLINKS)
{
// G_Printf("MaxPlinks Reached! node:%i numPlinks:%i\n", n1, pLinks[n1].numLinks);
// Com_Printf("MaxPlinks Reached! node:%i numPlinks:%i\n", n1, pLinks[n1].numLinks);
return false;
}

View file

@ -175,7 +175,7 @@ qboolean AI_BotRoamForLRGoal(edict_t *self, int current_node)
self->ai.tries = 0; // Reset the count of how many times we tried this goal
// if(AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: selected a bot roam of weight %f at node %d for LR goal.\n",self->ai.pers.netname, nav.broams[best_broam].weight, goal_node);
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a bot roam of weight %f at node %d for LR goal.\n",self->ai.pers.netname, nav.broams[best_broam].weight, goal_node);
AI_SetGoal(self,goal_node);
@ -209,7 +209,7 @@ void AI_PickLongRangeGoal(edict_t *self)
if(current_node == -1) //failed. Go wandering :(
{
// if (AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai.pers.netname, self->ai.nearest_node_tries);
// gi.cprintf(NULL, PRINT_HIGH, "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai.pers.netname, self->ai.nearest_node_tries);
// Com_Printf( "%s: LRGOAL: Closest node not found. Tries:%i\n", self->ai.pers.netname, self->ai.nearest_node_tries);
if( self->ai.state != BOT_STATE_WANDER )
@ -307,7 +307,7 @@ void AI_PickLongRangeGoal(edict_t *self)
self->ai.state = BOT_STATE_WANDER;
self->ai.wander_timeout = level.time + 1.0;
// if(AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: did not find a LR goal, wandering.\n",self->ai.pers.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: did not find a LR goal, wandering.\n",self->ai.pers.netname);
// Com_Printf( "%s: did not find a LR goal, wandering.\n",self->ai.pers.netname);
}
return; // no path?
@ -318,7 +318,7 @@ void AI_PickLongRangeGoal(edict_t *self)
self->ai.tries = 0; // Reset the count of how many times we tried this goal
// if(goal_ent != NULL && AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: selected a %s at node %d for LR goal.\n",self->ai.pers.netname, goal_ent->classname, goal_node);
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a %s at node %d for LR goal.\n",self->ai.pers.netname, goal_ent->classname, goal_node);
// if(goal_ent != NULL )
// Com_Printf( "%s: selected a %s at node %d for LR goal.\n",self->ai.pers.netname, goal_ent->classname, goal_node);
@ -356,7 +356,7 @@ void AI_PickShortRangeGoal(edict_t *self)
if (self->ai.status.playersWeights[target->owner->s.number-1])
{
// if(AIDevel.debugChased && bot_showcombat->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: ROCKET ALERT!\n", self->ai.pers.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: ROCKET ALERT!\n", self->ai.pers.netname);
self->enemy = target->owner; // set who fired the rocket as enemy
return;
@ -387,7 +387,7 @@ void AI_PickShortRangeGoal(edict_t *self)
self->movetarget = best;
self->goalentity = best;
// if(AIDevel.debugChased && bot_showsrgoal->value && (self->goalentity != self->movetarget))
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: selected a %s for SR goal.\n",self->ai.pers.netname, self->movetarget->classname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: selected a %s for SR goal.\n",self->ai.pers.netname, self->movetarget->classname);
}
}

View file

@ -72,7 +72,7 @@ qboolean AI_CanMove(edict_t *self, int direction)
if(tr.fraction == 1.0 || tr.contents & (CONTENTS_LAVA|CONTENTS_SLIME))
{
//if(AIDevel.debugChased) //jal: is too spammy. Temporary disabled
// G_PrintMsg (AIDevel.devguy, PRINT_HIGH, "%s: move blocked\n", self->bot.botStatus.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: move blocked\n", self->bot.botStatus.netname);
return false;
}
@ -363,7 +363,7 @@ qboolean AI_MoveToGoalEntity(edict_t *self, usercmd_t *ucmd)
VectorSubtract (self->movetarget->s.origin, self->s.origin, self->ai.move_vector);
AI_ChangeAngle(self);
// if(AIDevel.debugChased && bot_showcombat->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: Oh crap a rocket!\n",self->ai.pers.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: Oh crap a rocket!\n",self->ai.pers.netname);
// strafe left/right
if(rand()%1 && AI_CanMove(self, BOT_MOVE_LEFT))

View file

@ -144,7 +144,7 @@ void AI_SetGoal(edict_t *self, int goal_node)
//-------------------------
// if(AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai.pers.netname, node);
// gi.cprintf(NULL, PRINT_HIGH, "%s: GOAL: new START NODE selected %d\n", self->ai.pers.netname, node);
self->ai.next_node = self->ai.current_node; // make sure we get to the nearest node first
self->ai.node_timeout = 0;
@ -202,7 +202,7 @@ qboolean AI_FollowPath( edict_t *self )
if( self->ai.next_node == self->ai.goal_node )
{
// if(AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: GOAL REACHED!\n", self->ai.pers.netname);
// gi.cprintf(NULL, PRINT_HIGH, "%s: GOAL REACHED!\n", self->ai.pers.netname);
//if botroam, setup a timeout for it
if( nodes[self->ai.goal_node].flags & NODEFLAGS_BOTROAM )
@ -213,7 +213,7 @@ qboolean AI_FollowPath( edict_t *self )
continue;
// if(AIDevel.debugChased && bot_showlrgoal->value)
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: BotRoam Time Out set up for node %i\n", self->ai.pers.netname, nav.broams[i].node);
// gi.cprintf(NULL, PRINT_HIGH, "%s: BotRoam Time Out set up for node %i\n", self->ai.pers.netname, nav.broams[i].node);
self->ai.status.broam_timeouts[i] = level.time + 15.0;
break;
}
@ -228,7 +228,7 @@ qboolean AI_FollowPath( edict_t *self )
self->ai.next_node = self->ai.path->nodes[self->ai.path_position++];
// if(AIDevel.debugChased && bot_showpath->value > 1 )
// G_PrintMsg (AIDevel.chaseguy, PRINT_HIGH, "%s: CurrentNode(%i):%s NextNode(%i):%s\n", self->ai.pers.netname, self->ai.current_node, nodeTypeNames[nodes[self->ai.current_node].type], self->ai.next_node, nodeTypeNames[nodes[self->ai.next_node].type]);
// gi.cprintf(NULL, PRINT_HIGH, "%s: CurrentNode(%i):%s NextNode(%i):%s\n", self->ai.pers.netname, self->ai.current_node, nodeTypeNames[nodes[self->ai.current_node].type], self->ai.next_node, nodeTypeNames[nodes[self->ai.next_node].type]);
}
}

View file

@ -193,7 +193,7 @@ qboolean AI_PredictJumpadDestity( edict_t *ent, vec3_t out )
// trap_Trace ( &trace, target_origin, tv(-15, -15, -8), tv(15, 15, 8), floor_target_origin, NULL, MASK_NODESOLID);
trace = gi.trace( target_origin, tv(-15, -15, -8), tv(15, 15, 8), floor_target_origin, NULL, MASK_NODESOLID);
if ((trace.fraction == 1.0 && trace.startsolid) || (trace.allsolid && trace.startsolid)){
// G_Printf("JUMPAD LAND: ERROR: trace was in solid.\n"); //started inside solid (target should never be inside solid, this is a mapper error)
// Com_Printf("JUMPAD LAND: ERROR: trace was in solid.\n"); //started inside solid (target should never be inside solid, this is a mapper error)
return false;
} else if ( trace.fraction == 1.0 ) {
@ -645,7 +645,8 @@ qboolean AI_LoadPLKFile( char *mapname )
char filename[MAX_OSPATH];
int version;
Com_sprintf (filename, sizeof(filename), "%s/%s/%s.%s", AI_MOD_FOLDER, AI_NODES_FOLDER, mapname, NAV_FILE_EXTENSION);
Com_sprintf (filename, sizeof(filename), "%s/%s/%s.%s",
gi.FS_Gamedir(), AI_NODES_FOLDER, mapname, NAV_FILE_EXTENSION);
pIn = fopen( filename, "rb" );
if( pIn == NULL )
@ -904,12 +905,14 @@ void AI_InitNavigationData(void)
//Load nodes from file
nav.loaded = AI_LoadPLKFile( level.mapname );
if( !nav.loaded ) {
Com_Printf( "AI: FAILED to load nodes file.\n");
Com_Printf("AI: FAILED to load nodes file.\n");
return;
}
for( linkscount = 0, i = 0; i< nav.num_nodes; i++ )
{
linkscount += pLinks[i].numLinks;
}
servernodesstart = nav.num_nodes;
@ -918,12 +921,12 @@ void AI_InitNavigationData(void)
newlinks = AI_LinkServerNodes( servernodesstart );
newjumplinks = AI_LinkCloseNodes_JumpPass( servernodesstart );
Com_Printf("-------------------------------------\n" );
Com_Printf(" : AI: Nodes Initialized.\n" );
Com_Printf(" : loaded nodes:%i.\n", servernodesstart );
Com_Printf(" : added nodes:%i.\n", nav.num_nodes - servernodesstart );
Com_Printf(" : total nodes:%i.\n", nav.num_nodes );
Com_Printf(" : loaded links:%i.\n", linkscount );
Com_Printf(" : added links:%i.\n", newlinks );
Com_Printf(" : added jump links:%i.\n", newjumplinks );
Com_Printf("-------------------------------------\n");
Com_Printf("AI: Nodes Initialized.\n");
Com_Printf("Loaded nodes: %i.\n", servernodesstart);
Com_Printf("Added nodes: %i.\n", nav.num_nodes - servernodesstart);
Com_Printf("Total nodes: %i.\n", nav.num_nodes);
Com_Printf("Loaded links: %i.\n", linkscount);
Com_Printf("Added links: %i.\n", newlinks);
Com_Printf("Added jump links: %i.\n", newjumplinks);
}

View file

@ -40,7 +40,6 @@
#define NODES_MAX_PLINKS 16
#define NAV_FILE_VERSION 11
#define NAV_FILE_EXTENSION "nav"
#define AI_MOD_FOLDER "jabot"
#define AI_NODES_FOLDER "navigation"
#define MASK_NODESOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW)

View file

@ -39,23 +39,23 @@ void AIDebug_ToogleBotDebug(void)
{
/* if (AIDevel.debugMode || !sv_cheats->integer )
{
// G_Printf ("BOT: Debug Mode Off\n");
// Com_Printf("BOT: Debug Mode Off\n");
AIDevel.debugMode = false;
return;
}
//Activate debug mode
G_Printf ("\n======================================\n");
G_Printf ("--==[ D E B U G ]==--\n");
G_Printf ("======================================\n");
G_Printf ("'addnode [nodetype]' -- Add [specified] node to players current location\n");
G_Printf ("'movenode [node] [x y z]' -- Move [node] to [x y z] coordinates\n");
G_Printf ("'findnode' -- Finds closest node\n");
G_Printf ("'removelink [node1 node2]' -- Removes link between two nodes\n");
G_Printf ("'addlink [node1 node2]' -- Adds a link between two nodes\n");
G_Printf ("======================================\n\n");
Com_Printf("\n======================================\n");
Com_Printf("--==[ D E B U G ]==--\n");
Com_Printf("======================================\n");
Com_Printf("'addnode [nodetype]' -- Add [specified] node to players current location\n");
Com_Printf("'movenode [node] [x y z]' -- Move [node] to [x y z] coordinates\n");
Com_Printf("'findnode' -- Finds closest node\n");
Com_Printf("'removelink [node1 node2]' -- Removes link between two nodes\n");
Com_Printf("'addlink [node1 node2]' -- Adds a link between two nodes\n");
Com_Printf("======================================\n\n");
G_Printf ("BOT: Debug Mode On\n");
Com_Printf("BOT: Debug Mode On\n");
AIDevel.debugMode = true;
*/

View file

@ -62,7 +62,17 @@ static int goalNode;
static int currentNode;
int ValidLinksMask;
#define DEFAULT_MOVETYPES_MASK (LINK_MOVE|LINK_STAIRS|LINK_FALL|LINK_WATER|LINK_WATERJUMP|LINK_JUMPPAD|LINK_PLATFORM|LINK_TELEPORT);
#define DEFAULT_MOVETYPES_MASK ( \
LINK_MOVE | \
LINK_STAIRS | \
LINK_FALL | \
LINK_WATER | \
LINK_WATERJUMP | \
LINK_JUMPPAD | \
LINK_PLATFORM | \
LINK_TELEPORT);
//==========================================
//
//
@ -149,13 +159,17 @@ static int Astar_HDist_ManhatanGuess( int node )
//teleporters are exceptional
if( nodes[node].flags & NODEFLAGS_TELEPORTER_IN )
{
node++; //it's tele out is stored in the next node in the array
}
for (i=0 ; i<3 ; i++)
{
DistVec[i] = nodes[goalNode].origin[i] - nodes[node].origin[i];
if( DistVec[i] < 0.0f )
{
DistVec[i] = -DistVec[i]; //use only positive values. We don't care about direction.
}
}
HDist = (int)(DistVec[0] + DistVec[1] + DistVec[2]);
@ -164,7 +178,8 @@ static int Astar_HDist_ManhatanGuess( int node )
static void AStar_PutInClosed( int node )
{
if( !astarnodes[node].list ) {
if( !astarnodes[node].list )
{
alist[alist_numNodes] = node;
alist_numNodes++;
}
@ -182,17 +197,23 @@ static void AStar_PutAdjacentsInOpen(int node)
//ignore invalid links
if( !(ValidLinksMask & pLinks[node].moveType[i]) )
{
continue;
}
addnode = pLinks[node].nodes[i];
//ignore self
if( addnode == node )
{
continue;
}
//ignore if it's already in closed list
if( AStar_nodeIsInClosed( addnode ) )
{
continue;
}
//if it's already inside open list
if( AStar_nodeIsInOpen( addnode ) )
@ -202,7 +223,7 @@ static void AStar_PutAdjacentsInOpen(int node)
plinkDist = AStar_PLinkDistance( node, addnode );
if( plinkDist == -1)
{
//printf("WARNING: AStar_PutAdjacentsInOpen - Couldn't find distance between nodes\n");
Com_Printf("WARNING: AStar_PutAdjacentsInOpen - Couldn't find distance between nodes\n");
}
//compare G distances and choose best parent
else if( astarnodes[addnode].G > (astarnodes[node].G + plinkDist) )
@ -211,7 +232,9 @@ static void AStar_PutAdjacentsInOpen(int node)
astarnodes[addnode].G = astarnodes[node].G + plinkDist;
}
} else { //just put it in
}
else
{ //just put it in
int plinkDist;
@ -220,14 +243,16 @@ static void AStar_PutAdjacentsInOpen(int node)
{
plinkDist = AStar_PLinkDistance( addnode, node );
if( plinkDist == -1)
{
plinkDist = 999;//jalFIXME
}
//ERROR
//printf("WARNING: AStar_PutAdjacentsInOpen - Couldn't find distance between nodes\n");
Com_Printf("WARNING: AStar_PutAdjacentsInOpen - Couldn't find distance between nodes\n");
}
//put in global list
if( !astarnodes[addnode].list ) {
if( !astarnodes[addnode].list )
{
alist[alist_numNodes] = addnode;
alist_numNodes++;
}
@ -251,14 +276,18 @@ static int AStar_FindInOpen_BestF ( void )
int node = alist[i];
if( astarnodes[node].list != OPENLIST )
{
continue;
}
if ( bestF == -1 || bestF > (astarnodes[node].G + astarnodes[node].H) ) {
if ( bestF == -1 || bestF > (astarnodes[node].G + astarnodes[node].H) )
{
bestF = astarnodes[node].G + astarnodes[node].H;
best = node;
}
}
//printf("BEST:%i\n", best);
Com_Printf("BEST:%i\n", best);
return best;
}
@ -301,7 +330,9 @@ int AStar_ResolvePath ( int n1, int n2, int movetypes )
{
ValidLinksMask = movetypes;
if ( !ValidLinksMask )
{
ValidLinksMask = DEFAULT_MOVETYPES_MASK;
}
AStar_InitLists();
@ -312,12 +343,14 @@ int AStar_ResolvePath ( int n1, int n2, int movetypes )
while ( !AStar_nodeIsInOpen(goalNode) )
{
if( !AStar_FillLists() )
{
return 0; //failed
}
}
AStar_ListsToPath();
//printf("RESULT:\n Origin:%i\n Goal:%i\n numNodes:%i\n FirstInPath:%i\n LastInPath:%i\n", originNode, goalNode, Apath_numNodes, Apath[0], Apath[Apath_numNodes-1]);
Com_Printf("RESULT:\n Origin:%i\n Goal:%i\n numNodes:%i\n FirstInPath:%i\n LastInPath:%i\n", originNode, goalNode, Apath_numNodes, Apath[0], Apath[Apath_numNodes-1]);
return 1;
}
@ -327,14 +360,17 @@ int AStar_GetPath( int origin, int goal, int movetypes, struct astarpath_s *path
int i;
if( !AStar_ResolvePath ( origin, goal, movetypes ) )
{
return 0;
}
path->numNodes = Apath_numNodes;
path->originNode = origin;
path->goalNode = goal;
for(i=0; i<path->numNodes; i++)
{
path->nodes[i] = Apath[i];
}
return 1;
}

View file

@ -27,19 +27,6 @@
//ACE
//==========================================
// BOT_Commands
// Special command processor
//==========================================
qboolean BOT_Commands(edict_t *ent)
{
return false;
}
//==========================================
// BOT_ServerCommand
// Special server command processor
@ -59,10 +46,6 @@ qboolean BOT_ServerCommand (void)
else // name, skin
BOT_SpawnBot ( NULL, gi.argv(2), gi.argv(3), NULL );
}
// removebot
else if( !Q_stricmp (cmd, "removebot") )
BOT_RemoveBot(gi.argv(2));
else if( !Q_stricmp (cmd, "editnodes") )
AITools_InitEditnodes();
@ -84,94 +67,6 @@ qboolean BOT_ServerCommand (void)
return true;
}
//==========================================
// AI_BotObituary
// Bots can't use stock obituaries cause server doesn't print from them
//==========================================
void AI_BotObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
{
/* int mod;
char message[64];
char message2[64];
qboolean ff;
if (coop->value && attacker->client)
meansOfDeath |= MOD_FRIENDLY_FIRE;
if ( deathmatch->value || coop->value )
{
ff = meansOfDeath & MOD_FRIENDLY_FIRE;
mod = meansOfDeath & ~MOD_FRIENDLY_FIRE;
GS_Obituary ( self, G_PlayerGender ( self ), attacker, mod, message, message2 );
// duplicate message at server console for logging
if ( attacker && attacker->client )
{
if ( attacker != self )
{ // regular death message
if ( deathmatch->value ) {
if( ff )
attacker->client->resp.score--;
else
attacker->client->resp.score++;
}
self->enemy = attacker;
if( dedicated->value )
G_Printf ( "%s %s %s%s\n", self->client->pers.netname, message, attacker->client->pers.netname, message2 );
else
{ //bot
G_PrintMsg (NULL, PRINT_HIGH, "%s%s %s %s%s\n",
self->client->pers.netname,
S_COLOR_WHITE,
message,
attacker->client->pers.netname,
message2);
}
} else { // suicide
if( deathmatch->value )
self->client->resp.score--;
self->enemy = NULL;
if( dedicated->value )
G_Printf ( "%s %s\n", self->client->pers.netname, message );
else
{ //bot
G_PrintMsg (NULL, PRINT_HIGH, "%s%s %s\n",
self->client->pers.netname,
S_COLOR_WHITE,
message );
}
}
} else { // wrong place, suicide, etc.
if( deathmatch->value )
self->client->resp.score--;
self->enemy = NULL;
if( dedicated->value )
G_Printf( "%s %s\n", self->client->pers.netname, message );
else
{ //bot
G_PrintMsg (NULL, PRINT_HIGH, "%s%s %s\n",
self->client->pers.netname,
S_COLOR_WHITE,
message );
}
}
}
*/
}
///////////////////////////////////////////////////////////////////////
// These routines are bot safe print routines, all id code needs to be
// changed to these so the bots do not blow up on messages sent to them.
@ -185,34 +80,6 @@ void AI_BotObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// Debug print, could add a "logging" feature to print to a file
///////////////////////////////////////////////////////////////////////
void debug_printf(char *fmt, ...)
{
int i;
char bigbuffer[0x10000];
va_list argptr;
edict_t *cl_ent;
va_start (argptr,fmt);
vsprintf (bigbuffer,fmt,argptr);
va_end (argptr);
if (dedicated->value)
gi.cprintf(NULL, PRINT_MEDIUM, bigbuffer);
for (i=0 ; i<maxclients->value ; i++)
{
cl_ent = g_edicts + 1 + i;
if (!cl_ent->inuse || cl_ent->ai.is_bot)
continue;
gi.cprintf(cl_ent, PRINT_MEDIUM, bigbuffer);
}
}
///////////////////////////////////////////////////////////////////////
// botsafe cprintf
///////////////////////////////////////////////////////////////////////

View file

@ -114,16 +114,6 @@ cvar_t *bot_showsrgoal;
cvar_t *bot_showlrgoal;
cvar_t *bot_debugmonster;
/*
void ClientThink (edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect (edict_t *ent, char *userinfo);
void ClientUserinfoChanged (edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent);
void ClientBegin (edict_t *ent);
void ClientCommand (edict_t *ent);
void RunEntity (edict_t *ent);
void InitGame(void);
*/
static void G_RunFrame(void);
/* =================================================================== */

View file

@ -353,6 +353,12 @@ ServerCommand(void)
{
SVCmd_WriteIP_f();
}
/* JABot[start] */
else if(Q_stricmp(cmd, "removebot") == 0)
{
BOT_RemoveBot(gi.argv(2));
}
/* [end] */
else
{
gi.cprintf(NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);

View file

@ -1,5 +1,7 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2001 Steve Yeager
* Copyright (C) 2001-2004 Pat AfterMoon
* Copyright (c) ZeniMax Media Inc.
*
* This program is free software; you can redistribute it and/or modify
@ -98,7 +100,6 @@ typedef struct
// bot_cmds.c
qboolean BOT_Commands(edict_t *ent);
qboolean BOT_ServerCommand(void);
// ai_main.c
@ -114,9 +115,6 @@ void BOT_SpawnBot(char *team, char *name, char *skin, char *userinfo);
void BOT_RemoveBot(char *name);
void BOT_Respawn(edict_t *self);
//bot_misc.c
void AI_BotObituary(edict_t *self, edict_t *inflictor, edict_t *attacker);
// ai_tools.c
void AIDebug_ToogleBotDebug(void);
@ -124,7 +122,6 @@ void AITools_Frame(void);
void AITools_DropNodes(edict_t *ent);
// safe **cough** prints
void debug_printf(char *fmt, ...);
void safe_cprintf(edict_t *ent, int printlevel, char *fmt, ...);
void safe_centerprintf(edict_t *ent, char *fmt, ...);
void safe_bprintf(int printlevel, char *fmt, ...);

View file

@ -210,8 +210,10 @@ typedef struct
or a discrete file from anywhere in the quake search path
a -1 return means the file does not exist
NULL can be passed for buf to just determine existance */
int (*FS_LoadFile) (const char *name, void **buf);
void (*FS_FreeFile) (void *buf);
int (*FS_LoadFile)(const char *name, void **buf);
void (*FS_FreeFile)(void *buf);
const char * (*FS_Gamedir)(void);
void (*FS_CreatePath)(const char *path);
const char * (*get_configstring)(int num);
} game_import_t;

View file

@ -474,6 +474,8 @@ SV_InitGameProgs(void)
/* Extension to classic Quake2 API */
import.FS_LoadFile = FS_LoadFile;
import.FS_FreeFile = FS_FreeFile;
import.FS_Gamedir = FS_Gamedir;
import.FS_CreatePath = FS_CreatePath;
ge = (game_export_t *)Sys_GetGameAPI(&import);