Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/botlib/aas/aas_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ typedef struct aas_node_s
int children[2]; /* <0 means leaf/area, 0 means solid */
} aas_node_t;

typedef struct aas_campspot_s
{
vec3_t origin;
struct aas_campspot_s *next;
} aas_campspot_t;

/*
* Travel type definitions reconstructed from the Quake III / Gladiator
* binaries. The values mirror the original enum encoded in the reachability
Expand Down Expand Up @@ -227,6 +233,9 @@ typedef struct aas_world_s
int maxEntities;
aas_entity_t *entities; /* base pointer from data_100669a0 */

int numCampSpots;
aas_campspot_t *campSpots;

size_t areaEntityListCount; /* number of heads in areaEntityLists */
aas_link_t **areaEntityLists; /* entities linked per area */

Expand Down
121 changes: 121 additions & 0 deletions src/botlib/aas/aas_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ static size_t AAS_AreaBitWordCount(void);
static void AAS_ClampMinsMaxs(vec3_t mins, vec3_t maxs);
static void AAS_ClearWorld(void);
static void AAS_ParseEntityLump(const char *data, size_t length);
static qboolean AAS_ParseVectorValue(const char *value, vec3_t outValue);
static void AAS_RegisterCampSpot(const aas_parsed_entity_t *entity);

/*
* Global AAS world state. The original DLL zeroed the data_100667e0 block
Expand Down Expand Up @@ -105,6 +107,8 @@ typedef struct aas_parsed_entity_s
qboolean hasClassname;
char model[64];
qboolean hasModel;
vec3_t origin;
qboolean hasOrigin;
float lip;
qboolean hasLip;
float height;
Expand Down Expand Up @@ -193,6 +197,61 @@ static qboolean AAS_ParseIntValue(const char *value, int *outValue)
return qtrue;
}

/*
=============
AAS_ParseVectorValue

Parses a whitespace-delimited vec3 from the entity lump.
=============
*/
static qboolean AAS_ParseVectorValue(const char *value, vec3_t outValue)
{
if (value == NULL || outValue == NULL)
{
return qfalse;
}

const char *cursor = value;
float parsed[3] = {0.0f, 0.0f, 0.0f};

for (int axis = 0; axis < 3; ++axis)
{
while (*cursor != '\0' && isspace((unsigned char)*cursor))
{
++cursor;
}

if (*cursor == '\0')
{
return qfalse;
}

errno = 0;
char *endPtr = NULL;
float val = strtof(cursor, &endPtr);
if (endPtr == cursor || errno == ERANGE)
{
return qfalse;
}

parsed[axis] = val;
cursor = endPtr;
}

while (*cursor != '\0' && isspace((unsigned char)*cursor))
{
++cursor;
}

if (*cursor != '\0')
{
return qfalse;
}

VectorSet(outValue, parsed[0], parsed[1], parsed[2]);
return qtrue;
}

static void AAS_CopyStringField(char *destination,
size_t destinationSize,
const char *source,
Expand Down Expand Up @@ -473,6 +532,21 @@ static void AAS_ParseEntityKeyValue(aas_parsed_entity_t *entity, const char *key
AAS_CopyStringField(entity->model, sizeof(entity->model), value, key);
entity->hasModel = qtrue;
}
else if (strcmp(key, "origin") == 0)
{
vec3_t parsed;
if (AAS_ParseVectorValue(value, parsed))
{
VectorCopy(parsed, entity->origin);
entity->hasOrigin = qtrue;
}
else
{
BotLib_Print(PRT_WARNING,
"AAS_ParseEntityLump: failed to parse origin value '%s'\n",
value);
}
}
else if (strcmp(key, "lip") == 0)
{
float parsed = 0.0f;
Expand Down Expand Up @@ -609,6 +683,39 @@ static void AAS_RegisterMoverEntity(const aas_parsed_entity_t *entity)
}
}

/*
=============
AAS_RegisterCampSpot

Stores info_camp origins parsed from the BSP entity lump.
=============
*/
static void AAS_RegisterCampSpot(const aas_parsed_entity_t *entity)
{
if (entity == NULL || !entity->hasClassname || !entity->hasOrigin)
{
return;
}

if (strcmp(entity->classname, "info_camp") != 0)
{
return;
}

aas_campspot_t *spot = (aas_campspot_t *)calloc(1, sizeof(*spot));
if (spot == NULL)
{
BotLib_Print(PRT_WARNING,
"AAS_ParseEntityLump: out of memory registering camp spot\n");
return;
}

VectorCopy(entity->origin, spot->origin);
spot->next = aasworld.campSpots;
aasworld.campSpots = spot;
aasworld.numCampSpots++;
}

static void AAS_ParseEntityLump(const char *data, size_t length)
{
if (data == NULL || length == 0U)
Expand Down Expand Up @@ -718,6 +825,7 @@ static void AAS_ParseEntityLump(const char *data, size_t length)
if (!malformed)
{
AAS_RegisterMoverEntity(&entity);
AAS_RegisterCampSpot(&entity);
}
}
}
Expand Down Expand Up @@ -1097,6 +1205,19 @@ static void AAS_ClearWorld(void)
AAS_FreeAllRoutingCaches();
AAS_ClearReachabilityData();

if (aasworld.campSpots != NULL)
{
aas_campspot_t *spot = aasworld.campSpots;
while (spot != NULL)
{
aas_campspot_t *next = spot->next;
free(spot);
spot = next;
}
aasworld.campSpots = NULL;
aasworld.numCampSpots = 0;
}

if (aasworld.entities != NULL)
{
for (int i = 0; i < aasworld.maxEntities; ++i)
Expand Down
42 changes: 42 additions & 0 deletions src/botlib/ai_goal/bot_goal.c
Original file line number Diff line number Diff line change
Expand Up @@ -1022,6 +1022,48 @@ int BotTouchingGoal(const vec3_t origin, const bot_goal_t *goal)
return 1;
}

/*
=============
BotGetNextCampSpotGoal

Iterates the map camp spots and returns the next goal entry.
=============
*/
int BotGetNextCampSpotGoal(int num, bot_goal_t *goal)
{
if (goal == NULL)
{
return 0;
}

if (num < 0)
{
num = 0;
}

int index = num;
const aas_campspot_t *spot = aasworld.campSpots;
while (spot != NULL)
{
if (--index < 0)
{
vec3_t mins = {-8.0f, -8.0f, -8.0f};
vec3_t maxs = {8.0f, 8.0f, 8.0f};

goal->areanum = BotGoal_PointAreaNum(spot->origin);
VectorCopy(spot->origin, goal->origin);
goal->entitynum = 0;
VectorCopy(mins, goal->mins);
VectorCopy(maxs, goal->maxs);
return num + 1;
}

spot = spot->next;
}

return 0;
}

void BotGoalName(int number, char *name, int size)
{
if (name == NULL || size <= 0)
Expand Down
2 changes: 1 addition & 1 deletion src/botlib/ai_goal/bot_goal.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ float BotGoal_EvaluateStackGoal(int handle,
int *travel_time);

int BotTouchingGoal(const vec3_t origin, const bot_goal_t *goal);
int BotGetNextCampSpotGoal(int num, bot_goal_t *goal);
void BotGoalName(int number, char *name, int size);
void BotDumpAvoidGoals(int handle);
void BotDumpGoalStack(int handle);
Expand All @@ -128,4 +129,3 @@ const bot_goalstate_t *BotGoalStatePeek(int handle);
#ifdef __cplusplus
}
#endif

Loading